From cfef45c8097d122e7dfda42c5e2767bf21a7f649 Mon Sep 17 00:00:00 2001 From: Richard Guenther Date: Thu, 24 Mar 2011 11:23:29 +0000 Subject: [PATCH] re PR tree-optimization/46562 (CCP currently needs iteration for &a[i]) 2011-03-24 Richard Guenther PR tree-optimization/46562 * tree.c (build_invariant_address): New function. * tree.h (build_invariant_address): Declare. * tree-dfa.c (get_addr_base_and_unit_offset): Wrap around a renamed function moved ... * tree-flow-inline.h (get_addr_base_and_unit_offset_1): ... here. Take valueization callback parameter. * tree-flow.h (gimple_fold_stmt_to_constant): Declare. * gimple-fold.h: New file. * tree-ssa-ccp.c (ccp_fold): Use gimple_fold_stmt_to_constant_1. (ccp_fold, fold_const_aggregate_ref, fold_ctor_reference, fold_nonarray_ctor_reference, fold_array_ctor_reference, fold_string_cst_ctor_reference, get_base_constructor): Move ... * gimple-fold.c: ... here. (gimple_fold_stmt_to_constant_1): New function split out from ccp_fold. Take a valueization callback parameter. Valueize all operands. (gimple_fold_stmt_to_constant): New wrapper function. (fold_const_aggregate_ref_1): New function split out from fold_const_aggregate_ref. Take a valueization callback parameter. (fold_const_aggregate_ref): Wrap fold_const_aggregate_ref_1. * tree-ssa-sccvn.c (simplify_binary_expression): Simplify invariant POINTER_PLUS_EXPRs to invariant form. (vn_valueize): New function. (try_to_simplify): Simplify by using gimple_fold_stmt_to_constant. * tree-vrp.c (vrp_valueize): New function. (vrp_visit_assignment_or_call): Use gimple_fold_stmt_to_constant to fold statements to constants. * tree-ssa-pre.c (eliminate): Properly guard propagation of function declarations. * Makefile.in (tree-ssa-sccvn.o, tree-vrp.o, gimple-fold.o, tree-ssa-ccp.o): Add gimple-fold.h dependencies. * c-c++-common/pr46562-2.c: New testcase. * c-c++-common/pr46562.c: Likewise. From-SVN: r171386 --- gcc/ChangeLog | 36 ++ gcc/Makefile.in | 8 +- gcc/gimple-fold.c | 637 +++++++++++++++++++++++++ gcc/gimple-fold.h | 33 ++ gcc/ipa-split.c | 29 +- gcc/testsuite/ChangeLog | 6 + gcc/testsuite/c-c++-common/pr46562-2.c | 13 + gcc/testsuite/c-c++-common/pr46562.c | 13 + gcc/tree-dfa.c | 105 +--- gcc/tree-flow-inline.h | 135 ++++++ gcc/tree-flow.h | 1 + gcc/tree-ssa-ccp.c | 608 +---------------------- gcc/tree-ssa-pre.c | 7 +- gcc/tree-ssa-sccvn.c | 46 +- gcc/tree-vrp.c | 24 +- gcc/tree.c | 14 + gcc/tree.h | 1 + 17 files changed, 984 insertions(+), 732 deletions(-) create mode 100644 gcc/gimple-fold.h create mode 100644 gcc/testsuite/c-c++-common/pr46562-2.c create mode 100644 gcc/testsuite/c-c++-common/pr46562.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 907c83b5121..9dec3e406fa 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,39 @@ +2011-03-24 Richard Guenther + + PR tree-optimization/46562 + * tree.c (build_invariant_address): New function. + * tree.h (build_invariant_address): Declare. + * tree-dfa.c (get_addr_base_and_unit_offset): Wrap around + a renamed function moved ... + * tree-flow-inline.h (get_addr_base_and_unit_offset_1): ... here. + Take valueization callback parameter. + * tree-flow.h (gimple_fold_stmt_to_constant): Declare. + * gimple-fold.h: New file. + * tree-ssa-ccp.c (ccp_fold): Use gimple_fold_stmt_to_constant_1. + (ccp_fold, fold_const_aggregate_ref, + fold_ctor_reference, fold_nonarray_ctor_reference, + fold_array_ctor_reference, fold_string_cst_ctor_reference, + get_base_constructor): Move ... + * gimple-fold.c: ... here. + (gimple_fold_stmt_to_constant_1): New function + split out from ccp_fold. Take a valueization callback parameter. + Valueize all operands. + (gimple_fold_stmt_to_constant): New wrapper function. + (fold_const_aggregate_ref_1): New function split out from + fold_const_aggregate_ref. Take a valueization callback parameter. + (fold_const_aggregate_ref): Wrap fold_const_aggregate_ref_1. + * tree-ssa-sccvn.c (simplify_binary_expression): Simplify + invariant POINTER_PLUS_EXPRs to invariant form. + (vn_valueize): New function. + (try_to_simplify): Simplify by using gimple_fold_stmt_to_constant. + * tree-vrp.c (vrp_valueize): New function. + (vrp_visit_assignment_or_call): Use gimple_fold_stmt_to_constant + to fold statements to constants. + * tree-ssa-pre.c (eliminate): Properly guard propagation of + function declarations. + * Makefile.in (tree-ssa-sccvn.o, tree-vrp.o, gimple-fold.o, + tree-ssa-ccp.o): Add gimple-fold.h dependencies. + 2011-03-24 Richard Sandiford * config/h8300/predicates.md (jump_address_operand): Fix register diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 5e4027e5070..3ce80611bf4 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2485,12 +2485,12 @@ tree-ssa-sccvn.o : tree-ssa-sccvn.c $(TREE_FLOW_H) $(CONFIG_H) \ $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_PASS_H) $(FLAGS_H) $(CFGLOOP_H) \ alloc-pool.h $(BASIC_BLOCK_H) $(BITMAP_H) langhooks.h $(HASHTAB_H) $(GIMPLE_H) \ $(TREE_INLINE_H) tree-iterator.h tree-ssa-propagate.h tree-ssa-sccvn.h \ - $(PARAMS_H) tree-pretty-print.h gimple-pretty-print.h + $(PARAMS_H) tree-pretty-print.h gimple-pretty-print.h gimple-fold.h tree-vrp.o : tree-vrp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(TREE_FLOW_H) $(TREE_PASS_H) $(TREE_DUMP_H) $(DIAGNOSTIC_H) $(GGC_H) \ $(BASIC_BLOCK_H) tree-ssa-propagate.h $(FLAGS_H) $(TREE_DUMP_H) \ $(CFGLOOP_H) $(SCEV_H) $(TIMEVAR_H) intl.h tree-pretty-print.h \ - gimple-pretty-print.h + gimple-pretty-print.h gimple-fold.h tree-cfg.o : tree-cfg.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \ $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ @@ -2638,7 +2638,7 @@ gimple-fold.o : gimple-fold.c $(TREE_FLOW_H) $(CONFIG_H) \ $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h \ $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ $(TREE_DUMP_H) $(BASIC_BLOCK_H) $(TREE_PASS_H) langhooks.h \ - tree-ssa-propagate.h value-prof.h $(FLAGS_H) $(TARGET_H) + tree-ssa-propagate.h value-prof.h $(FLAGS_H) $(TARGET_H) gimple-fold.h gimple-low.o : gimple-low.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \ $(DIAGNOSTIC_H) $(GIMPLE_H) $(TREE_INLINE_H) langhooks.h \ $(LANGHOOKS_DEF_H) $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ @@ -3103,7 +3103,7 @@ tree-ssa-ccp.o : tree-ssa-ccp.c $(TREE_FLOW_H) $(CONFIG_H) \ $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ $(TREE_DUMP_H) $(BASIC_BLOCK_H) $(TREE_PASS_H) langhooks.h \ tree-ssa-propagate.h value-prof.h $(FLAGS_H) $(TARGET_H) $(DIAGNOSTIC_CORE_H) \ - $(DBGCNT_H) tree-pretty-print.h gimple-pretty-print.h + $(DBGCNT_H) tree-pretty-print.h gimple-pretty-print.h gimple-fold.h tree-sra.o : tree-sra.c $(CONFIG_H) $(SYSTEM_H) coretypes.h alloc-pool.h \ $(TM_H) $(TREE_H) $(GIMPLE_H) $(CGRAPH_H) $(TREE_FLOW_H) \ $(IPA_PROP_H) $(DIAGNOSTIC_H) statistics.h $(TREE_DUMP_H) $(TIMEVAR_H) \ diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 158cb05802d..367e40e3029 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "tree-ssa-propagate.h" #include "target.h" +#include "gimple-fold.h" /* Return true when DECL can be referenced from current unit. We can get declarations that are not possible to reference for @@ -2665,3 +2666,639 @@ maybe_fold_or_comparisons (enum tree_code code1, tree op1a, tree op1b, else return or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b); } + + +/* Fold STMT to a constant using VALUEIZE to valueize SSA names. + + Either NULL_TREE, a simplified but non-constant or a constant + is returned. + + ??? This should go into a gimple-fold-inline.h file to be eventually + privatized with the single valueize function used in the various TUs + to avoid the indirect function call overhead. */ + +tree +gimple_fold_stmt_to_constant_1 (gimple stmt, tree (*valueize) (tree)) +{ + location_t loc = gimple_location (stmt); + switch (gimple_code (stmt)) + { + case GIMPLE_ASSIGN: + { + enum tree_code subcode = gimple_assign_rhs_code (stmt); + + switch (get_gimple_rhs_class (subcode)) + { + case GIMPLE_SINGLE_RHS: + { + tree rhs = gimple_assign_rhs1 (stmt); + enum tree_code_class kind = TREE_CODE_CLASS (subcode); + + if (TREE_CODE (rhs) == SSA_NAME) + { + /* If the RHS is an SSA_NAME, return its known constant value, + if any. */ + return (*valueize) (rhs); + } + /* Handle propagating invariant addresses into address + operations. */ + else if (TREE_CODE (rhs) == ADDR_EXPR + && !is_gimple_min_invariant (rhs)) + { + HOST_WIDE_INT offset; + tree base; + base = get_addr_base_and_unit_offset_1 (TREE_OPERAND (rhs, 0), + &offset, + valueize); + if (base + && (CONSTANT_CLASS_P (base) + || decl_address_invariant_p (base))) + return build_invariant_address (TREE_TYPE (rhs), + base, offset); + } + else if (TREE_CODE (rhs) == CONSTRUCTOR + && TREE_CODE (TREE_TYPE (rhs)) == VECTOR_TYPE + && (CONSTRUCTOR_NELTS (rhs) + == TYPE_VECTOR_SUBPARTS (TREE_TYPE (rhs)))) + { + unsigned i; + tree val, list; + + list = NULL_TREE; + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (rhs), i, val) + { + val = (*valueize) (val); + if (TREE_CODE (val) == INTEGER_CST + || TREE_CODE (val) == REAL_CST + || TREE_CODE (val) == FIXED_CST) + list = tree_cons (NULL_TREE, val, list); + else + return NULL_TREE; + } + + return build_vector (TREE_TYPE (rhs), nreverse (list)); + } + + if (kind == tcc_reference) + { + if ((TREE_CODE (rhs) == VIEW_CONVERT_EXPR + || TREE_CODE (rhs) == REALPART_EXPR + || TREE_CODE (rhs) == IMAGPART_EXPR) + && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME) + { + tree val = (*valueize) (TREE_OPERAND (rhs, 0)); + return fold_unary_loc (EXPR_LOCATION (rhs), + TREE_CODE (rhs), + TREE_TYPE (rhs), val); + } + else if (TREE_CODE (rhs) == BIT_FIELD_REF + && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME) + { + tree val = (*valueize) (TREE_OPERAND (rhs, 0)); + return fold_ternary_loc (EXPR_LOCATION (rhs), + TREE_CODE (rhs), + TREE_TYPE (rhs), val, + TREE_OPERAND (rhs, 1), + TREE_OPERAND (rhs, 2)); + } + else if (TREE_CODE (rhs) == MEM_REF + && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME) + { + tree val = (*valueize) (TREE_OPERAND (rhs, 0)); + if (TREE_CODE (val) == ADDR_EXPR + && is_gimple_min_invariant (val)) + { + tree tem = fold_build2 (MEM_REF, TREE_TYPE (rhs), + unshare_expr (val), + TREE_OPERAND (rhs, 1)); + if (tem) + rhs = tem; + } + } + return fold_const_aggregate_ref_1 (rhs, valueize); + } + else if (kind == tcc_declaration) + return get_symbol_constant_value (rhs); + return rhs; + } + + case GIMPLE_UNARY_RHS: + { + /* Handle unary operators that can appear in GIMPLE form. + Note that we know the single operand must be a constant, + so this should almost always return a simplified RHS. */ + tree lhs = gimple_assign_lhs (stmt); + tree op0 = (*valueize) (gimple_assign_rhs1 (stmt)); + + /* Conversions are useless for CCP purposes if they are + value-preserving. Thus the restrictions that + useless_type_conversion_p places for pointer type conversions + do not apply here. Substitution later will only substitute to + allowed places. */ + if (CONVERT_EXPR_CODE_P (subcode) + && POINTER_TYPE_P (TREE_TYPE (lhs)) + && POINTER_TYPE_P (TREE_TYPE (op0))) + { + tree tem; + /* Try to re-construct array references on-the-fly. */ + if (!useless_type_conversion_p (TREE_TYPE (lhs), + TREE_TYPE (op0)) + && ((tem = maybe_fold_offset_to_address + (loc, + op0, integer_zero_node, TREE_TYPE (lhs))) + != NULL_TREE)) + return tem; + return op0; + } + + return + fold_unary_ignore_overflow_loc (loc, subcode, + gimple_expr_type (stmt), op0); + } + + case GIMPLE_BINARY_RHS: + { + /* Handle binary operators that can appear in GIMPLE form. */ + tree op0 = (*valueize) (gimple_assign_rhs1 (stmt)); + tree op1 = (*valueize) (gimple_assign_rhs2 (stmt)); + + /* Translate &x + CST into an invariant form suitable for + further propagation. */ + if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR + && TREE_CODE (op0) == ADDR_EXPR + && TREE_CODE (op1) == INTEGER_CST) + { + tree off = fold_convert (ptr_type_node, op1); + return build_fold_addr_expr + (fold_build2 (MEM_REF, + TREE_TYPE (TREE_TYPE (op0)), + unshare_expr (op0), off)); + } + + return fold_binary_loc (loc, subcode, + gimple_expr_type (stmt), op0, op1); + } + + case GIMPLE_TERNARY_RHS: + { + /* Handle ternary operators that can appear in GIMPLE form. */ + tree op0 = (*valueize) (gimple_assign_rhs1 (stmt)); + tree op1 = (*valueize) (gimple_assign_rhs2 (stmt)); + tree op2 = (*valueize) (gimple_assign_rhs3 (stmt)); + + return fold_ternary_loc (loc, subcode, + gimple_expr_type (stmt), op0, op1, op2); + } + + default: + gcc_unreachable (); + } + } + + case GIMPLE_CALL: + { + tree fn = (*valueize) (gimple_call_fn (stmt)); + if (TREE_CODE (fn) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL + && DECL_BUILT_IN (TREE_OPERAND (fn, 0))) + { + tree *args = XALLOCAVEC (tree, gimple_call_num_args (stmt)); + tree call, retval; + unsigned i; + for (i = 0; i < gimple_call_num_args (stmt); ++i) + args[i] = (*valueize) (gimple_call_arg (stmt, i)); + call = build_call_array_loc (loc, + gimple_call_return_type (stmt), + fn, gimple_call_num_args (stmt), args); + retval = fold_call_expr (EXPR_LOCATION (call), call, false); + if (retval) + /* fold_call_expr wraps the result inside a NOP_EXPR. */ + STRIP_NOPS (retval); + return retval; + } + return NULL_TREE; + } + + default: + return NULL_TREE; + } +} + +/* Fold STMT to a constant using VALUEIZE to valueize SSA names. + Returns NULL_TREE if folding to a constant is not possible, otherwise + returns a constant according to is_gimple_min_invariant. */ + +tree +gimple_fold_stmt_to_constant (gimple stmt, tree (*valueize) (tree)) +{ + tree res = gimple_fold_stmt_to_constant_1 (stmt, valueize); + if (res && is_gimple_min_invariant (res)) + return res; + return NULL_TREE; +} + + +/* The following set of functions are supposed to fold references using + their constant initializers. */ + +static tree fold_ctor_reference (tree type, tree ctor, + unsigned HOST_WIDE_INT offset, + unsigned HOST_WIDE_INT size); + +/* See if we can find constructor defining value of BASE. + When we know the consructor with constant offset (such as + base is array[40] and we do know constructor of array), then + BIT_OFFSET is adjusted accordingly. + + As a special case, return error_mark_node when constructor + is not explicitly available, but it is known to be zero + such as 'static const int a;'. */ +static tree +get_base_constructor (tree base, HOST_WIDE_INT *bit_offset, + tree (*valueize)(tree)) +{ + HOST_WIDE_INT bit_offset2, size, max_size; + if (TREE_CODE (base) == MEM_REF) + { + if (!integer_zerop (TREE_OPERAND (base, 1))) + { + if (!host_integerp (TREE_OPERAND (base, 1), 0)) + return NULL_TREE; + *bit_offset += (mem_ref_offset (base).low + * BITS_PER_UNIT); + } + + if (valueize + && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME) + base = valueize (TREE_OPERAND (base, 0)); + if (!base || TREE_CODE (base) != ADDR_EXPR) + return NULL_TREE; + base = TREE_OPERAND (base, 0); + } + + /* Get a CONSTRUCTOR. If BASE is a VAR_DECL, get its + DECL_INITIAL. If BASE is a nested reference into another + ARRAY_REF or COMPONENT_REF, make a recursive call to resolve + the inner reference. */ + switch (TREE_CODE (base)) + { + case VAR_DECL: + if (!const_value_known_p (base)) + return NULL_TREE; + + /* Fallthru. */ + case CONST_DECL: + if (!DECL_INITIAL (base) + && (TREE_STATIC (base) || DECL_EXTERNAL (base))) + return error_mark_node; + return DECL_INITIAL (base); + + case ARRAY_REF: + case COMPONENT_REF: + base = get_ref_base_and_extent (base, &bit_offset2, &size, &max_size); + if (max_size == -1 || size != max_size) + return NULL_TREE; + *bit_offset += bit_offset2; + return get_base_constructor (base, bit_offset, valueize); + + case STRING_CST: + case CONSTRUCTOR: + return base; + + default: + return NULL_TREE; + } +} + +/* CTOR is STRING_CST. Fold reference of type TYPE and size SIZE + to the memory at bit OFFSET. + + We do only simple job of folding byte accesses. */ + +static tree +fold_string_cst_ctor_reference (tree type, tree ctor, + unsigned HOST_WIDE_INT offset, + unsigned HOST_WIDE_INT size) +{ + if (INTEGRAL_TYPE_P (type) + && (TYPE_MODE (type) + == TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) + && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) + == MODE_INT) + && GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) == 1 + && size == BITS_PER_UNIT + && !(offset % BITS_PER_UNIT)) + { + offset /= BITS_PER_UNIT; + if (offset < (unsigned HOST_WIDE_INT) TREE_STRING_LENGTH (ctor)) + return build_int_cst_type (type, (TREE_STRING_POINTER (ctor) + [offset])); + /* Folding + const char a[20]="hello"; + return a[10]; + + might lead to offset greater than string length. In this case we + know value is either initialized to 0 or out of bounds. Return 0 + in both cases. */ + return build_zero_cst (type); + } + return NULL_TREE; +} + +/* CTOR is CONSTRUCTOR of an array type. Fold reference of type TYPE and size + SIZE to the memory at bit OFFSET. */ + +static tree +fold_array_ctor_reference (tree type, tree ctor, + unsigned HOST_WIDE_INT offset, + unsigned HOST_WIDE_INT size) +{ + unsigned HOST_WIDE_INT cnt; + tree cfield, cval; + double_int low_bound, elt_size; + double_int index, max_index; + double_int access_index; + tree domain_type = TYPE_DOMAIN (TREE_TYPE (ctor)); + HOST_WIDE_INT inner_offset; + + /* Compute low bound and elt size. */ + if (domain_type && TYPE_MIN_VALUE (domain_type)) + { + /* Static constructors for variably sized objects makes no sense. */ + gcc_assert (TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST); + low_bound = tree_to_double_int (TYPE_MIN_VALUE (domain_type)); + } + else + low_bound = double_int_zero; + /* Static constructors for variably sized objects makes no sense. */ + gcc_assert (TREE_CODE(TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor)))) + == INTEGER_CST); + elt_size = + tree_to_double_int (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor)))); + + + /* We can handle only constantly sized accesses that are known to not + be larger than size of array element. */ + if (!TYPE_SIZE_UNIT (type) + || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST + || double_int_cmp (elt_size, + tree_to_double_int (TYPE_SIZE_UNIT (type)), 0) < 0) + return NULL_TREE; + + /* Compute the array index we look for. */ + access_index = double_int_udiv (uhwi_to_double_int (offset / BITS_PER_UNIT), + elt_size, TRUNC_DIV_EXPR); + access_index = double_int_add (access_index, low_bound); + + /* And offset within the access. */ + inner_offset = offset % (double_int_to_uhwi (elt_size) * BITS_PER_UNIT); + + /* See if the array field is large enough to span whole access. We do not + care to fold accesses spanning multiple array indexes. */ + if (inner_offset + size > double_int_to_uhwi (elt_size) * BITS_PER_UNIT) + return NULL_TREE; + + index = double_int_sub (low_bound, double_int_one); + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval) + { + /* Array constructor might explicitely set index, or specify range + or leave index NULL meaning that it is next index after previous + one. */ + if (cfield) + { + if (TREE_CODE (cfield) == INTEGER_CST) + max_index = index = tree_to_double_int (cfield); + else + { + gcc_assert (TREE_CODE (cfield) == RANGE_EXPR); + index = tree_to_double_int (TREE_OPERAND (cfield, 0)); + max_index = tree_to_double_int (TREE_OPERAND (cfield, 1)); + } + } + else + max_index = index = double_int_add (index, double_int_one); + + /* Do we have match? */ + if (double_int_cmp (access_index, index, 1) >= 0 + && double_int_cmp (access_index, max_index, 1) <= 0) + return fold_ctor_reference (type, cval, inner_offset, size); + } + /* When memory is not explicitely mentioned in constructor, + it is 0 (or out of range). */ + return build_zero_cst (type); +} + +/* CTOR is CONSTRUCTOR of an aggregate or vector. + Fold reference of type TYPE and size SIZE to the memory at bit OFFSET. */ + +static tree +fold_nonarray_ctor_reference (tree type, tree ctor, + unsigned HOST_WIDE_INT offset, + unsigned HOST_WIDE_INT size) +{ + unsigned HOST_WIDE_INT cnt; + tree cfield, cval; + + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, + cval) + { + tree byte_offset = DECL_FIELD_OFFSET (cfield); + tree field_offset = DECL_FIELD_BIT_OFFSET (cfield); + tree field_size = DECL_SIZE (cfield); + double_int bitoffset; + double_int byte_offset_cst = tree_to_double_int (byte_offset); + double_int bits_per_unit_cst = uhwi_to_double_int (BITS_PER_UNIT); + double_int bitoffset_end; + + /* Variable sized objects in static constructors makes no sense, + but field_size can be NULL for flexible array members. */ + gcc_assert (TREE_CODE (field_offset) == INTEGER_CST + && TREE_CODE (byte_offset) == INTEGER_CST + && (field_size != NULL_TREE + ? TREE_CODE (field_size) == INTEGER_CST + : TREE_CODE (TREE_TYPE (cfield)) == ARRAY_TYPE)); + + /* Compute bit offset of the field. */ + bitoffset = double_int_add (tree_to_double_int (field_offset), + double_int_mul (byte_offset_cst, + bits_per_unit_cst)); + /* Compute bit offset where the field ends. */ + if (field_size != NULL_TREE) + bitoffset_end = double_int_add (bitoffset, + tree_to_double_int (field_size)); + else + bitoffset_end = double_int_zero; + + /* Is OFFSET in the range (BITOFFSET, BITOFFSET_END)? */ + if (double_int_cmp (uhwi_to_double_int (offset), bitoffset, 0) >= 0 + && (field_size == NULL_TREE + || double_int_cmp (uhwi_to_double_int (offset), + bitoffset_end, 0) < 0)) + { + double_int access_end = double_int_add (uhwi_to_double_int (offset), + uhwi_to_double_int (size)); + double_int inner_offset = double_int_sub (uhwi_to_double_int (offset), + bitoffset); + /* We do have overlap. Now see if field is large enough to + cover the access. Give up for accesses spanning multiple + fields. */ + if (double_int_cmp (access_end, bitoffset_end, 0) > 0) + return NULL_TREE; + return fold_ctor_reference (type, cval, + double_int_to_uhwi (inner_offset), size); + } + } + /* When memory is not explicitely mentioned in constructor, it is 0. */ + return build_zero_cst (type); +} + +/* CTOR is value initializing memory, fold reference of type TYPE and size SIZE + to the memory at bit OFFSET. */ + +static tree +fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset, + unsigned HOST_WIDE_INT size) +{ + tree ret; + + /* We found the field with exact match. */ + if (useless_type_conversion_p (type, TREE_TYPE (ctor)) + && !offset) + return canonicalize_constructor_val (ctor); + + /* We are at the end of walk, see if we can view convert the + result. */ + if (!AGGREGATE_TYPE_P (TREE_TYPE (ctor)) && !offset + /* VIEW_CONVERT_EXPR is defined only for matching sizes. */ + && operand_equal_p (TYPE_SIZE (type), + TYPE_SIZE (TREE_TYPE (ctor)), 0)) + { + ret = canonicalize_constructor_val (ctor); + ret = fold_unary (VIEW_CONVERT_EXPR, type, ret); + if (ret) + STRIP_NOPS (ret); + return ret; + } + if (TREE_CODE (ctor) == STRING_CST) + return fold_string_cst_ctor_reference (type, ctor, offset, size); + if (TREE_CODE (ctor) == CONSTRUCTOR) + { + + if (TREE_CODE (TREE_TYPE (ctor)) == ARRAY_TYPE) + return fold_array_ctor_reference (type, ctor, offset, size); + else + return fold_nonarray_ctor_reference (type, ctor, offset, size); + } + + return NULL_TREE; +} + +/* Return the tree representing the element referenced by T if T is an + ARRAY_REF or COMPONENT_REF into constant aggregates valuezing SSA + names using VALUEIZE. Return NULL_TREE otherwise. */ + +tree +fold_const_aggregate_ref_1 (tree t, tree (*valueize) (tree)) +{ + tree ctor, idx, base; + HOST_WIDE_INT offset, size, max_size; + tree tem; + + if (TREE_CODE_CLASS (TREE_CODE (t)) == tcc_declaration) + return get_symbol_constant_value (t); + + tem = fold_read_from_constant_string (t); + if (tem) + return tem; + + switch (TREE_CODE (t)) + { + case ARRAY_REF: + case ARRAY_RANGE_REF: + /* Constant indexes are handled well by get_base_constructor. + Only special case variable offsets. + FIXME: This code can't handle nested references with variable indexes + (they will be handled only by iteration of ccp). Perhaps we can bring + get_ref_base_and_extent here and make it use a valueize callback. */ + if (TREE_CODE (TREE_OPERAND (t, 1)) == SSA_NAME + && valueize + && (idx = (*valueize) (TREE_OPERAND (t, 1))) + && host_integerp (idx, 0)) + { + tree low_bound, unit_size; + + /* If the resulting bit-offset is constant, track it. */ + if ((low_bound = array_ref_low_bound (t), + host_integerp (low_bound, 0)) + && (unit_size = array_ref_element_size (t), + host_integerp (unit_size, 1))) + { + offset = TREE_INT_CST_LOW (idx); + offset -= TREE_INT_CST_LOW (low_bound); + offset *= TREE_INT_CST_LOW (unit_size); + offset *= BITS_PER_UNIT; + + base = TREE_OPERAND (t, 0); + ctor = get_base_constructor (base, &offset, valueize); + /* Empty constructor. Always fold to 0. */ + if (ctor == error_mark_node) + return build_zero_cst (TREE_TYPE (t)); + /* Out of bound array access. Value is undefined, + but don't fold. */ + if (offset < 0) + return NULL_TREE; + /* We can not determine ctor. */ + if (!ctor) + return NULL_TREE; + return fold_ctor_reference (TREE_TYPE (t), ctor, offset, + TREE_INT_CST_LOW (unit_size) + * BITS_PER_UNIT); + } + } + /* Fallthru. */ + + case COMPONENT_REF: + case BIT_FIELD_REF: + case TARGET_MEM_REF: + case MEM_REF: + base = get_ref_base_and_extent (t, &offset, &size, &max_size); + ctor = get_base_constructor (base, &offset, valueize); + + /* Empty constructor. Always fold to 0. */ + if (ctor == error_mark_node) + return build_zero_cst (TREE_TYPE (t)); + /* We do not know precise address. */ + if (max_size == -1 || max_size != size) + return NULL_TREE; + /* We can not determine ctor. */ + if (!ctor) + return NULL_TREE; + + /* Out of bound array access. Value is undefined, but don't fold. */ + if (offset < 0) + return NULL_TREE; + + return fold_ctor_reference (TREE_TYPE (t), ctor, offset, size); + + case REALPART_EXPR: + case IMAGPART_EXPR: + { + tree c = fold_const_aggregate_ref_1 (TREE_OPERAND (t, 0), valueize); + if (c && TREE_CODE (c) == COMPLEX_CST) + return fold_build1_loc (EXPR_LOCATION (t), + TREE_CODE (t), TREE_TYPE (t), c); + break; + } + + default: + break; + } + + return NULL_TREE; +} + +tree +fold_const_aggregate_ref (tree t) +{ + return fold_const_aggregate_ref_1 (t, NULL); +} diff --git a/gcc/gimple-fold.h b/gcc/gimple-fold.h new file mode 100644 index 00000000000..793d68a8538 --- /dev/null +++ b/gcc/gimple-fold.h @@ -0,0 +1,33 @@ +/* Gimple folding definitions. + + Copyright 2011 Free Software Foundation, Inc. + Contributed by Richard Guenther + +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_FOLD_H +#define GCC_GIMPLE_FOLD_H + +#include "coretypes.h" + +tree fold_const_aggregate_ref_1 (tree, tree (*) (tree)); +tree fold_const_aggregate_ref (tree); + +tree gimple_fold_stmt_to_constant_1 (gimple, tree (*) (tree)); +tree gimple_fold_stmt_to_constant (gimple, tree (*) (tree)); + +#endif /* GCC_GIMPLE_FOLD_H */ diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c index 3b26f61b1fb..1dde723e3da 100644 --- a/gcc/ipa-split.c +++ b/gcc/ipa-split.c @@ -169,8 +169,9 @@ static void dump_split_point (FILE * file, struct split_point *current) { fprintf (file, - "Split point at BB %i header time:%i header size: %i" - " split time: %i split size: %i\n bbs: ", + "Split point at BB %i\n" + " header time: %i header size: %i\n" + " split time: %i split size: %i\n bbs: ", current->entry_bb->index, current->header_time, current->header_size, current->split_time, current->split_size); dump_bitmap (file, current->split_bbs); @@ -1036,12 +1037,13 @@ split_function (struct split_point *split_point) /* If RETURN_BB has virtual operand PHIs, they must be removed and the virtual operand marked for renaming as we change the CFG in a way that - tree-inline is not able to compensate for. + tree-inline is not able to compensate for. Note this can happen whether or not we have a return value. If we have a return value, then RETURN_BB may have PHIs for real operands too. */ if (return_bb != EXIT_BLOCK_PTR) { + bool phi_p = false; for (gsi = gsi_start_phis (return_bb); !gsi_end_p (gsi);) { gimple stmt = gsi_stmt (gsi); @@ -1052,7 +1054,28 @@ split_function (struct split_point *split_point) } mark_virtual_phi_result_for_renaming (stmt); remove_phi_node (&gsi, true); + phi_p = true; } + /* In reality we have to rename the reaching definition of the + virtual operand at return_bb as we will eventually release it + when we remove the code region we outlined. + So we have to rename all immediate virtual uses of that region + if we didn't see a PHI definition yet. */ + /* ??? In real reality we want to set the reaching vdef of the + entry of the SESE region as the vuse of the call and the reaching + vdef of the exit of the SESE region as the vdef of the call. */ + if (!phi_p) + for (gsi = gsi_start_bb (return_bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple stmt = gsi_stmt (gsi); + if (gimple_vuse (stmt)) + { + gimple_set_vuse (stmt, NULL_TREE); + update_stmt (stmt); + } + if (gimple_vdef (stmt)) + break; + } } /* Now create the actual clone. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 87a8da95e51..8bda6a47eec 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2011-03-24 Richard Guenther + + PR tree-optimization/46562 + * c-c++-common/pr46562-2.c: New testcase. + * c-c++-common/pr46562.c: Likewise. + 2011-03-24 Ira Rosen * gcc.dg/vect/vect-cselim-1.c: New test. diff --git a/gcc/testsuite/c-c++-common/pr46562-2.c b/gcc/testsuite/c-c++-common/pr46562-2.c new file mode 100644 index 00000000000..5415860c7a7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr46562-2.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fno-tree-ccp -fno-tree-forwprop -fdump-tree-fre" } */ + +static const int a[4] = {}; +int foo(void) +{ + int i = 1; + const int *p = &a[i]; + return *p; +} + +/* { dg-final { scan-tree-dump "= 0;" "fre" } } */ +/* { dg-final { cleanup-tree-dump "fre" } } */ diff --git a/gcc/testsuite/c-c++-common/pr46562.c b/gcc/testsuite/c-c++-common/pr46562.c new file mode 100644 index 00000000000..30659070f01 --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr46562.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-ccp1" } */ + +static const int a[4] = {}; +int foo(void) +{ + int i = 1; + const int *p = &a[i]; + return *p; +} + +/* { dg-final { scan-tree-dump "return 0;" "ccp1" } } */ +/* { dg-final { cleanup-tree-dump "ccp1" } } */ diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c index 8e1e9b05a60..9766f00ddf7 100644 --- a/gcc/tree-dfa.c +++ b/gcc/tree-dfa.c @@ -963,110 +963,7 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset, tree get_addr_base_and_unit_offset (tree exp, HOST_WIDE_INT *poffset) { - HOST_WIDE_INT byte_offset = 0; - - /* Compute cumulative byte-offset for nested component-refs and array-refs, - and find the ultimate containing object. */ - while (1) - { - switch (TREE_CODE (exp)) - { - case BIT_FIELD_REF: - return NULL_TREE; - - case COMPONENT_REF: - { - tree field = TREE_OPERAND (exp, 1); - tree this_offset = component_ref_field_offset (exp); - HOST_WIDE_INT hthis_offset; - - if (!this_offset - || TREE_CODE (this_offset) != INTEGER_CST - || (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)) - % BITS_PER_UNIT)) - return NULL_TREE; - - hthis_offset = TREE_INT_CST_LOW (this_offset); - hthis_offset += (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)) - / BITS_PER_UNIT); - byte_offset += hthis_offset; - } - break; - - case ARRAY_REF: - case ARRAY_RANGE_REF: - { - tree index = TREE_OPERAND (exp, 1); - tree low_bound, unit_size; - - /* If the resulting bit-offset is constant, track it. */ - if (TREE_CODE (index) == INTEGER_CST - && (low_bound = array_ref_low_bound (exp), - TREE_CODE (low_bound) == INTEGER_CST) - && (unit_size = array_ref_element_size (exp), - TREE_CODE (unit_size) == INTEGER_CST)) - { - HOST_WIDE_INT hindex = TREE_INT_CST_LOW (index); - - hindex -= TREE_INT_CST_LOW (low_bound); - hindex *= TREE_INT_CST_LOW (unit_size); - byte_offset += hindex; - } - else - return NULL_TREE; - } - break; - - case REALPART_EXPR: - break; - - case IMAGPART_EXPR: - byte_offset += TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (exp))); - break; - - case VIEW_CONVERT_EXPR: - break; - - case MEM_REF: - /* Hand back the decl for MEM[&decl, off]. */ - if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR) - { - if (!integer_zerop (TREE_OPERAND (exp, 1))) - { - double_int off = mem_ref_offset (exp); - gcc_assert (off.high == -1 || off.high == 0); - byte_offset += double_int_to_shwi (off); - } - exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); - } - goto done; - - case TARGET_MEM_REF: - /* Hand back the decl for MEM[&decl, off]. */ - if (TREE_CODE (TMR_BASE (exp)) == ADDR_EXPR) - { - if (TMR_INDEX (exp) || TMR_INDEX2 (exp)) - return NULL_TREE; - if (!integer_zerop (TMR_OFFSET (exp))) - { - double_int off = mem_ref_offset (exp); - gcc_assert (off.high == -1 || off.high == 0); - byte_offset += double_int_to_shwi (off); - } - exp = TREE_OPERAND (TMR_BASE (exp), 0); - } - goto done; - - default: - goto done; - } - - exp = TREE_OPERAND (exp, 0); - } -done: - - *poffset = byte_offset; - return exp; + return get_addr_base_and_unit_offset_1 (exp, poffset, NULL); } /* Returns true if STMT references an SSA_NAME that has diff --git a/gcc/tree-flow-inline.h b/gcc/tree-flow-inline.h index 86566101e39..dcbe355e926 100644 --- a/gcc/tree-flow-inline.h +++ b/gcc/tree-flow-inline.h @@ -1227,4 +1227,139 @@ make_ssa_name (tree var, gimple stmt) return make_ssa_name_fn (cfun, var, stmt); } +/* Returns the base object and a constant BITS_PER_UNIT offset in *POFFSET that + denotes the starting address of the memory access EXP. + Returns NULL_TREE if the offset is not constant or any component + is not BITS_PER_UNIT-aligned. + VALUEIZE if non-NULL is used to valueize SSA names. It should return + its argument or a constant if the argument is known to be constant. */ + +static inline tree +get_addr_base_and_unit_offset_1 (tree exp, HOST_WIDE_INT *poffset, + tree (*valueize) (tree)) +{ + HOST_WIDE_INT byte_offset = 0; + + /* Compute cumulative byte-offset for nested component-refs and array-refs, + and find the ultimate containing object. */ + while (1) + { + switch (TREE_CODE (exp)) + { + case BIT_FIELD_REF: + return NULL_TREE; + + case COMPONENT_REF: + { + tree field = TREE_OPERAND (exp, 1); + tree this_offset = component_ref_field_offset (exp); + HOST_WIDE_INT hthis_offset; + + if (!this_offset + || TREE_CODE (this_offset) != INTEGER_CST + || (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)) + % BITS_PER_UNIT)) + return NULL_TREE; + + hthis_offset = TREE_INT_CST_LOW (this_offset); + hthis_offset += (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)) + / BITS_PER_UNIT); + byte_offset += hthis_offset; + } + break; + + case ARRAY_REF: + case ARRAY_RANGE_REF: + { + tree index = TREE_OPERAND (exp, 1); + tree low_bound, unit_size; + + if (valueize + && TREE_CODE (index) == SSA_NAME) + index = (*valueize) (index); + + /* If the resulting bit-offset is constant, track it. */ + if (TREE_CODE (index) == INTEGER_CST + && (low_bound = array_ref_low_bound (exp), + TREE_CODE (low_bound) == INTEGER_CST) + && (unit_size = array_ref_element_size (exp), + TREE_CODE (unit_size) == INTEGER_CST)) + { + HOST_WIDE_INT hindex = TREE_INT_CST_LOW (index); + + hindex -= TREE_INT_CST_LOW (low_bound); + hindex *= TREE_INT_CST_LOW (unit_size); + byte_offset += hindex; + } + else + return NULL_TREE; + } + break; + + case REALPART_EXPR: + break; + + case IMAGPART_EXPR: + byte_offset += TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (exp))); + break; + + case VIEW_CONVERT_EXPR: + break; + + case MEM_REF: + { + tree base = TREE_OPERAND (exp, 0); + if (valueize + && TREE_CODE (base) == SSA_NAME) + base = (*valueize) (base); + + /* Hand back the decl for MEM[&decl, off]. */ + if (TREE_CODE (base) == ADDR_EXPR) + { + if (!integer_zerop (TREE_OPERAND (exp, 1))) + { + double_int off = mem_ref_offset (exp); + gcc_assert (off.high == -1 || off.high == 0); + byte_offset += double_int_to_shwi (off); + } + exp = TREE_OPERAND (base, 0); + } + goto done; + } + + case TARGET_MEM_REF: + { + tree base = TREE_OPERAND (exp, 0); + if (valueize + && TREE_CODE (base) == SSA_NAME) + base = (*valueize) (base); + + /* Hand back the decl for MEM[&decl, off]. */ + if (TREE_CODE (base) == ADDR_EXPR) + { + if (TMR_INDEX (exp) || TMR_INDEX2 (exp)) + return NULL_TREE; + if (!integer_zerop (TMR_OFFSET (exp))) + { + double_int off = mem_ref_offset (exp); + gcc_assert (off.high == -1 || off.high == 0); + byte_offset += double_int_to_shwi (off); + } + exp = TREE_OPERAND (base, 0); + } + goto done; + } + + default: + goto done; + } + + exp = TREE_OPERAND (exp, 0); + } +done: + + *poffset = byte_offset; + return exp; +} + #endif /* _TREE_FLOW_INLINE_H */ diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 14c8827d1c5..c8ea3acdcd2 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -594,6 +594,7 @@ extern void ssanames_print_statistics (void); /* In tree-ssa-ccp.c */ tree fold_const_aggregate_ref (tree); +tree gimple_fold_stmt_to_constant (gimple, tree (*)(tree)); /* In tree-ssa-dom.c */ extern void dump_dominator_optimization_stats (FILE *); diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 4fc4316bb1c..059274a3513 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -132,6 +132,7 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "diagnostic-core.h" #include "dbgcnt.h" +#include "gimple-fold.h" /* Possible lattice values. */ @@ -167,9 +168,6 @@ static prop_value_t *const_val; static void canonicalize_float_value (prop_value_t *); static bool ccp_fold_stmt (gimple_stmt_iterator *); -static tree fold_ctor_reference (tree type, tree ctor, - unsigned HOST_WIDE_INT offset, - unsigned HOST_WIDE_INT size); /* Dump constant propagation value VAL to file OUTF prefixed by PREFIX. */ @@ -1098,220 +1096,6 @@ ccp_fold (gimple stmt) location_t loc = gimple_location (stmt); switch (gimple_code (stmt)) { - case GIMPLE_ASSIGN: - { - enum tree_code subcode = gimple_assign_rhs_code (stmt); - - switch (get_gimple_rhs_class (subcode)) - { - case GIMPLE_SINGLE_RHS: - { - tree rhs = gimple_assign_rhs1 (stmt); - enum tree_code_class kind = TREE_CODE_CLASS (subcode); - - if (TREE_CODE (rhs) == SSA_NAME) - { - /* If the RHS is an SSA_NAME, return its known constant value, - if any. */ - return get_constant_value (rhs); - } - /* Handle propagating invariant addresses into address operations. - The folding we do here matches that in tree-ssa-forwprop.c. */ - else if (TREE_CODE (rhs) == ADDR_EXPR) - { - tree *base; - base = &TREE_OPERAND (rhs, 0); - while (handled_component_p (*base)) - base = &TREE_OPERAND (*base, 0); - if (TREE_CODE (*base) == MEM_REF - && TREE_CODE (TREE_OPERAND (*base, 0)) == SSA_NAME) - { - tree val = get_constant_value (TREE_OPERAND (*base, 0)); - if (val - && TREE_CODE (val) == ADDR_EXPR) - { - tree ret, save = *base; - tree new_base; - new_base = fold_build2 (MEM_REF, TREE_TYPE (*base), - unshare_expr (val), - TREE_OPERAND (*base, 1)); - /* We need to return a new tree, not modify the IL - or share parts of it. So play some tricks to - avoid manually building it. */ - *base = new_base; - ret = unshare_expr (rhs); - recompute_tree_invariant_for_addr_expr (ret); - *base = save; - return ret; - } - } - } - else if (TREE_CODE (rhs) == CONSTRUCTOR - && TREE_CODE (TREE_TYPE (rhs)) == VECTOR_TYPE - && (CONSTRUCTOR_NELTS (rhs) - == TYPE_VECTOR_SUBPARTS (TREE_TYPE (rhs)))) - { - unsigned i; - tree val, list; - - list = NULL_TREE; - FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (rhs), i, val) - { - val = valueize_op (val); - if (TREE_CODE (val) == INTEGER_CST - || TREE_CODE (val) == REAL_CST - || TREE_CODE (val) == FIXED_CST) - list = tree_cons (NULL_TREE, val, list); - else - return NULL_TREE; - } - - return build_vector (TREE_TYPE (rhs), nreverse (list)); - } - - if (kind == tcc_reference) - { - if ((TREE_CODE (rhs) == VIEW_CONVERT_EXPR - || TREE_CODE (rhs) == REALPART_EXPR - || TREE_CODE (rhs) == IMAGPART_EXPR) - && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME) - { - tree val = get_constant_value (TREE_OPERAND (rhs, 0)); - if (val) - return fold_unary_loc (EXPR_LOCATION (rhs), - TREE_CODE (rhs), - TREE_TYPE (rhs), val); - } - else if (TREE_CODE (rhs) == BIT_FIELD_REF - && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME) - { - tree val = get_constant_value (TREE_OPERAND (rhs, 0)); - if (val) - return fold_ternary_loc (EXPR_LOCATION (rhs), - TREE_CODE (rhs), - TREE_TYPE (rhs), val, - TREE_OPERAND (rhs, 1), - TREE_OPERAND (rhs, 2)); - } - else if (TREE_CODE (rhs) == MEM_REF - && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME) - { - tree val = get_constant_value (TREE_OPERAND (rhs, 0)); - if (val - && TREE_CODE (val) == ADDR_EXPR) - { - tree tem = fold_build2 (MEM_REF, TREE_TYPE (rhs), - unshare_expr (val), - TREE_OPERAND (rhs, 1)); - if (tem) - rhs = tem; - } - } - return fold_const_aggregate_ref (rhs); - } - else if (kind == tcc_declaration) - return get_symbol_constant_value (rhs); - return rhs; - } - - case GIMPLE_UNARY_RHS: - { - /* Handle unary operators that can appear in GIMPLE form. - Note that we know the single operand must be a constant, - so this should almost always return a simplified RHS. */ - tree lhs = gimple_assign_lhs (stmt); - tree op0 = valueize_op (gimple_assign_rhs1 (stmt)); - - /* Conversions are useless for CCP purposes if they are - value-preserving. Thus the restrictions that - useless_type_conversion_p places for pointer type conversions - do not apply here. Substitution later will only substitute to - allowed places. */ - if (CONVERT_EXPR_CODE_P (subcode) - && POINTER_TYPE_P (TREE_TYPE (lhs)) - && POINTER_TYPE_P (TREE_TYPE (op0))) - { - tree tem; - /* Try to re-construct array references on-the-fly. */ - if (!useless_type_conversion_p (TREE_TYPE (lhs), - TREE_TYPE (op0)) - && ((tem = maybe_fold_offset_to_address - (loc, - op0, integer_zero_node, TREE_TYPE (lhs))) - != NULL_TREE)) - return tem; - return op0; - } - - return - fold_unary_ignore_overflow_loc (loc, subcode, - gimple_expr_type (stmt), op0); - } - - case GIMPLE_BINARY_RHS: - { - /* Handle binary operators that can appear in GIMPLE form. */ - tree op0 = valueize_op (gimple_assign_rhs1 (stmt)); - tree op1 = valueize_op (gimple_assign_rhs2 (stmt)); - - /* Translate &x + CST into an invariant form suitable for - further propagation. */ - if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR - && TREE_CODE (op0) == ADDR_EXPR - && TREE_CODE (op1) == INTEGER_CST) - { - tree off = fold_convert (ptr_type_node, op1); - return build_fold_addr_expr - (fold_build2 (MEM_REF, - TREE_TYPE (TREE_TYPE (op0)), - unshare_expr (op0), off)); - } - - return fold_binary_loc (loc, subcode, - gimple_expr_type (stmt), op0, op1); - } - - case GIMPLE_TERNARY_RHS: - { - /* Handle ternary operators that can appear in GIMPLE form. */ - tree op0 = valueize_op (gimple_assign_rhs1 (stmt)); - tree op1 = valueize_op (gimple_assign_rhs2 (stmt)); - tree op2 = valueize_op (gimple_assign_rhs3 (stmt)); - - return fold_ternary_loc (loc, subcode, - gimple_expr_type (stmt), op0, op1, op2); - } - - default: - gcc_unreachable (); - } - } - break; - - case GIMPLE_CALL: - { - tree fn = valueize_op (gimple_call_fn (stmt)); - if (TREE_CODE (fn) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL - && DECL_BUILT_IN (TREE_OPERAND (fn, 0))) - { - tree *args = XALLOCAVEC (tree, gimple_call_num_args (stmt)); - tree call, retval; - unsigned i; - for (i = 0; i < gimple_call_num_args (stmt); ++i) - args[i] = valueize_op (gimple_call_arg (stmt, i)); - call = build_call_array_loc (loc, - gimple_call_return_type (stmt), - fn, gimple_call_num_args (stmt), args); - retval = fold_call_expr (EXPR_LOCATION (call), call, false); - if (retval) - /* fold_call_expr wraps the result inside a NOP_EXPR. */ - STRIP_NOPS (retval); - return retval; - } - return NULL_TREE; - } - case GIMPLE_COND: { /* Handle comparison operators that can appear in GIMPLE form. */ @@ -1327,395 +1111,13 @@ ccp_fold (gimple stmt) return valueize_op (gimple_switch_index (stmt)); } - default: - gcc_unreachable (); - } -} - -/* See if we can find constructor defining value of BASE. - When we know the consructor with constant offset (such as - base is array[40] and we do know constructor of array), then - BIT_OFFSET is adjusted accordingly. - - As a special case, return error_mark_node when constructor - is not explicitly available, but it is known to be zero - such as 'static const int a;'. */ -static tree -get_base_constructor (tree base, HOST_WIDE_INT *bit_offset) -{ - HOST_WIDE_INT bit_offset2, size, max_size; - if (TREE_CODE (base) == MEM_REF) - { - if (!integer_zerop (TREE_OPERAND (base, 1))) - { - if (!host_integerp (TREE_OPERAND (base, 1), 0)) - return NULL_TREE; - *bit_offset += (mem_ref_offset (base).low - * BITS_PER_UNIT); - } - - base = get_constant_value (TREE_OPERAND (base, 0)); - if (!base || TREE_CODE (base) != ADDR_EXPR) - return NULL_TREE; - base = TREE_OPERAND (base, 0); - } - - /* Get a CONSTRUCTOR. If BASE is a VAR_DECL, get its - DECL_INITIAL. If BASE is a nested reference into another - ARRAY_REF or COMPONENT_REF, make a recursive call to resolve - the inner reference. */ - switch (TREE_CODE (base)) - { - case VAR_DECL: - if (!const_value_known_p (base)) - return NULL_TREE; - - /* Fallthru. */ - case CONST_DECL: - if (!DECL_INITIAL (base) - && (TREE_STATIC (base) || DECL_EXTERNAL (base))) - return error_mark_node; - return DECL_INITIAL (base); - - case ARRAY_REF: - case COMPONENT_REF: - base = get_ref_base_and_extent (base, &bit_offset2, &size, &max_size); - if (max_size == -1 || size != max_size) - return NULL_TREE; - *bit_offset += bit_offset2; - return get_base_constructor (base, bit_offset); - - case STRING_CST: - case CONSTRUCTOR: - return base; - - default: - return NULL_TREE; - } -} - -/* CTOR is STRING_CST. Fold reference of type TYPE and size SIZE - to the memory at bit OFFSET. - - We do only simple job of folding byte accesses. */ - -static tree -fold_string_cst_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset, - unsigned HOST_WIDE_INT size) -{ - if (INTEGRAL_TYPE_P (type) - && (TYPE_MODE (type) - == TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) - && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) - == MODE_INT) - && GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) == 1 - && size == BITS_PER_UNIT - && !(offset % BITS_PER_UNIT)) - { - offset /= BITS_PER_UNIT; - if (offset < (unsigned HOST_WIDE_INT) TREE_STRING_LENGTH (ctor)) - return build_int_cst_type (type, (TREE_STRING_POINTER (ctor) - [offset])); - /* Folding - const char a[20]="hello"; - return a[10]; - - might lead to offset greater than string length. In this case we - know value is either initialized to 0 or out of bounds. Return 0 - in both cases. */ - return build_zero_cst (type); - } - return NULL_TREE; -} - -/* CTOR is CONSTRUCTOR of an array type. Fold reference of type TYPE and size - SIZE to the memory at bit OFFSET. */ - -static tree -fold_array_ctor_reference (tree type, tree ctor, - unsigned HOST_WIDE_INT offset, - unsigned HOST_WIDE_INT size) -{ - unsigned HOST_WIDE_INT cnt; - tree cfield, cval; - double_int low_bound, elt_size; - double_int index, max_index; - double_int access_index; - tree domain_type = TYPE_DOMAIN (TREE_TYPE (ctor)); - HOST_WIDE_INT inner_offset; - - /* Compute low bound and elt size. */ - if (domain_type && TYPE_MIN_VALUE (domain_type)) - { - /* Static constructors for variably sized objects makes no sense. */ - gcc_assert (TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST); - low_bound = tree_to_double_int (TYPE_MIN_VALUE (domain_type)); - } - else - low_bound = double_int_zero; - /* Static constructors for variably sized objects makes no sense. */ - gcc_assert (TREE_CODE(TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor)))) - == INTEGER_CST); - elt_size = - tree_to_double_int (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor)))); - - - /* We can handle only constantly sized accesses that are known to not - be larger than size of array element. */ - if (!TYPE_SIZE_UNIT (type) - || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST - || double_int_cmp (elt_size, - tree_to_double_int (TYPE_SIZE_UNIT (type)), 0) < 0) - return NULL_TREE; - - /* Compute the array index we look for. */ - access_index = double_int_udiv (uhwi_to_double_int (offset / BITS_PER_UNIT), - elt_size, TRUNC_DIV_EXPR); - access_index = double_int_add (access_index, low_bound); - - /* And offset within the access. */ - inner_offset = offset % (double_int_to_uhwi (elt_size) * BITS_PER_UNIT); - - /* See if the array field is large enough to span whole access. We do not - care to fold accesses spanning multiple array indexes. */ - if (inner_offset + size > double_int_to_uhwi (elt_size) * BITS_PER_UNIT) - return NULL_TREE; - - index = double_int_sub (low_bound, double_int_one); - FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval) - { - /* Array constructor might explicitely set index, or specify range - or leave index NULL meaning that it is next index after previous - one. */ - if (cfield) - { - if (TREE_CODE (cfield) == INTEGER_CST) - max_index = index = tree_to_double_int (cfield); - else - { - gcc_assert (TREE_CODE (cfield) == RANGE_EXPR); - index = tree_to_double_int (TREE_OPERAND (cfield, 0)); - max_index = tree_to_double_int (TREE_OPERAND (cfield, 1)); - } - } - else - max_index = index = double_int_add (index, double_int_one); - - /* Do we have match? */ - if (double_int_cmp (access_index, index, 1) >= 0 - && double_int_cmp (access_index, max_index, 1) <= 0) - return fold_ctor_reference (type, cval, inner_offset, size); - } - /* When memory is not explicitely mentioned in constructor, - it is 0 (or out of range). */ - return build_zero_cst (type); -} - -/* CTOR is CONSTRUCTOR of an aggregate or vector. - Fold reference of type TYPE and size SIZE to the memory at bit OFFSET. */ - -static tree -fold_nonarray_ctor_reference (tree type, tree ctor, - unsigned HOST_WIDE_INT offset, - unsigned HOST_WIDE_INT size) -{ - unsigned HOST_WIDE_INT cnt; - tree cfield, cval; - - FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, - cval) - { - tree byte_offset = DECL_FIELD_OFFSET (cfield); - tree field_offset = DECL_FIELD_BIT_OFFSET (cfield); - tree field_size = DECL_SIZE (cfield); - double_int bitoffset; - double_int byte_offset_cst = tree_to_double_int (byte_offset); - double_int bits_per_unit_cst = uhwi_to_double_int (BITS_PER_UNIT); - double_int bitoffset_end; - - /* Variable sized objects in static constructors makes no sense, - but field_size can be NULL for flexible array members. */ - gcc_assert (TREE_CODE (field_offset) == INTEGER_CST - && TREE_CODE (byte_offset) == INTEGER_CST - && (field_size != NULL_TREE - ? TREE_CODE (field_size) == INTEGER_CST - : TREE_CODE (TREE_TYPE (cfield)) == ARRAY_TYPE)); - - /* Compute bit offset of the field. */ - bitoffset = double_int_add (tree_to_double_int (field_offset), - double_int_mul (byte_offset_cst, - bits_per_unit_cst)); - /* Compute bit offset where the field ends. */ - if (field_size != NULL_TREE) - bitoffset_end = double_int_add (bitoffset, - tree_to_double_int (field_size)); - else - bitoffset_end = double_int_zero; - - /* Is OFFSET in the range (BITOFFSET, BITOFFSET_END)? */ - if (double_int_cmp (uhwi_to_double_int (offset), bitoffset, 0) >= 0 - && (field_size == NULL_TREE - || double_int_cmp (uhwi_to_double_int (offset), - bitoffset_end, 0) < 0)) - { - double_int access_end = double_int_add (uhwi_to_double_int (offset), - uhwi_to_double_int (size)); - double_int inner_offset = double_int_sub (uhwi_to_double_int (offset), - bitoffset); - /* We do have overlap. Now see if field is large enough to - cover the access. Give up for accesses spanning multiple - fields. */ - if (double_int_cmp (access_end, bitoffset_end, 0) > 0) - return NULL_TREE; - return fold_ctor_reference (type, cval, - double_int_to_uhwi (inner_offset), size); - } - } - /* When memory is not explicitely mentioned in constructor, it is 0. */ - return build_zero_cst (type); -} - -/* CTOR is value initializing memory, fold reference of type TYPE and size SIZE - to the memory at bit OFFSET. */ - -static tree -fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset, - unsigned HOST_WIDE_INT size) -{ - tree ret; - - /* We found the field with exact match. */ - if (useless_type_conversion_p (type, TREE_TYPE (ctor)) - && !offset) - return canonicalize_constructor_val (ctor); - - /* We are at the end of walk, see if we can view convert the - result. */ - if (!AGGREGATE_TYPE_P (TREE_TYPE (ctor)) && !offset - /* VIEW_CONVERT_EXPR is defined only for matching sizes. */ - && operand_equal_p (TYPE_SIZE (type), - TYPE_SIZE (TREE_TYPE (ctor)), 0)) - { - ret = canonicalize_constructor_val (ctor); - ret = fold_unary (VIEW_CONVERT_EXPR, type, ret); - if (ret) - STRIP_NOPS (ret); - return ret; - } - if (TREE_CODE (ctor) == STRING_CST) - return fold_string_cst_ctor_reference (type, ctor, offset, size); - if (TREE_CODE (ctor) == CONSTRUCTOR) - { - - if (TREE_CODE (TREE_TYPE (ctor)) == ARRAY_TYPE) - return fold_array_ctor_reference (type, ctor, offset, size); - else - return fold_nonarray_ctor_reference (type, ctor, offset, size); - } - - return NULL_TREE; -} - -/* Return the tree representing the element referenced by T if T is an - ARRAY_REF or COMPONENT_REF into constant aggregates. Return - NULL_TREE otherwise. */ - -tree -fold_const_aggregate_ref (tree t) -{ - tree ctor, idx, base; - HOST_WIDE_INT offset, size, max_size; - tree tem; - - if (TREE_CODE_CLASS (TREE_CODE (t)) == tcc_declaration) - return get_symbol_constant_value (t); - - tem = fold_read_from_constant_string (t); - if (tem) - return tem; - - switch (TREE_CODE (t)) - { - case ARRAY_REF: - case ARRAY_RANGE_REF: - /* Constant indexes are handled well by get_base_constructor. - Only special case variable offsets. - FIXME: This code can't handle nested references with variable indexes - (they will be handled only by iteration of ccp). Perhaps we can bring - get_ref_base_and_extent here and make it use get_constant_value. */ - if (TREE_CODE (TREE_OPERAND (t, 1)) == SSA_NAME - && (idx = get_constant_value (TREE_OPERAND (t, 1))) - && host_integerp (idx, 0)) - { - tree low_bound, unit_size; - - /* If the resulting bit-offset is constant, track it. */ - if ((low_bound = array_ref_low_bound (t), - host_integerp (low_bound, 0)) - && (unit_size = array_ref_element_size (t), - host_integerp (unit_size, 1))) - { - offset = TREE_INT_CST_LOW (idx); - offset -= TREE_INT_CST_LOW (low_bound); - offset *= TREE_INT_CST_LOW (unit_size); - offset *= BITS_PER_UNIT; - - base = TREE_OPERAND (t, 0); - ctor = get_base_constructor (base, &offset); - /* Empty constructor. Always fold to 0. */ - if (ctor == error_mark_node) - return build_zero_cst (TREE_TYPE (t)); - /* Out of bound array access. Value is undefined, but don't fold. */ - if (offset < 0) - return NULL_TREE; - /* We can not determine ctor. */ - if (!ctor) - return NULL_TREE; - return fold_ctor_reference (TREE_TYPE (t), ctor, offset, - TREE_INT_CST_LOW (unit_size) - * BITS_PER_UNIT); - } - } - /* Fallthru. */ - - case COMPONENT_REF: - case BIT_FIELD_REF: - case TARGET_MEM_REF: - case MEM_REF: - base = get_ref_base_and_extent (t, &offset, &size, &max_size); - ctor = get_base_constructor (base, &offset); - - /* Empty constructor. Always fold to 0. */ - if (ctor == error_mark_node) - return build_zero_cst (TREE_TYPE (t)); - /* We do not know precise address. */ - if (max_size == -1 || max_size != size) - return NULL_TREE; - /* We can not determine ctor. */ - if (!ctor) - return NULL_TREE; - - /* Out of bound array access. Value is undefined, but don't fold. */ - if (offset < 0) - return NULL_TREE; - - return fold_ctor_reference (TREE_TYPE (t), ctor, offset, size); - - case REALPART_EXPR: - case IMAGPART_EXPR: - { - tree c = fold_const_aggregate_ref (TREE_OPERAND (t, 0)); - if (c && TREE_CODE (c) == COMPLEX_CST) - return fold_build1_loc (EXPR_LOCATION (t), - TREE_CODE (t), TREE_TYPE (t), c); - break; - } + case GIMPLE_ASSIGN: + case GIMPLE_CALL: + return gimple_fold_stmt_to_constant_1 (stmt, valueize_op); default: - break; + gcc_unreachable (); } - - return NULL_TREE; } /* Apply the operation CODE in type TYPE to the value, mask pair diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index f2466432f89..0a6fa9455de 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -4380,9 +4380,12 @@ eliminate (void) if (is_gimple_call (stmt) && TREE_CODE (gimple_call_fn (stmt)) == SSA_NAME) { - tree fn = VN_INFO (gimple_call_fn (stmt))->valnum; + tree orig_fn = gimple_call_fn (stmt); + tree fn = VN_INFO (orig_fn)->valnum; if (TREE_CODE (fn) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL) + && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL + && useless_type_conversion_p (TREE_TYPE (orig_fn), + TREE_TYPE (fn))) { bool can_make_abnormal_goto = stmt_can_make_abnormal_goto (stmt); diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c index a3462430209..29b80ea5780 100644 --- a/gcc/tree-ssa-sccvn.c +++ b/gcc/tree-ssa-sccvn.c @@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see #include "params.h" #include "tree-ssa-propagate.h" #include "tree-ssa-sccvn.h" +#include "gimple-fold.h" /* This algorithm is based on the SCC algorithm presented by Keith Cooper and L. Taylor Simpson in "SCC-Based Value numbering" @@ -2770,6 +2771,16 @@ simplify_binary_expression (gimple stmt) op1 = SSA_VAL (op1); } + /* Pointer plus constant can be represented as invariant address. + Do so to allow further propatation, see also tree forwprop. */ + if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR + && host_integerp (op1, 1) + && TREE_CODE (op0) == ADDR_EXPR + && is_gimple_min_invariant (op0)) + return build_invariant_address (TREE_TYPE (op0), + TREE_OPERAND (op0, 0), + TREE_INT_CST_LOW (op1)); + /* Avoid folding if nothing changed. */ if (op0 == gimple_assign_rhs1 (stmt) && op1 == gimple_assign_rhs2 (stmt)) @@ -2849,6 +2860,19 @@ simplify_unary_expression (gimple stmt) return NULL_TREE; } +/* Valueize NAME if it is an SSA name, otherwise just return it. */ + +static inline tree +vn_valueize (tree name) +{ + if (TREE_CODE (name) == SSA_NAME) + { + tree tem = SSA_VAL (name); + return tem == VN_TOP ? name : tem; + } + return name; +} + /* Try to simplify RHS using equivalences and constant folding. */ static tree @@ -2862,21 +2886,15 @@ try_to_simplify (gimple stmt) && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME) return NULL_TREE; + /* First try constant folding based on our current lattice. */ + tem = gimple_fold_stmt_to_constant (stmt, vn_valueize); + if (tem) + return tem; + + /* If that didn't work try combining multiple statements. */ switch (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt))) { - case tcc_declaration: - tem = get_symbol_constant_value (gimple_assign_rhs1 (stmt)); - if (tem) - return tem; - break; - case tcc_reference: - /* Do not do full-blown reference lookup here, but simplify - reads from constant aggregates. */ - tem = fold_const_aggregate_ref (gimple_assign_rhs1 (stmt)); - if (tem) - return tem; - /* Fallthrough for some codes that can operate on registers. */ if (!(TREE_CODE (gimple_assign_rhs1 (stmt)) == REALPART_EXPR || TREE_CODE (gimple_assign_rhs1 (stmt)) == IMAGPART_EXPR @@ -2886,11 +2904,11 @@ try_to_simplify (gimple stmt) into binary ops, but it's debatable whether it is worth it. */ case tcc_unary: return simplify_unary_expression (stmt); - break; + case tcc_comparison: case tcc_binary: return simplify_binary_expression (stmt); - break; + default: break; } diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 42ea9104e12..466c3a0f0da 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-scalar-evolution.h" #include "tree-ssa-propagate.h" #include "tree-chrec.h" +#include "gimple-fold.h" /* Type of value ranges. See value_range_d for a description of these @@ -5614,6 +5615,21 @@ vrp_initialize (void) } } +/* Return the singleton value-range for NAME or NAME. */ + +static inline tree +vrp_valueize (tree name) +{ + if (TREE_CODE (name) == SSA_NAME) + { + value_range_t *vr = get_value_range (name); + if (vr->type == VR_RANGE + && (vr->min == vr->max + || operand_equal_p (vr->min, vr->max, 0))) + return vr->min; + } + return name; +} /* Visit assignment STMT. If it produces an interesting range, record the SSA name in *OUTPUT_P. */ @@ -5637,7 +5653,12 @@ vrp_visit_assignment_or_call (gimple stmt, tree *output_p) { value_range_t new_vr = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }; - if (code == GIMPLE_CALL) + /* Try folding the statement to a constant first. */ + tree tem = gimple_fold_stmt_to_constant (stmt, vrp_valueize); + if (tem && !is_overflow_infinity (tem)) + set_value_range (&new_vr, VR_RANGE, tem, tem, NULL); + /* Then dispatch to value-range extracting functions. */ + else if (code == GIMPLE_CALL) extract_range_basic (&new_vr, stmt); else extract_range_from_assignment (&new_vr, stmt); @@ -6366,7 +6387,6 @@ vrp_visit_stmt (gimple stmt, edge *taken_edge_p, tree *output_p) /* In general, assignments with virtual operands are not useful for deriving ranges, with the obvious exception of calls to builtin functions. */ - if ((is_gimple_call (stmt) && gimple_call_fndecl (stmt) != NULL_TREE && DECL_IS_BUILTIN (gimple_call_fndecl (stmt))) diff --git a/gcc/tree.c b/gcc/tree.c index efa51bde3b1..f9e3f40d5ee 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -4013,6 +4013,20 @@ reference_alias_ptr_type (const_tree t) return build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (base))); } +/* Return an invariant ADDR_EXPR of type TYPE taking the address of BASE + offsetted by OFFSET units. */ + +tree +build_invariant_address (tree type, tree base, HOST_WIDE_INT offset) +{ + tree ref = fold_build2 (MEM_REF, TREE_TYPE (type), + build_fold_addr_expr (base), + build_int_cst (ptr_type_node, offset)); + tree addr = build1 (ADDR_EXPR, type, ref); + recompute_tree_invariant_for_addr_expr (addr); + return addr; +} + /* Similar except don't specify the TREE_TYPE and leave the TREE_SIDE_EFFECTS as 0. It is permissible for arguments to be null, diff --git a/gcc/tree.h b/gcc/tree.h index eb5e4cab96f..454d3287b48 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -5096,6 +5096,7 @@ extern tree build_simple_mem_ref_loc (location_t, tree); build_simple_mem_ref_loc (UNKNOWN_LOCATION, T) extern double_int mem_ref_offset (const_tree); extern tree reference_alias_ptr_type (const_tree); +extern tree build_invariant_address (tree, tree, HOST_WIDE_INT); extern tree constant_boolean_node (int, tree); extern tree div_if_zero_remainder (enum tree_code, const_tree, const_tree); -- 2.30.2