From: amacleod Date: Tue, 5 Nov 2013 19:26:07 +0000 (+0000) Subject: * gimple.h: Move some prototypes to gimple-expr.h and add to include X-Git-Tag: upstream/4.9.2~3203 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=46a19abf72e20d1334b54a936eab013be3be3a15;p=platform%2Fupstream%2Flinaro-gcc.git * gimple.h: Move some prototypes to gimple-expr.h and add to include list. (extract_ops_from_tree, gimple_call_addr_fndecl, is_gimple_reg_type): Move to gimple-expr.h. * gimple-expr.h: New file. Relocate some prototypes from gimple.h. (types_compatible_p, is_gimple_reg_type, is_gimple_variable, is_gimple_id, virtual_operand_p, is_gimple_addressable, is_gimple_constant, extract_ops_from_tree, gimple_call_addr_fndecl): Relocate here. * gimple.c (extract_ops_from_tree_1, gimple_cond_get_ops_from_tree, gimple_set_body, gimple_body, gimple_has_body_p, is_gimple_lvalue, is_gimple_condexpr, is_gimple_addressable, is_gimple_constant, is_gimple_address, is_gimple_invariant_address, is_gimple_ip_invariant_address, is_gimple_min_invariant, is_gimple_ip_invariant, is_gimple_variable, is_gimple_id, virtual_operand_p, is_gimple_reg, is_gimple_val, is_gimple_asm_val, is_gimple_min_lval, is_gimple_call_addr, is_gimple_mem_ref_addr, gimple_decl_printable_name, useless_type_conversion_p, types_compatible_p, gimple_can_coalesce_p, copy_var_decl): Move to gimple-expr.[ch]. * gimple-expr.c: New File. (useless_type_conversion_p, gimple_set_body, gimple_body, gimple_has_body_p, gimple_decl_printable_name, copy_var_decl, gimple_can_coalesce_p, extract_ops_from_tree_1, gimple_cond_get_ops_from_tree, is_gimple_lvalue, is_gimple_condexpr, is_gimple_address, is_gimple_invariant_address, is_gimple_ip_invariant_address, is_gimple_min_invariant, is_gimple_ip_invariant, is_gimple_reg, is_gimple_val, is_gimple_asm_val, is_gimple_min_lval, is_gimple_call_addr, is_gimple_mem_ref_addr): Relocate here. * Makefile.in (OBJS): Add gimple-expr.o. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@204412 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4ff3f05..468b185 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,37 @@ +2013-11-05 Andrew MacLeod + + * gimple.h: Move some prototypes to gimple-expr.h and add to include + list. + (extract_ops_from_tree, gimple_call_addr_fndecl, is_gimple_reg_type): + Move to gimple-expr.h. + * gimple-expr.h: New file. Relocate some prototypes from gimple.h. + (types_compatible_p, is_gimple_reg_type, is_gimple_variable, + is_gimple_id, virtual_operand_p, is_gimple_addressable, + is_gimple_constant, extract_ops_from_tree, gimple_call_addr_fndecl): + Relocate here. + * gimple.c (extract_ops_from_tree_1, gimple_cond_get_ops_from_tree, + gimple_set_body, gimple_body, gimple_has_body_p, is_gimple_lvalue, + is_gimple_condexpr, is_gimple_addressable, is_gimple_constant, + is_gimple_address, is_gimple_invariant_address, + is_gimple_ip_invariant_address, is_gimple_min_invariant, + is_gimple_ip_invariant, is_gimple_variable, is_gimple_id, + virtual_operand_p, is_gimple_reg, is_gimple_val, is_gimple_asm_val, + is_gimple_min_lval, is_gimple_call_addr, is_gimple_mem_ref_addr, + gimple_decl_printable_name, useless_type_conversion_p, + types_compatible_p, gimple_can_coalesce_p, copy_var_decl): Move to + gimple-expr.[ch]. + * gimple-expr.c: New File. + (useless_type_conversion_p, gimple_set_body, gimple_body, + gimple_has_body_p, gimple_decl_printable_name, copy_var_decl, + gimple_can_coalesce_p, extract_ops_from_tree_1, + gimple_cond_get_ops_from_tree, is_gimple_lvalue, is_gimple_condexpr, + is_gimple_address, is_gimple_invariant_address, + is_gimple_ip_invariant_address, is_gimple_min_invariant, + is_gimple_ip_invariant, is_gimple_reg, is_gimple_val, + is_gimple_asm_val, is_gimple_min_lval, is_gimple_call_addr, + is_gimple_mem_ref_addr): Relocate here. + * Makefile.in (OBJS): Add gimple-expr.o. + 2013-11-05 David Malcolm * gengtype-parse.c (struct_field_seq): Support empty structs. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index cc88fb8..be8aaff 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1230,6 +1230,7 @@ OBJS = \ ggc-common.o \ gimple.o \ gimple-builder.o \ + gimple-expr.o \ gimple-iterator.o \ gimple-fold.o \ gimple-low.o \ diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c new file mode 100644 index 0000000..c74d929 --- /dev/null +++ b/gcc/gimple-expr.c @@ -0,0 +1,721 @@ +/* Gimple decl, type, and expression support functions. + + Copyright (C) 2007-2013 Free Software Foundation, Inc. + Contributed by Aldy Hernandez + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "gimple.h" +#include "demangle.h" + +/* ----- Type related ----- */ + +/* Return true if the conversion from INNER_TYPE to OUTER_TYPE is a + useless type conversion, otherwise return false. + + This function implicitly defines the middle-end type system. With + the notion of 'a < b' meaning that useless_type_conversion_p (a, b) + holds and 'a > b' meaning that useless_type_conversion_p (b, a) holds, + the following invariants shall be fulfilled: + + 1) useless_type_conversion_p is transitive. + If a < b and b < c then a < c. + + 2) useless_type_conversion_p is not symmetric. + From a < b does not follow a > b. + + 3) Types define the available set of operations applicable to values. + A type conversion is useless if the operations for the target type + is a subset of the operations for the source type. For example + casts to void* are useless, casts from void* are not (void* can't + be dereferenced or offsetted, but copied, hence its set of operations + is a strict subset of that of all other data pointer types). Casts + to const T* are useless (can't be written to), casts from const T* + to T* are not. */ + +bool +useless_type_conversion_p (tree outer_type, tree inner_type) +{ + /* Do the following before stripping toplevel qualifiers. */ + if (POINTER_TYPE_P (inner_type) + && POINTER_TYPE_P (outer_type)) + { + /* Do not lose casts between pointers to different address spaces. */ + if (TYPE_ADDR_SPACE (TREE_TYPE (outer_type)) + != TYPE_ADDR_SPACE (TREE_TYPE (inner_type))) + return false; + } + + /* From now on qualifiers on value types do not matter. */ + inner_type = TYPE_MAIN_VARIANT (inner_type); + outer_type = TYPE_MAIN_VARIANT (outer_type); + + if (inner_type == outer_type) + return true; + + /* If we know the canonical types, compare them. */ + if (TYPE_CANONICAL (inner_type) + && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type)) + return true; + + /* Changes in machine mode are never useless conversions unless we + deal with aggregate types in which case we defer to later checks. */ + if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type) + && !AGGREGATE_TYPE_P (inner_type)) + return false; + + /* If both the inner and outer types are integral types, then the + conversion is not necessary if they have the same mode and + signedness and precision, and both or neither are boolean. */ + if (INTEGRAL_TYPE_P (inner_type) + && INTEGRAL_TYPE_P (outer_type)) + { + /* Preserve changes in signedness or precision. */ + if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type) + || TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type)) + return false; + + /* Preserve conversions to/from BOOLEAN_TYPE if types are not + of precision one. */ + if (((TREE_CODE (inner_type) == BOOLEAN_TYPE) + != (TREE_CODE (outer_type) == BOOLEAN_TYPE)) + && TYPE_PRECISION (outer_type) != 1) + return false; + + /* We don't need to preserve changes in the types minimum or + maximum value in general as these do not generate code + unless the types precisions are different. */ + return true; + } + + /* Scalar floating point types with the same mode are compatible. */ + else if (SCALAR_FLOAT_TYPE_P (inner_type) + && SCALAR_FLOAT_TYPE_P (outer_type)) + return true; + + /* Fixed point types with the same mode are compatible. */ + else if (FIXED_POINT_TYPE_P (inner_type) + && FIXED_POINT_TYPE_P (outer_type)) + return true; + + /* We need to take special care recursing to pointed-to types. */ + else if (POINTER_TYPE_P (inner_type) + && POINTER_TYPE_P (outer_type)) + { + /* Do not lose casts to function pointer types. */ + if ((TREE_CODE (TREE_TYPE (outer_type)) == FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (outer_type)) == METHOD_TYPE) + && !(TREE_CODE (TREE_TYPE (inner_type)) == FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (inner_type)) == METHOD_TYPE)) + return false; + + /* We do not care for const qualification of the pointed-to types + as const qualification has no semantic value to the middle-end. */ + + /* Otherwise pointers/references are equivalent. */ + return true; + } + + /* Recurse for complex types. */ + else if (TREE_CODE (inner_type) == COMPLEX_TYPE + && TREE_CODE (outer_type) == COMPLEX_TYPE) + return useless_type_conversion_p (TREE_TYPE (outer_type), + TREE_TYPE (inner_type)); + + /* Recurse for vector types with the same number of subparts. */ + else if (TREE_CODE (inner_type) == VECTOR_TYPE + && TREE_CODE (outer_type) == VECTOR_TYPE + && TYPE_PRECISION (inner_type) == TYPE_PRECISION (outer_type)) + return useless_type_conversion_p (TREE_TYPE (outer_type), + TREE_TYPE (inner_type)); + + else if (TREE_CODE (inner_type) == ARRAY_TYPE + && TREE_CODE (outer_type) == ARRAY_TYPE) + { + /* Preserve string attributes. */ + if (TYPE_STRING_FLAG (inner_type) != TYPE_STRING_FLAG (outer_type)) + return false; + + /* Conversions from array types with unknown extent to + array types with known extent are not useless. */ + if (!TYPE_DOMAIN (inner_type) + && TYPE_DOMAIN (outer_type)) + return false; + + /* Nor are conversions from array types with non-constant size to + array types with constant size or to different size. */ + if (TYPE_SIZE (outer_type) + && TREE_CODE (TYPE_SIZE (outer_type)) == INTEGER_CST + && (!TYPE_SIZE (inner_type) + || TREE_CODE (TYPE_SIZE (inner_type)) != INTEGER_CST + || !tree_int_cst_equal (TYPE_SIZE (outer_type), + TYPE_SIZE (inner_type)))) + return false; + + /* Check conversions between arrays with partially known extents. + If the array min/max values are constant they have to match. + Otherwise allow conversions to unknown and variable extents. + In particular this declares conversions that may change the + mode to BLKmode as useless. */ + if (TYPE_DOMAIN (inner_type) + && TYPE_DOMAIN (outer_type) + && TYPE_DOMAIN (inner_type) != TYPE_DOMAIN (outer_type)) + { + tree inner_min = TYPE_MIN_VALUE (TYPE_DOMAIN (inner_type)); + tree outer_min = TYPE_MIN_VALUE (TYPE_DOMAIN (outer_type)); + tree inner_max = TYPE_MAX_VALUE (TYPE_DOMAIN (inner_type)); + tree outer_max = TYPE_MAX_VALUE (TYPE_DOMAIN (outer_type)); + + /* After gimplification a variable min/max value carries no + additional information compared to a NULL value. All that + matters has been lowered to be part of the IL. */ + if (inner_min && TREE_CODE (inner_min) != INTEGER_CST) + inner_min = NULL_TREE; + if (outer_min && TREE_CODE (outer_min) != INTEGER_CST) + outer_min = NULL_TREE; + if (inner_max && TREE_CODE (inner_max) != INTEGER_CST) + inner_max = NULL_TREE; + if (outer_max && TREE_CODE (outer_max) != INTEGER_CST) + outer_max = NULL_TREE; + + /* Conversions NULL / variable <- cst are useless, but not + the other way around. */ + if (outer_min + && (!inner_min + || !tree_int_cst_equal (inner_min, outer_min))) + return false; + if (outer_max + && (!inner_max + || !tree_int_cst_equal (inner_max, outer_max))) + return false; + } + + /* Recurse on the element check. */ + return useless_type_conversion_p (TREE_TYPE (outer_type), + TREE_TYPE (inner_type)); + } + + else if ((TREE_CODE (inner_type) == FUNCTION_TYPE + || TREE_CODE (inner_type) == METHOD_TYPE) + && TREE_CODE (inner_type) == TREE_CODE (outer_type)) + { + tree outer_parm, inner_parm; + + /* If the return types are not compatible bail out. */ + if (!useless_type_conversion_p (TREE_TYPE (outer_type), + TREE_TYPE (inner_type))) + return false; + + /* Method types should belong to a compatible base class. */ + if (TREE_CODE (inner_type) == METHOD_TYPE + && !useless_type_conversion_p (TYPE_METHOD_BASETYPE (outer_type), + TYPE_METHOD_BASETYPE (inner_type))) + return false; + + /* A conversion to an unprototyped argument list is ok. */ + if (!prototype_p (outer_type)) + return true; + + /* If the unqualified argument types are compatible the conversion + is useless. */ + if (TYPE_ARG_TYPES (outer_type) == TYPE_ARG_TYPES (inner_type)) + return true; + + for (outer_parm = TYPE_ARG_TYPES (outer_type), + inner_parm = TYPE_ARG_TYPES (inner_type); + outer_parm && inner_parm; + outer_parm = TREE_CHAIN (outer_parm), + inner_parm = TREE_CHAIN (inner_parm)) + if (!useless_type_conversion_p + (TYPE_MAIN_VARIANT (TREE_VALUE (outer_parm)), + TYPE_MAIN_VARIANT (TREE_VALUE (inner_parm)))) + return false; + + /* If there is a mismatch in the number of arguments the functions + are not compatible. */ + if (outer_parm || inner_parm) + return false; + + /* Defer to the target if necessary. */ + if (TYPE_ATTRIBUTES (inner_type) || TYPE_ATTRIBUTES (outer_type)) + return comp_type_attributes (outer_type, inner_type) != 0; + + return true; + } + + /* For aggregates we rely on TYPE_CANONICAL exclusively and require + explicit conversions for types involving to be structurally + compared types. */ + else if (AGGREGATE_TYPE_P (inner_type) + && TREE_CODE (inner_type) == TREE_CODE (outer_type)) + return false; + + return false; +} + + +/* ----- Decl related ----- */ + +/* Set sequence SEQ to be the GIMPLE body for function FN. */ + +void +gimple_set_body (tree fndecl, gimple_seq seq) +{ + struct function *fn = DECL_STRUCT_FUNCTION (fndecl); + if (fn == NULL) + { + /* If FNDECL still does not have a function structure associated + with it, then it does not make sense for it to receive a + GIMPLE body. */ + gcc_assert (seq == NULL); + } + else + fn->gimple_body = seq; +} + + +/* Return the body of GIMPLE statements for function FN. After the + CFG pass, the function body doesn't exist anymore because it has + been split up into basic blocks. In this case, it returns + NULL. */ + +gimple_seq +gimple_body (tree fndecl) +{ + struct function *fn = DECL_STRUCT_FUNCTION (fndecl); + return fn ? fn->gimple_body : NULL; +} + +/* Return true when FNDECL has Gimple body either in unlowered + or CFG form. */ +bool +gimple_has_body_p (tree fndecl) +{ + struct function *fn = DECL_STRUCT_FUNCTION (fndecl); + return (gimple_body (fndecl) || (fn && fn->cfg)); +} + +/* Return a printable name for symbol DECL. */ + +const char * +gimple_decl_printable_name (tree decl, int verbosity) +{ + if (!DECL_NAME (decl)) + return NULL; + + if (DECL_ASSEMBLER_NAME_SET_P (decl)) + { + const char *str, *mangled_str; + int dmgl_opts = DMGL_NO_OPTS; + + if (verbosity >= 2) + { + dmgl_opts = DMGL_VERBOSE + | DMGL_ANSI + | DMGL_GNU_V3 + | DMGL_RET_POSTFIX; + if (TREE_CODE (decl) == FUNCTION_DECL) + dmgl_opts |= DMGL_PARAMS; + } + + mangled_str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + str = cplus_demangle_v3 (mangled_str, dmgl_opts); + return (str) ? str : mangled_str; + } + + return IDENTIFIER_POINTER (DECL_NAME (decl)); +} + + +/* Create a new VAR_DECL and copy information from VAR to it. */ + +tree +copy_var_decl (tree var, tree name, tree type) +{ + tree copy = build_decl (DECL_SOURCE_LOCATION (var), VAR_DECL, name, type); + + TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (var); + TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (var); + DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (var); + DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (var); + DECL_IGNORED_P (copy) = DECL_IGNORED_P (var); + DECL_CONTEXT (copy) = DECL_CONTEXT (var); + TREE_NO_WARNING (copy) = TREE_NO_WARNING (var); + TREE_USED (copy) = 1; + DECL_SEEN_IN_BIND_EXPR_P (copy) = 1; + DECL_ATTRIBUTES (copy) = DECL_ATTRIBUTES (var); + + return copy; +} + +/* Given SSA_NAMEs NAME1 and NAME2, return true if they are candidates for + coalescing together, false otherwise. + + This must stay consistent with var_map_base_init in tree-ssa-live.c. */ + +bool +gimple_can_coalesce_p (tree name1, tree name2) +{ + /* First check the SSA_NAME's associated DECL. We only want to + coalesce if they have the same DECL or both have no associated DECL. */ + tree var1 = SSA_NAME_VAR (name1); + tree var2 = SSA_NAME_VAR (name2); + var1 = (var1 && (!VAR_P (var1) || !DECL_IGNORED_P (var1))) ? var1 : NULL_TREE; + var2 = (var2 && (!VAR_P (var2) || !DECL_IGNORED_P (var2))) ? var2 : NULL_TREE; + if (var1 != var2) + return false; + + /* Now check the types. If the types are the same, then we should + try to coalesce V1 and V2. */ + tree t1 = TREE_TYPE (name1); + tree t2 = TREE_TYPE (name2); + if (t1 == t2) + return true; + + /* If the types are not the same, check for a canonical type match. This + (for example) allows coalescing when the types are fundamentally the + same, but just have different names. + + Note pointer types with different address spaces may have the same + canonical type. Those are rejected for coalescing by the + types_compatible_p check. */ + if (TYPE_CANONICAL (t1) + && TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2) + && types_compatible_p (t1, t2)) + return true; + + return false; +} + + +/* ----- Expression related ----- */ + +/* Extract the operands and code for expression EXPR into *SUBCODE_P, + *OP1_P, *OP2_P and *OP3_P respectively. */ + +void +extract_ops_from_tree_1 (tree expr, enum tree_code *subcode_p, tree *op1_p, + tree *op2_p, tree *op3_p) +{ + enum gimple_rhs_class grhs_class; + + *subcode_p = TREE_CODE (expr); + grhs_class = get_gimple_rhs_class (*subcode_p); + + if (grhs_class == GIMPLE_TERNARY_RHS) + { + *op1_p = TREE_OPERAND (expr, 0); + *op2_p = TREE_OPERAND (expr, 1); + *op3_p = TREE_OPERAND (expr, 2); + } + else if (grhs_class == GIMPLE_BINARY_RHS) + { + *op1_p = TREE_OPERAND (expr, 0); + *op2_p = TREE_OPERAND (expr, 1); + *op3_p = NULL_TREE; + } + else if (grhs_class == GIMPLE_UNARY_RHS) + { + *op1_p = TREE_OPERAND (expr, 0); + *op2_p = NULL_TREE; + *op3_p = NULL_TREE; + } + else if (grhs_class == GIMPLE_SINGLE_RHS) + { + *op1_p = expr; + *op2_p = NULL_TREE; + *op3_p = NULL_TREE; + } + else + gcc_unreachable (); +} + +/* Extract operands for a GIMPLE_COND statement out of COND_EXPR tree COND. */ + +void +gimple_cond_get_ops_from_tree (tree cond, enum tree_code *code_p, + tree *lhs_p, tree *rhs_p) +{ + gcc_assert (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison + || TREE_CODE (cond) == TRUTH_NOT_EXPR + || is_gimple_min_invariant (cond) + || SSA_VAR_P (cond)); + + extract_ops_from_tree (cond, code_p, lhs_p, rhs_p); + + /* Canonicalize conditionals of the form 'if (!VAL)'. */ + if (*code_p == TRUTH_NOT_EXPR) + { + *code_p = EQ_EXPR; + gcc_assert (*lhs_p && *rhs_p == NULL_TREE); + *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p)); + } + /* Canonicalize conditionals of the form 'if (VAL)' */ + else if (TREE_CODE_CLASS (*code_p) != tcc_comparison) + { + *code_p = NE_EXPR; + gcc_assert (*lhs_p && *rhs_p == NULL_TREE); + *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p)); + } +} + +/* Return true if T is a valid LHS for a GIMPLE assignment expression. */ + +bool +is_gimple_lvalue (tree t) +{ + return (is_gimple_addressable (t) + || TREE_CODE (t) == WITH_SIZE_EXPR + /* These are complex lvalues, but don't have addresses, so they + go here. */ + || TREE_CODE (t) == BIT_FIELD_REF); +} + +/* Return true if T is a GIMPLE condition. */ + +bool +is_gimple_condexpr (tree t) +{ + return (is_gimple_val (t) || (COMPARISON_CLASS_P (t) + && !tree_could_throw_p (t) + && is_gimple_val (TREE_OPERAND (t, 0)) + && is_gimple_val (TREE_OPERAND (t, 1)))); +} + +/* Return true if T is a gimple address. */ + +bool +is_gimple_address (const_tree t) +{ + tree op; + + if (TREE_CODE (t) != ADDR_EXPR) + return false; + + op = TREE_OPERAND (t, 0); + while (handled_component_p (op)) + { + if ((TREE_CODE (op) == ARRAY_REF + || TREE_CODE (op) == ARRAY_RANGE_REF) + && !is_gimple_val (TREE_OPERAND (op, 1))) + return false; + + op = TREE_OPERAND (op, 0); + } + + if (CONSTANT_CLASS_P (op) || TREE_CODE (op) == MEM_REF) + return true; + + switch (TREE_CODE (op)) + { + case PARM_DECL: + case RESULT_DECL: + case LABEL_DECL: + case FUNCTION_DECL: + case VAR_DECL: + case CONST_DECL: + return true; + + default: + return false; + } +} + +/* Return true if T is a gimple invariant address. */ + +bool +is_gimple_invariant_address (const_tree t) +{ + const_tree op; + + if (TREE_CODE (t) != ADDR_EXPR) + return false; + + op = strip_invariant_refs (TREE_OPERAND (t, 0)); + if (!op) + return false; + + if (TREE_CODE (op) == MEM_REF) + { + const_tree op0 = TREE_OPERAND (op, 0); + return (TREE_CODE (op0) == ADDR_EXPR + && (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0)) + || decl_address_invariant_p (TREE_OPERAND (op0, 0)))); + } + + return CONSTANT_CLASS_P (op) || decl_address_invariant_p (op); +} + +/* Return true if T is a gimple invariant address at IPA level + (so addresses of variables on stack are not allowed). */ + +bool +is_gimple_ip_invariant_address (const_tree t) +{ + const_tree op; + + if (TREE_CODE (t) != ADDR_EXPR) + return false; + + op = strip_invariant_refs (TREE_OPERAND (t, 0)); + if (!op) + return false; + + if (TREE_CODE (op) == MEM_REF) + { + const_tree op0 = TREE_OPERAND (op, 0); + return (TREE_CODE (op0) == ADDR_EXPR + && (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0)) + || decl_address_ip_invariant_p (TREE_OPERAND (op0, 0)))); + } + + return CONSTANT_CLASS_P (op) || decl_address_ip_invariant_p (op); +} + +/* Return true if T is a GIMPLE minimal invariant. It's a restricted + form of function invariant. */ + +bool +is_gimple_min_invariant (const_tree t) +{ + if (TREE_CODE (t) == ADDR_EXPR) + return is_gimple_invariant_address (t); + + return is_gimple_constant (t); +} + +/* Return true if T is a GIMPLE interprocedural invariant. It's a restricted + form of gimple minimal invariant. */ + +bool +is_gimple_ip_invariant (const_tree t) +{ + if (TREE_CODE (t) == ADDR_EXPR) + return is_gimple_ip_invariant_address (t); + + return is_gimple_constant (t); +} + +/* Return true if T is a non-aggregate register variable. */ + +bool +is_gimple_reg (tree t) +{ + if (virtual_operand_p (t)) + return false; + + if (TREE_CODE (t) == SSA_NAME) + return true; + + if (!is_gimple_variable (t)) + return false; + + if (!is_gimple_reg_type (TREE_TYPE (t))) + return false; + + /* A volatile decl is not acceptable because we can't reuse it as + needed. We need to copy it into a temp first. */ + if (TREE_THIS_VOLATILE (t)) + return false; + + /* We define "registers" as things that can be renamed as needed, + which with our infrastructure does not apply to memory. */ + if (needs_to_live_in_memory (t)) + return false; + + /* Hard register variables are an interesting case. For those that + are call-clobbered, we don't know where all the calls are, since + we don't (want to) take into account which operations will turn + into libcalls at the rtl level. For those that are call-saved, + we don't currently model the fact that calls may in fact change + global hard registers, nor do we examine ASM_CLOBBERS at the tree + level, and so miss variable changes that might imply. All around, + it seems safest to not do too much optimization with these at the + tree level at all. We'll have to rely on the rtl optimizers to + clean this up, as there we've got all the appropriate bits exposed. */ + if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t)) + return false; + + /* Complex and vector values must have been put into SSA-like form. + That is, no assignments to the individual components. */ + if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE + || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE) + return DECL_GIMPLE_REG_P (t); + + return true; +} + + +/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant. */ + +bool +is_gimple_val (tree t) +{ + /* Make loads from volatiles and memory vars explicit. */ + if (is_gimple_variable (t) + && is_gimple_reg_type (TREE_TYPE (t)) + && !is_gimple_reg (t)) + return false; + + return (is_gimple_variable (t) || is_gimple_min_invariant (t)); +} + +/* Similarly, but accept hard registers as inputs to asm statements. */ + +bool +is_gimple_asm_val (tree t) +{ + if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t)) + return true; + + return is_gimple_val (t); +} + +/* Return true if T is a GIMPLE minimal lvalue. */ + +bool +is_gimple_min_lval (tree t) +{ + if (!(t = CONST_CAST_TREE (strip_invariant_refs (t)))) + return false; + return (is_gimple_id (t) || TREE_CODE (t) == MEM_REF); +} + +/* Return true if T is a valid function operand of a CALL_EXPR. */ + +bool +is_gimple_call_addr (tree t) +{ + return (TREE_CODE (t) == OBJ_TYPE_REF || is_gimple_val (t)); +} + +/* Return true if T is a valid address operand of a MEM_REF. */ + +bool +is_gimple_mem_ref_addr (tree t) +{ + return (is_gimple_reg (t) + || TREE_CODE (t) == INTEGER_CST + || (TREE_CODE (t) == ADDR_EXPR + && (CONSTANT_CLASS_P (TREE_OPERAND (t, 0)) + || decl_address_invariant_p (TREE_OPERAND (t, 0))))); +} diff --git a/gcc/gimple-expr.h b/gcc/gimple-expr.h new file mode 100644 index 0000000..aad558c --- /dev/null +++ b/gcc/gimple-expr.h @@ -0,0 +1,171 @@ +/* Header file for gimple decl, type and expressions. + Copyright (C) 2013 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef GCC_GIMPLE_EXPR_H +#define GCC_GIMPLE_EXPR_H + +extern bool useless_type_conversion_p (tree, tree); + +extern void gimple_set_body (tree, gimple_seq); +extern gimple_seq gimple_body (tree); +extern bool gimple_has_body_p (tree); +extern const char *gimple_decl_printable_name (tree, int); +extern tree copy_var_decl (tree, tree, tree); +extern bool gimple_can_coalesce_p (tree, tree); + +extern void extract_ops_from_tree_1 (tree, enum tree_code *, tree *, tree *, + tree *); +extern void gimple_cond_get_ops_from_tree (tree, enum tree_code *, tree *, + tree *); +extern bool is_gimple_lvalue (tree); +extern bool is_gimple_condexpr (tree); +extern bool is_gimple_address (const_tree); +extern bool is_gimple_invariant_address (const_tree); +extern bool is_gimple_ip_invariant_address (const_tree); +extern bool is_gimple_min_invariant (const_tree); +extern bool is_gimple_ip_invariant (const_tree); +extern bool is_gimple_reg (tree); +extern bool is_gimple_val (tree); +extern bool is_gimple_asm_val (tree); +extern bool is_gimple_min_lval (tree); +extern bool is_gimple_call_addr (tree); +extern bool is_gimple_mem_ref_addr (tree); + +/* Return true if a conversion from either type of TYPE1 and TYPE2 + to the other is not required. Otherwise return false. */ + +static inline bool +types_compatible_p (tree type1, tree type2) +{ + return (type1 == type2 + || (useless_type_conversion_p (type1, type2) + && useless_type_conversion_p (type2, type1))); +} + +/* Return true if TYPE is a suitable type for a scalar register variable. */ + +static inline bool +is_gimple_reg_type (tree type) +{ + return !AGGREGATE_TYPE_P (type); +} + +/* Return true if T is a variable. */ + +static inline bool +is_gimple_variable (tree t) +{ + return (TREE_CODE (t) == VAR_DECL + || TREE_CODE (t) == PARM_DECL + || TREE_CODE (t) == RESULT_DECL + || TREE_CODE (t) == SSA_NAME); +} + +/* Return true if T is a GIMPLE identifier (something with an address). */ + +static inline bool +is_gimple_id (tree t) +{ + return (is_gimple_variable (t) + || TREE_CODE (t) == FUNCTION_DECL + || TREE_CODE (t) == LABEL_DECL + || TREE_CODE (t) == CONST_DECL + /* Allow string constants, since they are addressable. */ + || TREE_CODE (t) == STRING_CST); +} + +/* Return true if OP, an SSA name or a DECL is a virtual operand. */ + +static inline bool +virtual_operand_p (tree op) +{ + if (TREE_CODE (op) == SSA_NAME) + { + op = SSA_NAME_VAR (op); + if (!op) + return false; + } + + if (TREE_CODE (op) == VAR_DECL) + return VAR_DECL_IS_VIRTUAL_OPERAND (op); + + return false; +} + +/* Return true if T is something whose address can be taken. */ + +static inline bool +is_gimple_addressable (tree t) +{ + return (is_gimple_id (t) || handled_component_p (t) + || TREE_CODE (t) == MEM_REF); +} + +/* Return true if T is a valid gimple constant. */ + +static inline bool +is_gimple_constant (const_tree t) +{ + switch (TREE_CODE (t)) + { + case INTEGER_CST: + case REAL_CST: + case FIXED_CST: + case STRING_CST: + case COMPLEX_CST: + case VECTOR_CST: + return true; + + default: + return false; + } +} + +/* A wrapper around extract_ops_from_tree_1, for callers which expect + to see only a maximum of two operands. */ + +static inline void +extract_ops_from_tree (tree expr, enum tree_code *code, tree *op0, + tree *op1) +{ + tree op2; + extract_ops_from_tree_1 (expr, code, op0, op1, &op2); + gcc_assert (op2 == NULL_TREE); +} + +/* Given a valid GIMPLE_CALL function address return the FUNCTION_DECL + associated with the callee if known. Otherwise return NULL_TREE. */ + +static inline tree +gimple_call_addr_fndecl (const_tree fn) +{ + if (fn && TREE_CODE (fn) == ADDR_EXPR) + { + tree fndecl = TREE_OPERAND (fn, 0); + if (TREE_CODE (fndecl) == MEM_REF + && TREE_CODE (TREE_OPERAND (fndecl, 0)) == ADDR_EXPR + && integer_zerop (TREE_OPERAND (fndecl, 1))) + fndecl = TREE_OPERAND (TREE_OPERAND (fndecl, 0), 0); + if (TREE_CODE (fndecl) == FUNCTION_DECL) + return fndecl; + } + return NULL_TREE; +} + +#endif /* GCC_GIMPLE_EXPR_H */ diff --git a/gcc/gimple.c b/gcc/gimple.c index 20f6010..4839f3e 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -386,47 +386,6 @@ gimple_call_get_nobnd_arg_index (const_gimple gs, unsigned index) } -/* Extract the operands and code for expression EXPR into *SUBCODE_P, - *OP1_P, *OP2_P and *OP3_P respectively. */ - -void -extract_ops_from_tree_1 (tree expr, enum tree_code *subcode_p, tree *op1_p, - tree *op2_p, tree *op3_p) -{ - enum gimple_rhs_class grhs_class; - - *subcode_p = TREE_CODE (expr); - grhs_class = get_gimple_rhs_class (*subcode_p); - - if (grhs_class == GIMPLE_TERNARY_RHS) - { - *op1_p = TREE_OPERAND (expr, 0); - *op2_p = TREE_OPERAND (expr, 1); - *op3_p = TREE_OPERAND (expr, 2); - } - else if (grhs_class == GIMPLE_BINARY_RHS) - { - *op1_p = TREE_OPERAND (expr, 0); - *op2_p = TREE_OPERAND (expr, 1); - *op3_p = NULL_TREE; - } - else if (grhs_class == GIMPLE_UNARY_RHS) - { - *op1_p = TREE_OPERAND (expr, 0); - *op2_p = NULL_TREE; - *op3_p = NULL_TREE; - } - else if (grhs_class == GIMPLE_SINGLE_RHS) - { - *op1_p = expr; - *op2_p = NULL_TREE; - *op3_p = NULL_TREE; - } - else - gcc_unreachable (); -} - - /* Build a GIMPLE_ASSIGN statement. LHS of the assignment. @@ -526,37 +485,6 @@ gimple_build_cond (enum tree_code pred_code, tree lhs, tree rhs, return p; } - -/* Extract operands for a GIMPLE_COND statement out of COND_EXPR tree COND. */ - -void -gimple_cond_get_ops_from_tree (tree cond, enum tree_code *code_p, - tree *lhs_p, tree *rhs_p) -{ - gcc_assert (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison - || TREE_CODE (cond) == TRUTH_NOT_EXPR - || is_gimple_min_invariant (cond) - || SSA_VAR_P (cond)); - - extract_ops_from_tree (cond, code_p, lhs_p, rhs_p); - - /* Canonicalize conditionals of the form 'if (!VAL)'. */ - if (*code_p == TRUTH_NOT_EXPR) - { - *code_p = EQ_EXPR; - gcc_assert (*lhs_p && *rhs_p == NULL_TREE); - *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p)); - } - /* Canonicalize conditionals of the form 'if (VAL)' */ - else if (TREE_CODE_CLASS (*code_p) != tcc_comparison) - { - *code_p = NE_EXPR; - gcc_assert (*lhs_p && *rhs_p == NULL_TREE); - *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p)); - } -} - - /* Build a GIMPLE_COND statement from the conditional expression tree COND. T_LABEL and F_LABEL are as in gimple_build_cond. */ @@ -1906,45 +1834,6 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt, } -/* Set sequence SEQ to be the GIMPLE body for function FN. */ - -void -gimple_set_body (tree fndecl, gimple_seq seq) -{ - struct function *fn = DECL_STRUCT_FUNCTION (fndecl); - if (fn == NULL) - { - /* If FNDECL still does not have a function structure associated - with it, then it does not make sense for it to receive a - GIMPLE body. */ - gcc_assert (seq == NULL); - } - else - fn->gimple_body = seq; -} - - -/* Return the body of GIMPLE statements for function FN. After the - CFG pass, the function body doesn't exist anymore because it has - been split up into basic blocks. In this case, it returns - NULL. */ - -gimple_seq -gimple_body (tree fndecl) -{ - struct function *fn = DECL_STRUCT_FUNCTION (fndecl); - return fn ? fn->gimple_body : NULL; -} - -/* Return true when FNDECL has Gimple body either in unlowered - or CFG form. */ -bool -gimple_has_body_p (tree fndecl) -{ - struct function *fn = DECL_STRUCT_FUNCTION (fndecl); - return (gimple_body (fndecl) || (fn && fn->cfg)); -} - /* Return true if calls C1 and C2 are known to go to the same function. */ bool @@ -2602,325 +2491,6 @@ const unsigned char gimple_rhs_class_table[] = { #undef DEFTREECODE #undef END_OF_BASE_TREE_CODES -/* For the definitive definition of GIMPLE, see doc/tree-ssa.texi. */ - -/* Validation of GIMPLE expressions. */ - -/* Return true if T is a valid LHS for a GIMPLE assignment expression. */ - -bool -is_gimple_lvalue (tree t) -{ - return (is_gimple_addressable (t) - || TREE_CODE (t) == WITH_SIZE_EXPR - /* These are complex lvalues, but don't have addresses, so they - go here. */ - || TREE_CODE (t) == BIT_FIELD_REF); -} - -/* Return true if T is a GIMPLE condition. */ - -bool -is_gimple_condexpr (tree t) -{ - return (is_gimple_val (t) || (COMPARISON_CLASS_P (t) - && !tree_could_throw_p (t) - && is_gimple_val (TREE_OPERAND (t, 0)) - && is_gimple_val (TREE_OPERAND (t, 1)))); -} - -/* Return true if T is something whose address can be taken. */ - -bool -is_gimple_addressable (tree t) -{ - return (is_gimple_id (t) || handled_component_p (t) - || TREE_CODE (t) == MEM_REF); -} - -/* Return true if T is a valid gimple constant. */ - -bool -is_gimple_constant (const_tree t) -{ - switch (TREE_CODE (t)) - { - case INTEGER_CST: - case REAL_CST: - case FIXED_CST: - case STRING_CST: - case COMPLEX_CST: - case VECTOR_CST: - return true; - - default: - return false; - } -} - -/* Return true if T is a gimple address. */ - -bool -is_gimple_address (const_tree t) -{ - tree op; - - if (TREE_CODE (t) != ADDR_EXPR) - return false; - - op = TREE_OPERAND (t, 0); - while (handled_component_p (op)) - { - if ((TREE_CODE (op) == ARRAY_REF - || TREE_CODE (op) == ARRAY_RANGE_REF) - && !is_gimple_val (TREE_OPERAND (op, 1))) - return false; - - op = TREE_OPERAND (op, 0); - } - - if (CONSTANT_CLASS_P (op) || TREE_CODE (op) == MEM_REF) - return true; - - switch (TREE_CODE (op)) - { - case PARM_DECL: - case RESULT_DECL: - case LABEL_DECL: - case FUNCTION_DECL: - case VAR_DECL: - case CONST_DECL: - return true; - - default: - return false; - } -} - -/* Return true if T is a gimple invariant address. */ - -bool -is_gimple_invariant_address (const_tree t) -{ - const_tree op; - - if (TREE_CODE (t) != ADDR_EXPR) - return false; - - op = strip_invariant_refs (TREE_OPERAND (t, 0)); - if (!op) - return false; - - if (TREE_CODE (op) == MEM_REF) - { - const_tree op0 = TREE_OPERAND (op, 0); - return (TREE_CODE (op0) == ADDR_EXPR - && (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0)) - || decl_address_invariant_p (TREE_OPERAND (op0, 0)))); - } - - return CONSTANT_CLASS_P (op) || decl_address_invariant_p (op); -} - -/* Return true if T is a gimple invariant address at IPA level - (so addresses of variables on stack are not allowed). */ - -bool -is_gimple_ip_invariant_address (const_tree t) -{ - const_tree op; - - if (TREE_CODE (t) != ADDR_EXPR) - return false; - - op = strip_invariant_refs (TREE_OPERAND (t, 0)); - if (!op) - return false; - - if (TREE_CODE (op) == MEM_REF) - { - const_tree op0 = TREE_OPERAND (op, 0); - return (TREE_CODE (op0) == ADDR_EXPR - && (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0)) - || decl_address_ip_invariant_p (TREE_OPERAND (op0, 0)))); - } - - return CONSTANT_CLASS_P (op) || decl_address_ip_invariant_p (op); -} - -/* Return true if T is a GIMPLE minimal invariant. It's a restricted - form of function invariant. */ - -bool -is_gimple_min_invariant (const_tree t) -{ - if (TREE_CODE (t) == ADDR_EXPR) - return is_gimple_invariant_address (t); - - return is_gimple_constant (t); -} - -/* Return true if T is a GIMPLE interprocedural invariant. It's a restricted - form of gimple minimal invariant. */ - -bool -is_gimple_ip_invariant (const_tree t) -{ - if (TREE_CODE (t) == ADDR_EXPR) - return is_gimple_ip_invariant_address (t); - - return is_gimple_constant (t); -} - -/* Return true if T is a variable. */ - -bool -is_gimple_variable (tree t) -{ - return (TREE_CODE (t) == VAR_DECL - || TREE_CODE (t) == PARM_DECL - || TREE_CODE (t) == RESULT_DECL - || TREE_CODE (t) == SSA_NAME); -} - -/* Return true if T is a GIMPLE identifier (something with an address). */ - -bool -is_gimple_id (tree t) -{ - return (is_gimple_variable (t) - || TREE_CODE (t) == FUNCTION_DECL - || TREE_CODE (t) == LABEL_DECL - || TREE_CODE (t) == CONST_DECL - /* Allow string constants, since they are addressable. */ - || TREE_CODE (t) == STRING_CST); -} - -/* Return true if OP, an SSA name or a DECL is a virtual operand. */ - -bool -virtual_operand_p (tree op) -{ - if (TREE_CODE (op) == SSA_NAME) - { - op = SSA_NAME_VAR (op); - if (!op) - return false; - } - - if (TREE_CODE (op) == VAR_DECL) - return VAR_DECL_IS_VIRTUAL_OPERAND (op); - - return false; -} - - -/* Return true if T is a non-aggregate register variable. */ - -bool -is_gimple_reg (tree t) -{ - if (virtual_operand_p (t)) - return false; - - if (TREE_CODE (t) == SSA_NAME) - return true; - - if (!is_gimple_variable (t)) - return false; - - if (!is_gimple_reg_type (TREE_TYPE (t))) - return false; - - /* A volatile decl is not acceptable because we can't reuse it as - needed. We need to copy it into a temp first. */ - if (TREE_THIS_VOLATILE (t)) - return false; - - /* We define "registers" as things that can be renamed as needed, - which with our infrastructure does not apply to memory. */ - if (needs_to_live_in_memory (t)) - return false; - - /* Hard register variables are an interesting case. For those that - are call-clobbered, we don't know where all the calls are, since - we don't (want to) take into account which operations will turn - into libcalls at the rtl level. For those that are call-saved, - we don't currently model the fact that calls may in fact change - global hard registers, nor do we examine ASM_CLOBBERS at the tree - level, and so miss variable changes that might imply. All around, - it seems safest to not do too much optimization with these at the - tree level at all. We'll have to rely on the rtl optimizers to - clean this up, as there we've got all the appropriate bits exposed. */ - if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t)) - return false; - - /* Complex and vector values must have been put into SSA-like form. - That is, no assignments to the individual components. */ - if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE - || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE) - return DECL_GIMPLE_REG_P (t); - - return true; -} - - -/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant. */ - -bool -is_gimple_val (tree t) -{ - /* Make loads from volatiles and memory vars explicit. */ - if (is_gimple_variable (t) - && is_gimple_reg_type (TREE_TYPE (t)) - && !is_gimple_reg (t)) - return false; - - return (is_gimple_variable (t) || is_gimple_min_invariant (t)); -} - -/* Similarly, but accept hard registers as inputs to asm statements. */ - -bool -is_gimple_asm_val (tree t) -{ - if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t)) - return true; - - return is_gimple_val (t); -} - -/* Return true if T is a GIMPLE minimal lvalue. */ - -bool -is_gimple_min_lval (tree t) -{ - if (!(t = CONST_CAST_TREE (strip_invariant_refs (t)))) - return false; - return (is_gimple_id (t) || TREE_CODE (t) == MEM_REF); -} - -/* Return true if T is a valid function operand of a CALL_EXPR. */ - -bool -is_gimple_call_addr (tree t) -{ - return (TREE_CODE (t) == OBJ_TYPE_REF || is_gimple_val (t)); -} - -/* Return true if T is a valid address operand of a MEM_REF. */ - -bool -is_gimple_mem_ref_addr (tree t) -{ - return (is_gimple_reg (t) - || TREE_CODE (t) == INTEGER_CST - || (TREE_CODE (t) == ADDR_EXPR - && (CONSTANT_CLASS_P (TREE_OPERAND (t, 0)) - || decl_address_invariant_p (TREE_OPERAND (t, 0))))); -} - - /* Given a memory reference expression T, return its base address. The base address of a memory reference expression is the main object being referenced. For instance, the base address for @@ -3642,37 +3212,6 @@ gimple_ior_addresses_taken (bitmap addresses_taken, gimple stmt) } -/* Return a printable name for symbol DECL. */ - -const char * -gimple_decl_printable_name (tree decl, int verbosity) -{ - if (!DECL_NAME (decl)) - return NULL; - - if (DECL_ASSEMBLER_NAME_SET_P (decl)) - { - const char *str, *mangled_str; - int dmgl_opts = DMGL_NO_OPTS; - - if (verbosity >= 2) - { - dmgl_opts = DMGL_VERBOSE - | DMGL_ANSI - | DMGL_GNU_V3 - | DMGL_RET_POSTFIX; - if (TREE_CODE (decl) == FUNCTION_DECL) - dmgl_opts |= DMGL_PARAMS; - } - - mangled_str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); - str = cplus_demangle_v3 (mangled_str, dmgl_opts); - return (str) ? str : mangled_str; - } - - return IDENTIFIER_POINTER (DECL_NAME (decl)); -} - /* Return TRUE iff stmt is a call to a built-in function. */ bool @@ -3763,261 +3302,6 @@ gimple_asm_clobbers_memory_p (const_gimple stmt) return false; } - -/* Return true if the conversion from INNER_TYPE to OUTER_TYPE is a - useless type conversion, otherwise return false. - - This function implicitly defines the middle-end type system. With - the notion of 'a < b' meaning that useless_type_conversion_p (a, b) - holds and 'a > b' meaning that useless_type_conversion_p (b, a) holds, - the following invariants shall be fulfilled: - - 1) useless_type_conversion_p is transitive. - If a < b and b < c then a < c. - - 2) useless_type_conversion_p is not symmetric. - From a < b does not follow a > b. - - 3) Types define the available set of operations applicable to values. - A type conversion is useless if the operations for the target type - is a subset of the operations for the source type. For example - casts to void* are useless, casts from void* are not (void* can't - be dereferenced or offsetted, but copied, hence its set of operations - is a strict subset of that of all other data pointer types). Casts - to const T* are useless (can't be written to), casts from const T* - to T* are not. */ - -bool -useless_type_conversion_p (tree outer_type, tree inner_type) -{ - /* Do the following before stripping toplevel qualifiers. */ - if (POINTER_TYPE_P (inner_type) - && POINTER_TYPE_P (outer_type)) - { - /* Do not lose casts between pointers to different address spaces. */ - if (TYPE_ADDR_SPACE (TREE_TYPE (outer_type)) - != TYPE_ADDR_SPACE (TREE_TYPE (inner_type))) - return false; - } - - /* From now on qualifiers on value types do not matter. */ - inner_type = TYPE_MAIN_VARIANT (inner_type); - outer_type = TYPE_MAIN_VARIANT (outer_type); - - if (inner_type == outer_type) - return true; - - /* If we know the canonical types, compare them. */ - if (TYPE_CANONICAL (inner_type) - && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type)) - return true; - - /* Changes in machine mode are never useless conversions unless we - deal with aggregate types in which case we defer to later checks. */ - if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type) - && !AGGREGATE_TYPE_P (inner_type)) - return false; - - /* If both the inner and outer types are integral types, then the - conversion is not necessary if they have the same mode and - signedness and precision, and both or neither are boolean. */ - if (INTEGRAL_TYPE_P (inner_type) - && INTEGRAL_TYPE_P (outer_type)) - { - /* Preserve changes in signedness or precision. */ - if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type) - || TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type)) - return false; - - /* Preserve conversions to/from BOOLEAN_TYPE if types are not - of precision one. */ - if (((TREE_CODE (inner_type) == BOOLEAN_TYPE) - != (TREE_CODE (outer_type) == BOOLEAN_TYPE)) - && TYPE_PRECISION (outer_type) != 1) - return false; - - /* We don't need to preserve changes in the types minimum or - maximum value in general as these do not generate code - unless the types precisions are different. */ - return true; - } - - /* Scalar floating point types with the same mode are compatible. */ - else if (SCALAR_FLOAT_TYPE_P (inner_type) - && SCALAR_FLOAT_TYPE_P (outer_type)) - return true; - - /* Fixed point types with the same mode are compatible. */ - else if (FIXED_POINT_TYPE_P (inner_type) - && FIXED_POINT_TYPE_P (outer_type)) - return true; - - /* We need to take special care recursing to pointed-to types. */ - else if (POINTER_TYPE_P (inner_type) - && POINTER_TYPE_P (outer_type)) - { - /* Do not lose casts to function pointer types. */ - if ((TREE_CODE (TREE_TYPE (outer_type)) == FUNCTION_TYPE - || TREE_CODE (TREE_TYPE (outer_type)) == METHOD_TYPE) - && !(TREE_CODE (TREE_TYPE (inner_type)) == FUNCTION_TYPE - || TREE_CODE (TREE_TYPE (inner_type)) == METHOD_TYPE)) - return false; - - /* We do not care for const qualification of the pointed-to types - as const qualification has no semantic value to the middle-end. */ - - /* Otherwise pointers/references are equivalent. */ - return true; - } - - /* Recurse for complex types. */ - else if (TREE_CODE (inner_type) == COMPLEX_TYPE - && TREE_CODE (outer_type) == COMPLEX_TYPE) - return useless_type_conversion_p (TREE_TYPE (outer_type), - TREE_TYPE (inner_type)); - - /* Recurse for vector types with the same number of subparts. */ - else if (TREE_CODE (inner_type) == VECTOR_TYPE - && TREE_CODE (outer_type) == VECTOR_TYPE - && TYPE_PRECISION (inner_type) == TYPE_PRECISION (outer_type)) - return useless_type_conversion_p (TREE_TYPE (outer_type), - TREE_TYPE (inner_type)); - - else if (TREE_CODE (inner_type) == ARRAY_TYPE - && TREE_CODE (outer_type) == ARRAY_TYPE) - { - /* Preserve string attributes. */ - if (TYPE_STRING_FLAG (inner_type) != TYPE_STRING_FLAG (outer_type)) - return false; - - /* Conversions from array types with unknown extent to - array types with known extent are not useless. */ - if (!TYPE_DOMAIN (inner_type) - && TYPE_DOMAIN (outer_type)) - return false; - - /* Nor are conversions from array types with non-constant size to - array types with constant size or to different size. */ - if (TYPE_SIZE (outer_type) - && TREE_CODE (TYPE_SIZE (outer_type)) == INTEGER_CST - && (!TYPE_SIZE (inner_type) - || TREE_CODE (TYPE_SIZE (inner_type)) != INTEGER_CST - || !tree_int_cst_equal (TYPE_SIZE (outer_type), - TYPE_SIZE (inner_type)))) - return false; - - /* Check conversions between arrays with partially known extents. - If the array min/max values are constant they have to match. - Otherwise allow conversions to unknown and variable extents. - In particular this declares conversions that may change the - mode to BLKmode as useless. */ - if (TYPE_DOMAIN (inner_type) - && TYPE_DOMAIN (outer_type) - && TYPE_DOMAIN (inner_type) != TYPE_DOMAIN (outer_type)) - { - tree inner_min = TYPE_MIN_VALUE (TYPE_DOMAIN (inner_type)); - tree outer_min = TYPE_MIN_VALUE (TYPE_DOMAIN (outer_type)); - tree inner_max = TYPE_MAX_VALUE (TYPE_DOMAIN (inner_type)); - tree outer_max = TYPE_MAX_VALUE (TYPE_DOMAIN (outer_type)); - - /* After gimplification a variable min/max value carries no - additional information compared to a NULL value. All that - matters has been lowered to be part of the IL. */ - if (inner_min && TREE_CODE (inner_min) != INTEGER_CST) - inner_min = NULL_TREE; - if (outer_min && TREE_CODE (outer_min) != INTEGER_CST) - outer_min = NULL_TREE; - if (inner_max && TREE_CODE (inner_max) != INTEGER_CST) - inner_max = NULL_TREE; - if (outer_max && TREE_CODE (outer_max) != INTEGER_CST) - outer_max = NULL_TREE; - - /* Conversions NULL / variable <- cst are useless, but not - the other way around. */ - if (outer_min - && (!inner_min - || !tree_int_cst_equal (inner_min, outer_min))) - return false; - if (outer_max - && (!inner_max - || !tree_int_cst_equal (inner_max, outer_max))) - return false; - } - - /* Recurse on the element check. */ - return useless_type_conversion_p (TREE_TYPE (outer_type), - TREE_TYPE (inner_type)); - } - - else if ((TREE_CODE (inner_type) == FUNCTION_TYPE - || TREE_CODE (inner_type) == METHOD_TYPE) - && TREE_CODE (inner_type) == TREE_CODE (outer_type)) - { - tree outer_parm, inner_parm; - - /* If the return types are not compatible bail out. */ - if (!useless_type_conversion_p (TREE_TYPE (outer_type), - TREE_TYPE (inner_type))) - return false; - - /* Method types should belong to a compatible base class. */ - if (TREE_CODE (inner_type) == METHOD_TYPE - && !useless_type_conversion_p (TYPE_METHOD_BASETYPE (outer_type), - TYPE_METHOD_BASETYPE (inner_type))) - return false; - - /* A conversion to an unprototyped argument list is ok. */ - if (!prototype_p (outer_type)) - return true; - - /* If the unqualified argument types are compatible the conversion - is useless. */ - if (TYPE_ARG_TYPES (outer_type) == TYPE_ARG_TYPES (inner_type)) - return true; - - for (outer_parm = TYPE_ARG_TYPES (outer_type), - inner_parm = TYPE_ARG_TYPES (inner_type); - outer_parm && inner_parm; - outer_parm = TREE_CHAIN (outer_parm), - inner_parm = TREE_CHAIN (inner_parm)) - if (!useless_type_conversion_p - (TYPE_MAIN_VARIANT (TREE_VALUE (outer_parm)), - TYPE_MAIN_VARIANT (TREE_VALUE (inner_parm)))) - return false; - - /* If there is a mismatch in the number of arguments the functions - are not compatible. */ - if (outer_parm || inner_parm) - return false; - - /* Defer to the target if necessary. */ - if (TYPE_ATTRIBUTES (inner_type) || TYPE_ATTRIBUTES (outer_type)) - return comp_type_attributes (outer_type, inner_type) != 0; - - return true; - } - - /* For aggregates we rely on TYPE_CANONICAL exclusively and require - explicit conversions for types involving to be structurally - compared types. */ - else if (AGGREGATE_TYPE_P (inner_type) - && TREE_CODE (inner_type) == TREE_CODE (outer_type)) - return false; - - return false; -} - -/* Return true if a conversion from either type of TYPE1 and TYPE2 - to the other is not required. Otherwise return false. */ - -bool -types_compatible_p (tree type1, tree type2) -{ - return (type1 == type2 - || (useless_type_conversion_p (type1, type2) - && useless_type_conversion_p (type2, type1))); -} - /* Dump bitmap SET (assumed to contain VAR_DECLs) to FILE. */ void @@ -4042,45 +3326,6 @@ dump_decl_set (FILE *file, bitmap set) fprintf (file, "NIL"); } -/* Given SSA_NAMEs NAME1 and NAME2, return true if they are candidates for - coalescing together, false otherwise. - - This must stay consistent with var_map_base_init in tree-ssa-live.c. */ - -bool -gimple_can_coalesce_p (tree name1, tree name2) -{ - /* First check the SSA_NAME's associated DECL. We only want to - coalesce if they have the same DECL or both have no associated DECL. */ - tree var1 = SSA_NAME_VAR (name1); - tree var2 = SSA_NAME_VAR (name2); - var1 = (var1 && (!VAR_P (var1) || !DECL_IGNORED_P (var1))) ? var1 : NULL_TREE; - var2 = (var2 && (!VAR_P (var2) || !DECL_IGNORED_P (var2))) ? var2 : NULL_TREE; - if (var1 != var2) - return false; - - /* Now check the types. If the types are the same, then we should - try to coalesce V1 and V2. */ - tree t1 = TREE_TYPE (name1); - tree t2 = TREE_TYPE (name2); - if (t1 == t2) - return true; - - /* If the types are not the same, check for a canonical type match. This - (for example) allows coalescing when the types are fundamentally the - same, but just have different names. - - Note pointer types with different address spaces may have the same - canonical type. Those are rejected for coalescing by the - types_compatible_p check. */ - if (TYPE_CANONICAL (t1) - && TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2) - && types_compatible_p (t1, t2)) - return true; - - return false; -} - /* Return true when CALL is a call stmt that definitely doesn't free any memory or makes it unavailable otherwise. */ bool @@ -4102,24 +3347,3 @@ nonfreeing_call_p (gimple call) return false; } - -/* Create a new VAR_DECL and copy information from VAR to it. */ - -tree -copy_var_decl (tree var, tree name, tree type) -{ - tree copy = build_decl (DECL_SOURCE_LOCATION (var), VAR_DECL, name, type); - - TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (var); - TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (var); - DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (var); - DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (var); - DECL_IGNORED_P (copy) = DECL_IGNORED_P (var); - DECL_CONTEXT (copy) = DECL_CONTEXT (var); - TREE_NO_WARNING (copy) = TREE_NO_WARNING (var); - TREE_USED (copy) = 1; - DECL_SEEN_IN_BIND_EXPR_P (copy) = 1; - DECL_ATTRIBUTES (copy) = DECL_ATTRIBUTES (var); - - return copy; -} diff --git a/gcc/gimple.h b/gcc/gimple.h index 90773c0..70a4eb6 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see #include "internal-fn.h" #include "gimple-fold.h" #include "tree-eh.h" +#include "gimple-expr.h" typedef gimple gimple_seq_node; @@ -745,8 +746,6 @@ gimple gimple_build_return (tree); gimple gimple_build_assign_stat (tree, tree MEM_STAT_DECL); #define gimple_build_assign(l,r) gimple_build_assign_stat (l, r MEM_STAT_INFO) -void extract_ops_from_tree_1 (tree, enum tree_code *, tree *, tree *, tree *); - gimple gimple_build_assign_with_ops (enum tree_code, tree, tree, tree CXX_MEM_STAT_INFO); @@ -809,9 +808,6 @@ gimple gimple_build_predict (enum br_predictor, enum prediction); enum gimple_statement_structure_enum gss_for_assign (enum tree_code); void sort_case_labels (vec ); void preprocess_case_label_vec_for_gimple (vec , tree, tree *); -void gimple_set_body (tree, gimple_seq); -gimple_seq gimple_body (tree); -bool gimple_has_body_p (tree); gimple_seq gimple_seq_alloc (void); void gimple_seq_free (gimple_seq); void gimple_seq_add_seq (gimple_seq *, gimple_seq); @@ -832,7 +828,6 @@ tree gimple_get_lhs (const_gimple); void gimple_set_lhs (gimple, tree); void gimple_replace_lhs (gimple, tree); gimple gimple_copy (gimple); -void gimple_cond_get_ops_from_tree (tree, enum tree_code *, tree *, tree *); gimple gimple_build_cond_from_tree (tree, tree, tree); void gimple_cond_set_condition_from_tree (gimple, tree); bool gimple_has_side_effects (const_gimple); @@ -844,48 +839,6 @@ bool empty_body_p (gimple_seq); unsigned get_gimple_rhs_num_ops (enum tree_code); #define gimple_alloc(c, n) gimple_alloc_stat (c, n MEM_STAT_INFO) gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL); -const char *gimple_decl_printable_name (tree, int); - -/* Returns true iff T is a virtual ssa name decl. */ -extern bool virtual_operand_p (tree); -/* Returns true iff T is a scalar register variable. */ -extern bool is_gimple_reg (tree); -/* Returns true iff T is any sort of variable. */ -extern bool is_gimple_variable (tree); -/* Returns true iff T is any sort of symbol. */ -extern bool is_gimple_id (tree); -/* Returns true iff T is a variable or an INDIRECT_REF (of a variable). */ -extern bool is_gimple_min_lval (tree); -/* Returns true iff T is something whose address can be taken. */ -extern bool is_gimple_addressable (tree); -/* Returns true iff T is any valid GIMPLE lvalue. */ -extern bool is_gimple_lvalue (tree); - -/* Returns true iff T is a GIMPLE address. */ -bool is_gimple_address (const_tree); -/* Returns true iff T is a GIMPLE invariant address. */ -bool is_gimple_invariant_address (const_tree); -/* Returns true iff T is a GIMPLE invariant address at interprocedural - level. */ -bool is_gimple_ip_invariant_address (const_tree); -/* Returns true iff T is a valid GIMPLE constant. */ -bool is_gimple_constant (const_tree); -/* Returns true iff T is a GIMPLE restricted function invariant. */ -extern bool is_gimple_min_invariant (const_tree); -/* Returns true iff T is a GIMPLE restricted interprecodural invariant. */ -extern bool is_gimple_ip_invariant (const_tree); -/* Returns true iff T is a GIMPLE rvalue. */ -extern bool is_gimple_val (tree); -/* Returns true iff T is a GIMPLE asm statement input. */ -extern bool is_gimple_asm_val (tree); -/* Returns true iff T is a valid address operand of a MEM_REF. */ -bool is_gimple_mem_ref_addr (tree); - -/* Returns true iff T is a valid if-statement condition. */ -extern bool is_gimple_condexpr (tree); - -/* Returns true iff T is a valid call address expression. */ -extern bool is_gimple_call_addr (tree); /* Return TRUE iff stmt is a call to a built-in function. */ extern bool is_gimple_builtin_call (gimple stmt); @@ -906,8 +859,6 @@ extern bool gimple_ior_addresses_taken (bitmap, gimple); extern bool gimple_call_builtin_p (gimple, enum built_in_class); extern bool gimple_call_builtin_p (gimple, enum built_in_function); extern bool gimple_asm_clobbers_memory_p (const_gimple); -extern bool useless_type_conversion_p (tree, tree); -extern bool types_compatible_p (tree, tree); /* In gimplify.c */ extern tree create_tmp_var_raw (tree, const char *); @@ -1086,9 +1037,7 @@ extern tree gimple_boolify (tree); extern gimple_predicate rhs_predicate_for (tree); extern tree canonicalize_cond_expr_cond (tree); extern void dump_decl_set (FILE *, bitmap); -extern bool gimple_can_coalesce_p (tree, tree); extern bool nonfreeing_call_p (gimple); -extern tree copy_var_decl (tree, tree, tree); /* In trans-mem.c. */ extern void diagnose_tm_safe_errors (tree); @@ -2042,18 +1991,6 @@ gimple_assign_set_rhs_with_ops (gimple_stmt_iterator *gsi, enum tree_code code, gimple_assign_set_rhs_with_ops_1 (gsi, code, op1, op2, NULL); } -/* A wrapper around extract_ops_from_tree_1, for callers which expect - to see only a maximum of two operands. */ - -static inline void -extract_ops_from_tree (tree expr, enum tree_code *code, tree *op0, - tree *op1) -{ - tree op2; - extract_ops_from_tree_1 (expr, code, op0, op1, &op2); - gcc_assert (op2 == NULL_TREE); -} - /* Returns true if GS is a nontemporal move. */ static inline bool @@ -2316,25 +2253,6 @@ gimple_call_set_internal_fn (gimple gs, enum internal_fn fn) } -/* Given a valid GIMPLE_CALL function address return the FUNCTION_DECL - associated with the callee if known. Otherwise return NULL_TREE. */ - -static inline tree -gimple_call_addr_fndecl (const_tree fn) -{ - if (fn && TREE_CODE (fn) == ADDR_EXPR) - { - tree fndecl = TREE_OPERAND (fn, 0); - if (TREE_CODE (fndecl) == MEM_REF - && TREE_CODE (TREE_OPERAND (fndecl, 0)) == ADDR_EXPR - && integer_zerop (TREE_OPERAND (fndecl, 1))) - fndecl = TREE_OPERAND (TREE_OPERAND (fndecl, 0), 0); - if (TREE_CODE (fndecl) == FUNCTION_DECL) - return fndecl; - } - return NULL_TREE; -} - /* If a given GIMPLE_CALL's callee is a FUNCTION_DECL, return it. Otherwise return NULL. This function is analogous to get_callee_fndecl in tree land. */ @@ -5385,14 +5303,6 @@ gimple_expr_type (const_gimple stmt) return void_type_node; } -/* Return true if TYPE is a suitable type for a scalar register variable. */ - -static inline bool -is_gimple_reg_type (tree type) -{ - return !AGGREGATE_TYPE_P (type); -} - /* Return a new iterator pointing to GIMPLE_SEQ's first statement. */ static inline gimple_stmt_iterator