summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog36
-rw-r--r--gcc/Makefile.in8
-rw-r--r--gcc/gimple-fold.c637
-rw-r--r--gcc/gimple-fold.h33
-rw-r--r--gcc/ipa-split.c29
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/c-c++-common/pr46562-2.c13
-rw-r--r--gcc/testsuite/c-c++-common/pr46562.c13
-rw-r--r--gcc/tree-dfa.c105
-rw-r--r--gcc/tree-flow-inline.h135
-rw-r--r--gcc/tree-flow.h1
-rw-r--r--gcc/tree-ssa-ccp.c608
-rw-r--r--gcc/tree-ssa-pre.c7
-rw-r--r--gcc/tree-ssa-sccvn.c46
-rw-r--r--gcc/tree-vrp.c24
-rw-r--r--gcc/tree.c14
-rw-r--r--gcc/tree.h1
17 files changed, 984 insertions, 732 deletions
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 <rguenther@suse.de>
+
+ 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 <richard.sandiford@linaro.org>
* 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 <rguenther@suse.de>
+
+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
+<http://www.gnu.org/licenses/>. */
+
+#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 <rguenther@suse.de>
+
+ PR tree-optimization/46562
+ * c-c++-common/pr46562-2.c: New testcase.
+ * c-c++-common/pr46562.c: Likewise.
+
2011-03-24 Ira Rosen <ira.rosen@linaro.org>
* 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);