re PR target/63679 ([AArch64] Failure to constant fold.)
authorRichard Biener <rguenther@suse.de>
Mon, 24 Nov 2014 14:07:18 +0000 (14:07 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Mon, 24 Nov 2014 14:07:18 +0000 (14:07 +0000)
2014-11-24  Richard Biener  <rguenther@suse.de>

PR tree-optimization/63679
* tree-ssa-sccvn.c: Include ipa-ref.h, plugin-api.h and cgraph.h.
(copy_reference_ops_from_ref): Fix non-constant ADDR_EXPR case
to properly leave off at -1.
(fully_constant_vn_reference_p): Generalize folding from
constant initializers.
(vn_reference_lookup_3): When looking through aggregate copies
handle offsetted reads and try simplifying the result to
a constant.
* gimple-fold.h (fold_ctor_reference): Export.
* gimple-fold.c (fold_ctor_reference): Likewise.

* gcc.dg/tree-ssa/ssa-fre-42.c: New testcase.
* gcc.dg/tree-ssa/20030807-5.c: Avoid folding read from global to zero.
* gcc.target/i386/ssetype-1.c: Likewise.
* gcc.target/i386/ssetype-3.c: Likewise.
* gcc.target/i386/ssetype-5.c: Likewise.

From-SVN: r218019

gcc/ChangeLog
gcc/gimple-fold.c
gcc/gimple-fold.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/20030807-5.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-42.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/ssetype-1.c
gcc/testsuite/gcc.target/i386/ssetype-3.c
gcc/testsuite/gcc.target/i386/ssetype-5.c
gcc/tree-ssa-sccvn.c

index e362f1d80434702e851a470c017a01663677c381..cadd82f65c72d7d3382f3fb53ade8f5c33d6ae6a 100644 (file)
@@ -1,3 +1,17 @@
+2014-11-24  Richard Biener  <rguenther@suse.de>
+
+       PR tree-optimization/63679
+       * tree-ssa-sccvn.c: Include ipa-ref.h, plugin-api.h and cgraph.h.
+       (copy_reference_ops_from_ref): Fix non-constant ADDR_EXPR case
+       to properly leave off at -1.
+       (fully_constant_vn_reference_p): Generalize folding from
+       constant initializers.
+       (vn_reference_lookup_3): When looking through aggregate copies
+       handle offsetted reads and try simplifying the result to
+       a constant.
+       * gimple-fold.h (fold_ctor_reference): Export.
+       * gimple-fold.c (fold_ctor_reference): Likewise.
+
 2014-11-24  Petr Murzin  <petr.murzin@intel.com>
 
        * simplify-rtx.c (simplify_ternary_operation): Simplify
index 91b9b0c12827444fed74c47cba6e6adb9e66926f..98ec1176a7c90aaa5408a5c18530742f1f3f05ad 100644 (file)
@@ -4788,10 +4788,6 @@ gimple_fold_stmt_to_constant (gimple stmt, tree (*valueize) (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, tree);
-
 /* 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
@@ -5027,7 +5023,7 @@ fold_nonarray_ctor_reference (tree type, tree ctor,
 /* CTOR is value initializing memory, fold reference of type TYPE and size SIZE
    to the memory at bit OFFSET.  */
 
-static tree
+tree
 fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset,
                     unsigned HOST_WIDE_INT size, tree from_decl)
 {
index a38848f3396c0107b7bfd6a950dd15e54a0cd96a..7574de85d184b151b5e1b60dfc2cc0680e92d649 100644 (file)
@@ -39,6 +39,8 @@ extern tree follow_single_use_edges (tree);
 extern tree gimple_fold_stmt_to_constant_1 (gimple, tree (*) (tree),
                                            tree (*) (tree) = no_follow_ssa_edges);
 extern tree gimple_fold_stmt_to_constant (gimple, tree (*) (tree));
+extern tree fold_ctor_reference (tree, tree, unsigned HOST_WIDE_INT,
+                                unsigned HOST_WIDE_INT, tree);
 extern tree fold_const_aggregate_ref_1 (tree, tree (*) (tree));
 extern tree fold_const_aggregate_ref (tree);
 extern tree gimple_get_virt_method_for_binfo (HOST_WIDE_INT, tree,
index a9ac86bd33cc204525c8cc04c082660d7f8f2266..7db895bd2a227073191e292982fbea6d67962f13 100644 (file)
@@ -1,3 +1,12 @@
+2014-11-24  Richard Biener  <rguenther@suse.de>
+
+       PR tree-optimization/63679
+       * gcc.dg/tree-ssa/ssa-fre-42.c: New testcase.
+       * gcc.dg/tree-ssa/20030807-5.c: Avoid folding read from global to zero.
+       * gcc.target/i386/ssetype-1.c: Likewise.
+       * gcc.target/i386/ssetype-3.c: Likewise.
+       * gcc.target/i386/ssetype-5.c: Likewise.
+
 2014-11-24  Jonathan Wakely  <jwakely@redhat.com>
            Paolo Carlini  <paolo.carlini@oracle.com>
 
index 424b5583bb8ee6c2a7de4614d532b2a2c38d4996..2397644129f7f596c4e9920dd7d1a35c9bb06cfd 100644 (file)
@@ -13,7 +13,7 @@ struct rtx_def
   unsigned int unchanging:1;
 
 };
-static rtx current_sym_addr;
+rtx current_sym_addr;
 
 int
 foo ()
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-42.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-42.c
new file mode 100644 (file)
index 0000000..c90bb0d
--- /dev/null
@@ -0,0 +1,34 @@
+/* { dg-do run } */
+/* { dg-require-alias "" } */
+/* { dg-options "-O -fdump-tree-fre1" } */
+
+extern void abort (void);
+
+struct X { int a[128]; };
+static const struct X a = { 0, 1, 2, 3 };
+/* Prevent gimplify_modify_expr_rhs / gimplify_init_constructor from
+   expanding the aggregate copy below inline.  */
+static const struct X A __attribute__((alias("a")));
+struct X *q;
+int __attribute__((noinline))
+foo ()
+{
+  struct X b = A;
+  int *p = &b.a[2];
+  /* Prevent SRA from decomposing b.  */
+  q = &b;
+  return *p;
+}
+
+int main()
+{
+  if (foo() != 2)
+    abort ();
+  return 0;
+}
+
+/* Verify the aggregate copy we want to look through is still in place.  */
+/* { dg-final { scan-tree-dump "b = A;" "fre1" } } */
+/* Verify we have propagated the element read all the way to the return.  */
+/* { dg-final { scan-tree-dump "return 2" "fre1" } } */
+/* { dg-final { cleanup-tree-dump "fre1" } } */
index 36dcaf6b4e528fc68767c4dcb0fcd6910e3f08f0..34185dd01f294877b3004d80b935be51eb92268c 100644 (file)
@@ -14,7 +14,7 @@
 
 #include <xmmintrin.h>
 
-static __m128d magic_a, magic_b;
+__m128d magic_a, magic_b;
 
 __m128d
 t1(void)
index d6887d5cd20ae552a7779624a5c83c2a0f484de5..c2eff2be1348a09ec7d0c10968f9791331899e83 100644 (file)
@@ -13,7 +13,7 @@
 
 #include <xmmintrin.h>
 
-static __m128 magic_a, magic_b;
+__m128 magic_a, magic_b;
 __m128
 t1(void)
 {
index bc903f537336fcc01915c974ea322008fa7b754c..2dd2de4f0c6b445fa5f52c7c04040c76fcd274fe 100644 (file)
@@ -13,7 +13,7 @@
 /* Verify that we generate proper instruction with memory operand.  */
 
 #include <xmmintrin.h>
-static __m128i magic_a, magic_b;
+__m128i magic_a, magic_b;
 __m128i
 t1(void)
 {
index aa155a8e1461572fe6138b2d0345a037902ea75b..8b3f2c7f058e9075a7bdd9076eda67670a237da0 100644 (file)
@@ -65,6 +65,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-sccvn.h"
 #include "tree-cfg.h"
 #include "domwalk.h"
+#include "ipa-ref.h"
+#include "plugin-api.h"
+#include "cgraph.h"
 
 /* This algorithm is based on the SCC algorithm presented by Keith
    Cooper and L. Taylor Simpson in "SCC-Based Value numbering"
@@ -920,7 +923,7 @@ copy_reference_ops_from_ref (tree ref, vec<vn_reference_op_s> *result)
              temp.op0 = ref;
              break;
            }
-         /* Fallthrough.  */
+         break;
          /* These are only interesting for their operands, their
             existence, and their type.  They will never be the last
             ref in the chain of references (IE they require an
@@ -1325,24 +1328,66 @@ fully_constant_vn_reference_p (vn_reference_t ref)
        }
     }
 
-  /* Simplify reads from constant strings.  */
-  else if (op->opcode == ARRAY_REF
-          && TREE_CODE (op->op0) == INTEGER_CST
-          && integer_zerop (op->op1)
-          && operands.length () == 2)
+  /* Simplify reads from constants or constant initializers.  */
+  else if (BITS_PER_UNIT == 8
+          && is_gimple_reg_type (ref->type)
+          && (!INTEGRAL_TYPE_P (ref->type)
+              || TYPE_PRECISION (ref->type) % BITS_PER_UNIT == 0))
     {
-      vn_reference_op_t arg0;
-      arg0 = &operands[1];
-      if (arg0->opcode == STRING_CST
-         && (TYPE_MODE (op->type)
-             == TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0->op0))))
-         && GET_MODE_CLASS (TYPE_MODE (op->type)) == MODE_INT
-         && GET_MODE_SIZE (TYPE_MODE (op->type)) == 1
-         && tree_int_cst_sgn (op->op0) >= 0
-         && compare_tree_int (op->op0, TREE_STRING_LENGTH (arg0->op0)) < 0)
-       return build_int_cst_type (op->type,
-                                  (TREE_STRING_POINTER (arg0->op0)
-                                   [TREE_INT_CST_LOW (op->op0)]));
+      HOST_WIDE_INT off = 0;
+      HOST_WIDE_INT size = tree_to_shwi (TYPE_SIZE (ref->type));
+      if (size % BITS_PER_UNIT != 0
+         || size > MAX_BITSIZE_MODE_ANY_MODE)
+       return NULL_TREE;
+      size /= BITS_PER_UNIT;
+      unsigned i;
+      for (i = 0; i < operands.length (); ++i)
+       {
+         if (operands[i].off == -1)
+           return NULL_TREE;
+         off += operands[i].off;
+         if (operands[i].opcode == MEM_REF)
+           {
+             ++i;
+             break;
+           }
+       }
+      vn_reference_op_t base = &operands[--i];
+      tree ctor = error_mark_node;
+      tree decl = NULL_TREE;
+      if (TREE_CODE_CLASS (base->opcode) == tcc_constant)
+       ctor = base->op0;
+      else if (base->opcode == MEM_REF
+              && base[1].opcode == ADDR_EXPR
+              && (TREE_CODE (TREE_OPERAND (base[1].op0, 0)) == VAR_DECL
+                  || TREE_CODE (TREE_OPERAND (base[1].op0, 0)) == CONST_DECL))
+       {
+         decl = TREE_OPERAND (base[1].op0, 0);
+         ctor = ctor_for_folding (decl);
+       }
+      if (ctor == NULL_TREE)
+       return build_zero_cst (ref->type);
+      else if (ctor != error_mark_node)
+       {
+         if (decl)
+           {
+             tree res = fold_ctor_reference (ref->type, ctor,
+                                             off * BITS_PER_UNIT,
+                                             size * BITS_PER_UNIT, decl);
+             if (res)
+               {
+                 STRIP_USELESS_TYPE_CONVERSION (res);
+                 if (is_gimple_min_invariant (res))
+                   return res;
+               }
+           }
+         else
+           {
+             unsigned char buf[MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT];
+             if (native_encode_expr (ctor, buf, size, off) > 0)
+               return native_interpret_expr (ref->type, buf, size);
+           }
+       }
     }
 
   return NULL_TREE;
@@ -1850,11 +1895,20 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_,
         may fail when comparing types for compatibility.  But we really
         don't care here - further lookups with the rewritten operands
         will simply fail if we messed up types too badly.  */
+      HOST_WIDE_INT extra_off = 0;
       if (j == 0 && i >= 0
          && lhs_ops[0].opcode == MEM_REF
-         && lhs_ops[0].off != -1
-         && (lhs_ops[0].off == vr->operands[i].off))
-       i--, j--;
+         && lhs_ops[0].off != -1)
+       {
+         if (lhs_ops[0].off == vr->operands[i].off)
+           i--, j--;
+         else if (vr->operands[i].opcode == MEM_REF
+                  && vr->operands[i].off != -1)
+           {
+             extra_off = vr->operands[i].off - lhs_ops[0].off;
+             i--, j--;
+           }
+       }
 
       /* i now points to the first additional op.
         ???  LHS may not be completely contained in VR, one or more
@@ -1865,6 +1919,20 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_,
 
       /* Now re-write REF to be based on the rhs of the assignment.  */
       copy_reference_ops_from_ref (gimple_assign_rhs1 (def_stmt), &rhs);
+
+      /* Apply an extra offset to the inner MEM_REF of the RHS.  */
+      if (extra_off != 0)
+       {
+         if (rhs.length () < 2
+             || rhs[0].opcode != MEM_REF
+             || rhs[0].off == -1)
+           return (void *)-1;
+         rhs[0].off += extra_off;
+         rhs[0].op0 = int_const_binop (PLUS_EXPR, rhs[0].op0,
+                                       build_int_cst (TREE_TYPE (rhs[0].op0),
+                                                      extra_off));
+       }
+
       /* We need to pre-pend vr->operands[0..i] to rhs.  */
       vec<vn_reference_op_s> old = vr->operands;
       if (i + 1 + rhs.length () > vr->operands.length ())
@@ -1882,6 +1950,12 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_,
        shared_lookup_references = vr->operands;
       vr->hashcode = vn_reference_compute_hash (vr);
 
+      /* Try folding the new reference to a constant.  */
+      tree val = fully_constant_vn_reference_p (vr);
+      if (val)
+       return vn_reference_lookup_or_insert_for_pieces
+                (vuse, vr->set, vr->type, vr->operands, val);
+
       /* Adjust *ref from the new operands.  */
       if (!ao_ref_init_from_vn_reference (&r, vr->set, vr->type, vr->operands))
        return (void *)-1;