This patch picks up work that was in my working tree already and fixes
it up.  When targets choose to not emitting piecewise aggregate inits
during gimplification or when that is disabled for other reasons
(like being too large) then even FRE with all its tricks cannot
constant fold from them.  The following patch teaches it to do that
via allowing offsetted reads (at the moment only reads from offset
zero would have been handled) and finally trying to do a lookup
from the static initializer.  It also generalizes the code doing
that to not only simplify reads from string constants but from
arbitrary constans by means of the recently improved 
native_encode/interpret_expr code and from CONSTRUCTORs via
using fold_ctor_reference.

This exposes several testcases that use static uninitialized globals
for which they don't expect loads to be optimized to zero ...

Bootstrapped on x86_64-unknown-linux-gnu, re-testing in progress
after a minor fix.

To really fix PR63679 fold_ctor_reference would need to learn
to combine several array fields to a vector constant or
native_encode_expr would need to learn to encode CONSTRUCTORs.
Also FRE would have to be run late.

Still referencing that PR as it lead me to re-investigate all this.

I'll go ahead and apply this patch as bugfix on Monday unless somebody
screams loudly.

Richard.

2014-11-21  Richard Biener  <rguent...@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.

Index: gcc/tree-ssa-sccvn.c
===================================================================
*** gcc/tree-ssa-sccvn.c.orig   2014-11-21 11:09:55.230818525 +0100
--- gcc/tree-ssa-sccvn.c        2014-11-21 14:51:03.328237909 +0100
*************** along with GCC; see the file COPYING3.
*** 65,70 ****
--- 65,73 ----
  #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"
*************** copy_reference_ops_from_ref (tree ref, v
*** 936,942 ****
              temp.op0 = ref;
              break;
            }
!         /* Fallthrough.  */
          /* 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
--- 939,945 ----
              temp.op0 = ref;
              break;
            }
!         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
*************** fully_constant_vn_reference_p (vn_refere
*** 1341,1364 ****
        }
      }
  
!   /* Simplify reads from constant strings.  */
!   else if (op->opcode == ARRAY_REF
!          && TREE_CODE (op->op0) == INTEGER_CST
!          && integer_zerop (op->op1)
!          && operands.length () == 2)
!     {
!       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)]));
      }
  
    return NULL_TREE;
--- 1344,1409 ----
        }
      }
  
!   /* 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))
!     {
!       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;
*************** vn_reference_lookup_3 (ao_ref *ref, tree
*** 1866,1876 ****
         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.  */
        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--;
  
        /* i now points to the first additional op.
         ???  LHS may not be completely contained in VR, one or more
--- 1911,1930 ----
         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)
!       {
!         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
*************** vn_reference_lookup_3 (ao_ref *ref, tree
*** 1881,1886 ****
--- 1935,1954 ----
  
        /* 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 ())
*************** vn_reference_lookup_3 (ao_ref *ref, tree
*** 1898,1903 ****
--- 1966,1977 ----
        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;
Index: gcc/gimple-fold.c
===================================================================
*** gcc/gimple-fold.c.orig      2014-11-21 11:09:09.137820542 +0100
--- gcc/gimple-fold.c   2014-11-21 11:10:00.688818286 +0100
*************** gimple_fold_stmt_to_constant (gimple stm
*** 4787,4796 ****
  /* 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
--- 4787,4792 ----
*************** fold_nonarray_ctor_reference (tree type,
*** 5026,5032 ****
  /* 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 from_decl)
  {
--- 5022,5028 ----
  /* CTOR is value initializing memory, fold reference of type TYPE and size 
SIZE
     to the memory at bit OFFSET.  */
  
! tree
  fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset,
                     unsigned HOST_WIDE_INT size, tree from_decl)
  {
Index: gcc/gimple-fold.h
===================================================================
*** gcc/gimple-fold.h.orig      2014-11-21 11:09:09.138820542 +0100
--- gcc/gimple-fold.h   2014-11-21 11:10:00.688818286 +0100
*************** extern tree follow_single_use_edges (tre
*** 39,44 ****
--- 39,46 ----
  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: gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-42.c
===================================================================
*** /dev/null   1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-42.c  2014-11-21 11:10:00.689818286 
+0100
***************
*** 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: gcc/testsuite/gcc.dg/tree-ssa/20030807-5.c
===================================================================
*** gcc/testsuite/gcc.dg/tree-ssa/20030807-5.c.orig     2008-08-22 
16:05:13.000000000 +0200
--- gcc/testsuite/gcc.dg/tree-ssa/20030807-5.c  2014-11-21 14:34:03.066282556 
+0100
*************** struct rtx_def
*** 13,19 ****
    unsigned int unchanging:1;
  
  };
! static rtx current_sym_addr;
  
  int
  foo ()
--- 13,19 ----
    unsigned int unchanging:1;
  
  };
! rtx current_sym_addr;
  
  int
  foo ()
Index: gcc/testsuite/gcc.target/i386/ssetype-1.c
===================================================================
*** gcc/testsuite/gcc.target/i386/ssetype-1.c.orig      2014-11-13 
10:17:47.625202511 +0100
--- gcc/testsuite/gcc.target/i386/ssetype-1.c   2014-11-21 14:35:06.832279766 
+0100
***************
*** 14,20 ****
  
  #include <xmmintrin.h>
  
! static __m128d magic_a, magic_b;
  
  __m128d
  t1(void)
--- 14,20 ----
  
  #include <xmmintrin.h>
  
! __m128d magic_a, magic_b;
  
  __m128d
  t1(void)
Index: gcc/testsuite/gcc.target/i386/ssetype-3.c
===================================================================
*** gcc/testsuite/gcc.target/i386/ssetype-3.c.orig      2010-07-23 
16:02:22.000000000 +0200
--- gcc/testsuite/gcc.target/i386/ssetype-3.c   2014-11-21 14:35:25.969278928 
+0100
***************
*** 13,19 ****
  
  #include <xmmintrin.h>
  
! static __m128 magic_a, magic_b;
  __m128
  t1(void)
  {
--- 13,19 ----
  
  #include <xmmintrin.h>
  
! __m128 magic_a, magic_b;
  __m128
  t1(void)
  {
Index: gcc/testsuite/gcc.target/i386/ssetype-5.c
===================================================================
*** gcc/testsuite/gcc.target/i386/ssetype-5.c.orig      2014-11-13 
10:17:47.610202511 +0100
--- gcc/testsuite/gcc.target/i386/ssetype-5.c   2014-11-21 14:35:35.198278525 
+0100
***************
*** 13,19 ****
  /* Verify that we generate proper instruction with memory operand.  */
  
  #include <xmmintrin.h>
! static __m128i magic_a, magic_b;
  __m128i
  t1(void)
  {
--- 13,19 ----
  /* Verify that we generate proper instruction with memory operand.  */
  
  #include <xmmintrin.h>
! __m128i magic_a, magic_b;
  __m128i
  t1(void)
  {

Reply via email to