]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR tree-optimization/46562 (CCP currently needs iteration for &a[i])
authorRichard Guenther <rguenther@suse.de>
Thu, 24 Mar 2011 11:23:29 +0000 (11:23 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 24 Mar 2011 11:23:29 +0000 (11:23 +0000)
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.

* c-c++-common/pr46562-2.c: New testcase.
* c-c++-common/pr46562.c: Likewise.

From-SVN: r171386

17 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/gimple-fold.c
gcc/gimple-fold.h [new file with mode: 0644]
gcc/ipa-split.c
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/pr46562-2.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/pr46562.c [new file with mode: 0644]
gcc/tree-dfa.c
gcc/tree-flow-inline.h
gcc/tree-flow.h
gcc/tree-ssa-ccp.c
gcc/tree-ssa-pre.c
gcc/tree-ssa-sccvn.c
gcc/tree-vrp.c
gcc/tree.c
gcc/tree.h

index 907c83b5121776dd17fc61c91f42ba526399248d..9dec3e406fae2d62ab4fca9374ba2254a9ce6172 100644 (file)
@@ -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
index 5e4027e50708fcde7cd9d077dd227a94320e32fb..3ce80611bf4d04eefedbb28f041383e8aaee041c 100644 (file)
@@ -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) \
index 158cb05802d629b419673ab3a2133c36fa4e04a8..367e40e30295a696dd872c09ef77d8d0b27b4cb5 100644 (file)
@@ -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 (file)
index 0000000..793d68a
--- /dev/null
@@ -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 */
index 3b26f61b1fb32193fc82409489b9bc58b4ff3037..1dde723e3da1bad9034182b39e222a65081e4818 100644 (file)
@@ -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.  */
index 87a8da95e51283fd19f601b740d4372626a8563a..8bda6a47eec39837098642c85827ed5c28637d58 100644 (file)
@@ -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 (file)
index 0000000..5415860
--- /dev/null
@@ -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 (file)
index 0000000..3065907
--- /dev/null
@@ -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" } } */
index 8e1e9b05a60869ec8fa903c0d529c54cc143274e..9766f00ddf757d13cd5791f710ea96f798c562b4 100644 (file)
@@ -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
index 86566101e394467eaf005408eb99b05bc3a00142..dcbe355e926220af8c6c517653c01aa7996c86a0 100644 (file)
@@ -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  */
index 14c8827d1c5d0b8cbdd13a589003b90415dc354f..c8ea3acdcd2e9156d789792bc1406c2a6e80b804 100644 (file)
@@ -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 *);
index 4fc4316bb1c57509cf13ed78d0df7c4e76afe366..059274a3513679f2108397d28a4455e1808d794a 100644 (file)
@@ -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
index f2466432f89fd120dcb2cec793149590deb07b21..0a6fa9455debecd56a0aa4258550e84a7be8352c 100644 (file)
@@ -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);
index a346243020956d8895aa8b899572fd77811742b2..29b80ea5780c0ec88c8bc42a25a474bd13f83ad2 100644 (file)
@@ -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;
     }
index 42ea9104e12e3423123202f02db9299b392dbd73..466c3a0f0da23a4c0783fbf9f00a63e3e8f24e1d 100644 (file)
@@ -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)))
index efa51bde3b1ac6b11582d379812fd6db35a2c786..f9e3f40d5ee51afd2276312bd429f2b1791cd749 100644 (file)
@@ -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,
index eb5e4cab96fee6c47f373f9282f99be36208d9c7..454d3287b4802923fac663cd8cce19a338afbf1e 100644 (file)
@@ -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);