OSDN Git Service

2009-05-25 Richard Guenther <rguenther@suse.de>
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 25 May 2009 15:18:21 +0000 (15:18 +0000)
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 25 May 2009 15:18:21 +0000 (15:18 +0000)
PR tree-optimization/36327
* tree-ssa-alias.c (walk_non_aliased_vuses): Add second walker
callback for reference translation or lookup at the point
of may-defs.
* tree-ssa-alias.h (walk_non_aliased_vuses): Adjust prototype.
* tree-ssa-sccvn.c (get_ref_from_reference_ops): Bail out
for union COMPONENT_REFs.
(vn_reference_lookup_3): New callback.  Lookup from memset
and CONSTRUCTOR assignment, translate through struct copies.
(vn_reference_lookup_pieces): Make sure to not free the
passed operands array.  Adjust walk_non_aliased_vuses call.
(vn_reference_lookup): Adjust walk_non_aliased_vuses call,
make sure we do not leak memory.

* gcc.dg/tree-ssa/ssa-fre-24.c: New testcase.
* gcc.dg/tree-ssa/ssa-fre-25.c: Likewise.
* gcc.dg/tree-ssa/sra-2.c: Disable FRE.
* gcc.dg/vect/no-vfa-vect-43.c: Adjust.
* gcc.dg/vect/vect-40.c: Likewise.
* gcc.dg/vect/vect-42.c: Likewise.
* gcc.dg/vect/vect-46.c: Likewise.
* gcc.dg/vect/vect-76.c: Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@147851 138bc75d-0d04-0410-961f-82ee72b054a4

13 files changed:
gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/sra-2.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-24.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-25.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/vect/no-vfa-vect-43.c
gcc/testsuite/gcc.dg/vect/vect-40.c
gcc/testsuite/gcc.dg/vect/vect-42.c
gcc/testsuite/gcc.dg/vect/vect-46.c
gcc/testsuite/gcc.dg/vect/vect-76.c
gcc/tree-ssa-alias.c
gcc/tree-ssa-alias.h
gcc/tree-ssa-sccvn.c

index ef7e845..6899679 100644 (file)
@@ -1,5 +1,21 @@
 2009-05-25  Richard Guenther  <rguenther@suse.de>
 
+       PR tree-optimization/36327
+       * tree-ssa-alias.c (walk_non_aliased_vuses): Add second walker
+       callback for reference translation or lookup at the point
+       of may-defs.
+       * tree-ssa-alias.h (walk_non_aliased_vuses): Adjust prototype.
+       * tree-ssa-sccvn.c (get_ref_from_reference_ops): Bail out
+       for union COMPONENT_REFs.
+       (vn_reference_lookup_3): New callback.  Lookup from memset
+       and CONSTRUCTOR assignment, translate through struct copies.
+       (vn_reference_lookup_pieces): Make sure to not free the
+       passed operands array.  Adjust walk_non_aliased_vuses call.
+       (vn_reference_lookup): Adjust walk_non_aliased_vuses call,
+       make sure we do not leak memory.
+
+2009-05-25  Richard Guenther  <rguenther@suse.de>
+
        * tree-ssa-alias.h (dump_points_to_solution): Declare.
        * tree-inline.c (expand_call_inline): Reset the escaped and
        callused solutions.
index a5025a3..578bbee 100644 (file)
@@ -1,3 +1,15 @@
+2009-05-25  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/36327
+       * gcc.dg/tree-ssa/ssa-fre-24.c: New testcase.
+       * gcc.dg/tree-ssa/ssa-fre-25.c: Likewise.
+       * gcc.dg/tree-ssa/sra-2.c: Disable FRE.
+       * gcc.dg/vect/no-vfa-vect-43.c: Adjust.
+       * gcc.dg/vect/vect-40.c: Likewise.
+       * gcc.dg/vect/vect-42.c: Likewise.
+       * gcc.dg/vect/vect-46.c: Likewise.
+       * gcc.dg/vect/vect-76.c: Likewise.
+
 2009-05-25  Janus Weil  <janus@gcc.gnu.org>
 
        PR fortran/40176
index ec30bc9..177c4bc 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */ 
-/* { dg-options "-O1 -fdump-tree-optimized --param sra-max-structure-size=32" } */
+/* { dg-options "-O1 -fno-tree-fre -fdump-tree-optimized --param sra-max-structure-size=32" } */
 
 /* Test for SRA. */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-24.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-24.c
new file mode 100644 (file)
index 0000000..705993a
--- /dev/null
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fno-tree-sra -fdump-tree-fre" } */
+
+int foo(void)
+{
+  int a[16] = {};
+  return a[3];
+}
+
+int bar(void)
+{
+  int a[16];
+  __builtin_memset (a, 0, sizeof(a));
+  return a[3];
+}
+
+struct X { int i; };
+int baz(void)
+{
+  struct X a,b;
+  a.i = 0;
+  b = a;
+  return b.i;
+}
+
+int bazzoo (void)
+{
+  struct X b, a = {};
+  b = a;
+  return b.i;
+}
+
+/* { dg-final { scan-tree-dump-times "= 0;" 5 "fre" } } */
+/* { dg-final { cleanup-tree-dump "fre" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-25.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-25.c
new file mode 100644 (file)
index 0000000..f7f99bf
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fno-tree-sra -fdump-tree-fre" } */
+
+struct X { int i; int j; };
+void bar (struct X *);
+int foo (struct X *p)
+{
+  struct X x;
+  p->i = 1;
+  x = *p;
+  x.j = 2;
+  return p->i - x.i;
+}
+
+/* We should optimize this to return 0.  */
+
+/* { dg-final { scan-tree-dump "= 0;" "fre" } } */
+/* { dg-final { cleanup-tree-dump "fre" } } */
index 13fbc82..65e36fe 100644 (file)
@@ -22,41 +22,53 @@ void bar (float *pa, float *pb, float *pc)
 
 
 __attribute__ ((noinline)) int
-main1 (float *pa)
+main1 (float *pa, float *pb, float *pc)
 {
   int i;
-  float pb[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__))) = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57};
-  float pc[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__))) = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
+  float b[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)));
+  float c[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)));
+
+  for (i = 0; i < N; i++)
+    {
+      b[i] = pb[i];
+      c[i] = pc[i];
+    }
 
   /* Vectorizable: pa may not alias pb and/or pc, even though their
      addresses escape.  &pa would need to escape to point to escaped memory.  */
   for (i = 0; i < N; i++)
     {
-      pa[i] = pb[i] * pc[i];
+      pa[i] = b[i] * c[i];
     }
 
-  bar (pa,pb,pc);
+  bar (pa,b,c);
 
   return 0;
 }
 
 __attribute__ ((noinline)) int
-main2 (float * pa)
+main2 (float *pa, float *pb, float *pc)
 {
   int i;
-  float pb[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57};
-  float pc[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
+  float b[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)));
+  float c[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)));
+
+  for (i = 0; i < N; i++)
+    {
+      b[i] = pb[i];
+      c[i] = pc[i];
+    }
 
   /* Vectorizable: pb and pc addresses do not escape.  */
   for (i = 0; i < N; i++)
     {
-      pa[i] = pb[i] * pc[i];
+      pa[i] = b[i] * c[i];
     }   
   
   /* check results:  */
   for (i = 0; i < N; i++)
     {
-      if (pa[i] != (pb[i] * pc[i]))
+      if (pa[i] != (b[i] * c[i]))
         abort ();
     }
   
@@ -67,14 +79,16 @@ int main (void)
 {
   int i;
   float a[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)));
+  float b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57};
+  float c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
 
   check_vect ();
 
-  main1 (a);
-  main2 (a);
+  main1 (a,b,c);
+  main2 (a,b,c);
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 2 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 2 "vect" } } */
 /*  { dg-final { scan-tree-dump-times "Alignment of access forced using versioning" 2 "vect" { target vect_no_align } } } */
 /* { dg-final { cleanup-tree-dump "vect" } } */
index a73d155..d2c17d1 100644 (file)
@@ -26,13 +26,16 @@ void bar (float *pa, float *pb, float *pc)
    vect-46.c is similar to this one with one difference: 
         the loop bound is unknown.  */
 
+float b[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)))
+     = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57};
+float c[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)))
+     = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
+
 __attribute__ ((noinline)) int
 main1 ()
 {
   int i;
   float a[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)));
-  float b[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__))) = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57};
-  float c[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__))) = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
   float *pa = a;
   float *pb = b;
   float *pc = c;
index f1764e1..2968863 100644 (file)
@@ -27,15 +27,22 @@ void bar (float *pa, float *pb, float *pc)
    No aliasing problems.  */
 
 __attribute__ ((noinline)) int
-main1 (float * __restrict__ pa)
+main1 (float * __restrict__ pa, float *pb, float *pc)
 {
+  float b[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)));
+  float c[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)));
   int i;
-  float pb[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__))) = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57};
-  float pc[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__))) = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
 
+  /* We also vectorize this loop.  */
   for (i = 0; i < N; i++)
     {
-      pa[i] = pb[i] * pc[i];
+      b[i] = pb[i];
+      c[i] = pc[i];
+    }
+
+  for (i = 0; i < N; i++)
+    {
+      pa[i] = b[i] * c[i];
     }
 
   return 0;
@@ -45,18 +52,18 @@ int main (void)
 {
   int i;
   float a[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)));
-  float b[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__))) = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57};
-  float c[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__))) = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
+  float b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57};
+  float c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
 
   check_vect ();
 
-  main1 (a);
+  main1 (a,b,c);
   bar (a,b,c);
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect" } } */
 /*  { dg-final { scan-tree-dump-times "Alignment of access forced using versioning" 1 "vect" { target { vect_no_align || { ! vector_alignment_reachable } } } } } */
-/* { dg-final { scan-tree-dump-times "Vectorizing an unaligned access" 2 "vect" { xfail { vect_no_align || { ! vector_alignment_reachable } } } } } */
+/* { dg-final { scan-tree-dump-times "Vectorizing an unaligned access" 4 "vect" { xfail { vect_no_align || { ! vector_alignment_reachable } } } } } */
 /* { dg-final { scan-tree-dump-times "Alignment of access forced using peeling" 1 "vect" { xfail {vect_no_align || { ! vector_alignment_reachable } } } } } */
 /* { dg-final { cleanup-tree-dump "vect" } } */
index 2588a7b..d506d43 100644 (file)
@@ -26,11 +26,16 @@ void bar (float *pa, float *pb, float *pc)
    vect-40.c is similar to this one with one difference:
         the loop bound is known.  */
 
+float b[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)))
+     = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57};
+float c[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)))
+     = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
+
 __attribute__ ((noinline)) int
 main1 (int n)
 {
   int i;
-  float a[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)));  float b[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__))) = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57};  float c[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__))) = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
+  float a[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)));
   float *pa = a;
   float *pb = b;
   float *pc = c;
index 7097e7a..d771302 100644 (file)
    more involved than just an ssa_name.  */
 
 int ib[N+OFF] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__))) = {0, 1, 3, 5, 7, 11, 13, 17, 0, 2, 6, 10};
+int ic[N+OFF] = {0, 1, 3, 5, 7, 11, 13, 17, 0, 2, 6, 10};
 
 __attribute__ ((noinline))
 int main1 (int *pib)
 {
   int i;
   int ia[N+OFF];
-  int ic[N+OFF] = {0, 1, 3, 5, 7, 11, 13, 17, 0, 2, 6, 10};
 
   for (i = OFF; i < N; i++)
     {
index 5be39f0..5bb1f82 100644 (file)
@@ -1086,11 +1086,19 @@ get_continuation_for_phi (gimple phi, tree ref, bitmap *visited)
    WALKER returns non-NULL the walk stops and its result is returned.
    At the end of a non-successful walk NULL is returned.
 
+   TRANSLATE if non-NULL is called with a pointer to REF, the virtual
+   use which definition is a statement that may clobber REF and DATA.
+   If TRANSLATE returns (void *)-1 the walk stops and NULL is returned.
+   If TRANSLATE returns non-NULL the walk stops and its result is returned.
+   If TRANSLATE returns NULL the walk continues and TRANSLATE is supposed
+   to adjust REF and *DATA to make that valid.
+
    TODO: Cache the vector of equivalent vuses per ref, vuse pair.  */
 
 void *
 walk_non_aliased_vuses (tree ref, tree vuse,
-                       void *(*walker)(tree, tree, void *), void *data)
+                       void *(*walker)(tree, tree, void *),
+                       void *(*translate)(tree *, tree, void *),void *data)
 {
   bitmap visited = NULL;
   void *res;
@@ -1114,7 +1122,21 @@ walk_non_aliased_vuses (tree ref, tree vuse,
       else
        {
          if (stmt_may_clobber_ref_p (def_stmt, ref))
-           break;
+           {
+             if (!translate)
+               break;
+             res = (*translate) (&ref, vuse, data);
+             /* Failed lookup and translation.  */
+             if (res == (void *)-1)
+               {
+                 res = NULL;
+                 break;
+               }
+             /* Lookup succeeded.  */
+             else if (res != NULL)
+               break;
+             /* Translation succeeded, continue walking.  */
+           }
          vuse = gimple_vuse (def_stmt);
        }
     }
index d4d736d..bc96712 100644 (file)
@@ -83,7 +83,8 @@ extern bool refs_output_dependent_p (tree, tree);
 extern bool ref_maybe_used_by_stmt_p (gimple, tree);
 extern bool stmt_may_clobber_ref_p (gimple, tree);
 extern void *walk_non_aliased_vuses (tree, tree,
-                                    void *(*)(tree, tree, void *), void *);
+                                    void *(*)(tree, tree, void *),
+                                    void *(*)(tree *, tree, void *), void *);
 extern unsigned int walk_aliased_vdefs (tree, tree,
                                        bool (*)(tree, tree, void *), void *,
                                        bitmap *);
index 068484b..d2dafb3 100644 (file)
@@ -649,6 +649,9 @@ get_ref_from_reference_ops (VEC(vn_reference_op_s, heap) *ops)
          break;
 
        case COMPONENT_REF:
+         /* We cannot re-construct our fancy union reference handling.  */
+         if (TREE_CODE (op->op0) == INTEGER_CST)
+           return NULL_TREE;
          *op0_p = build3 (COMPONENT_REF, TREE_TYPE (op->op0), NULL_TREE,
                           op->op0, op->op1);
          op0_p = &TREE_OPERAND (*op0_p, 0);
@@ -940,6 +943,146 @@ vn_reference_lookup_2 (tree op ATTRIBUTE_UNUSED, tree vuse, void *vr_)
   return NULL;
 }
 
+/* Callback for walk_non_aliased_vuses.  Tries to perform a lookup
+   from the statement defining VUSE and if not successful tries to
+   translate *REFP and VR_ through an aggregate copy at the defintion
+   of VUSE.  */
+
+static void *
+vn_reference_lookup_3 (tree *refp, tree vuse, void *vr_)
+{
+  vn_reference_t vr = (vn_reference_t)vr_;
+  gimple def_stmt = SSA_NAME_DEF_STMT (vuse);
+  tree fndecl;
+  tree ref = *refp;
+  tree base;
+  HOST_WIDE_INT offset, size, maxsize;
+
+  base = get_ref_base_and_extent (ref, &offset, &size, &maxsize);
+
+  /* If we cannot constrain the size of the reference we cannot
+     test if anything kills it.  */
+  if (maxsize == -1)
+    return (void *)-1;
+
+  /* def_stmt may-defs *ref.  See if we can derive a value for *ref
+     from that defintion.
+     1) Memset.  */
+  if (is_gimple_reg_type (TREE_TYPE (ref))
+      && is_gimple_call (def_stmt)
+      && (fndecl = gimple_call_fndecl (def_stmt))
+      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+      && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET
+      && integer_zerop (gimple_call_arg (def_stmt, 1))
+      && host_integerp (gimple_call_arg (def_stmt, 2), 1)
+      && TREE_CODE (gimple_call_arg (def_stmt, 0)) == ADDR_EXPR)
+    {
+      tree ref2 = TREE_OPERAND (gimple_call_arg (def_stmt, 0), 0);
+      tree base2;
+      HOST_WIDE_INT offset2, size2, maxsize2;
+      base2 = get_ref_base_and_extent (ref2, &offset2, &size2, &maxsize2);
+      size2 = TREE_INT_CST_LOW (gimple_call_arg (def_stmt, 2)) * 8;
+      if ((unsigned HOST_WIDE_INT)size2 / 8
+         == TREE_INT_CST_LOW (gimple_call_arg (def_stmt, 2))
+         && operand_equal_p (base, base2, 0)
+         && offset2 <= offset
+         && offset2 + size2 >= offset + maxsize)
+       return vn_reference_insert (ref,
+                                   fold_convert (TREE_TYPE (ref),
+                                                 integer_zero_node), vuse);
+    }
+
+  /* 2) Assignment from an empty CONSTRUCTOR.  */
+  else if (is_gimple_reg_type (TREE_TYPE (ref))
+          && gimple_assign_single_p (def_stmt)
+          && gimple_assign_rhs_code (def_stmt) == CONSTRUCTOR
+          && CONSTRUCTOR_NELTS (gimple_assign_rhs1 (def_stmt)) == 0)
+    {
+      tree base2;
+      HOST_WIDE_INT offset2, size2, maxsize2;
+      base2 = get_ref_base_and_extent (gimple_assign_lhs (def_stmt),
+                                      &offset2, &size2, &maxsize2);
+      if (operand_equal_p (base, base2, 0)
+         && offset2 <= offset
+         && offset2 + size2 >= offset + maxsize)
+       return vn_reference_insert (ref,
+                                   fold_convert (TREE_TYPE (ref),
+                                                 integer_zero_node), vuse);
+    }
+
+  /* For aggregate copies translate the reference through them if
+     the copy kills ref.  */
+  else if (gimple_assign_single_p (def_stmt)
+          && (DECL_P (gimple_assign_rhs1 (def_stmt))
+              || INDIRECT_REF_P (gimple_assign_rhs1 (def_stmt))
+              || handled_component_p (gimple_assign_rhs1 (def_stmt))))
+    {
+      tree base2;
+      HOST_WIDE_INT offset2, size2, maxsize2;
+      int i, j;
+      VEC (vn_reference_op_s, heap) *lhs = NULL, *rhs = NULL;
+      vn_reference_op_t vro;
+
+      /* See if the assignment kills REF.  */
+      base2 = get_ref_base_and_extent (gimple_assign_lhs (def_stmt),
+                                      &offset2, &size2, &maxsize2);
+      if (!operand_equal_p (base, base2, 0)
+         || offset2 > offset
+         || offset2 + size2 < offset + maxsize)
+       return (void *)-1;
+
+      /* Find the common base of ref and the lhs.  */
+      copy_reference_ops_from_ref (gimple_assign_lhs (def_stmt), &lhs);
+      i = VEC_length (vn_reference_op_s, vr->operands) - 1;
+      j = VEC_length (vn_reference_op_s, lhs) - 1;
+      while (j >= 0
+            && vn_reference_op_eq (VEC_index (vn_reference_op_s,
+                                              vr->operands, i),
+                                   VEC_index (vn_reference_op_s, lhs, j)))
+       {
+         i--;
+         j--;
+       }
+      /* i now points to the first additional op.
+        ???  LHS may not be completely contained in VR, one or more
+        VIEW_CONVERT_EXPRs could be in its way.  We could at least
+        try handling outermost VIEW_CONVERT_EXPRs.  */
+      if (j != -1)
+       return (void *)-1;
+      VEC_free (vn_reference_op_s, heap, lhs);
+
+      /* Now re-write REF to be based on the rhs of the assignment.  */
+      copy_reference_ops_from_ref (gimple_assign_rhs1 (def_stmt), &rhs);
+      /* We need to pre-pend vr->operands[0..i] to rhs.  */
+      if (i + 1 + VEC_length (vn_reference_op_s, rhs)
+         > VEC_length (vn_reference_op_s, vr->operands))
+       {
+         VEC (vn_reference_op_s, heap) *old = vr->operands;
+         VEC_safe_grow (vn_reference_op_s, heap, vr->operands,
+                        i + 1 + VEC_length (vn_reference_op_s, rhs));
+         if (old == shared_lookup_references
+             && vr->operands != old)
+           shared_lookup_references = NULL;
+       }
+      else
+       VEC_truncate (vn_reference_op_s, vr->operands,
+                     i + 1 + VEC_length (vn_reference_op_s, rhs));
+      for (j = 0; VEC_iterate (vn_reference_op_s, rhs, j, vro); ++j)
+       VEC_replace (vn_reference_op_s, vr->operands, i + 1 + j, vro);
+      VEC_free (vn_reference_op_s, heap, rhs);
+      vr->hashcode = vn_reference_compute_hash (vr);
+      *refp = get_ref_from_reference_ops (vr->operands);
+      if (!*refp)
+       return (void *)-1;
+
+      /* Keep looking for the adjusted *REF / VR pair.  */
+      return NULL;
+    }
+
+  /* Bail out and stop walking.  */
+  return (void *)-1;
+}
+
 /* Lookup a reference operation by it's parts, in the current hash table.
    Returns the resulting value number if it exists in the hash table,
    NULL_TREE otherwise.  VNRESULT will be filled in with the actual
@@ -956,9 +1099,17 @@ vn_reference_lookup_pieces (tree vuse,
   if (!vnresult)
     vnresult = &tmp;
   *vnresult = NULL;
-  
+
   vr1.vuse = vuse ? SSA_VAL (vuse) : NULL_TREE;
-  vr1.operands = valueize_refs (operands);
+  VEC_truncate (vn_reference_op_s, shared_lookup_references, 0);
+  VEC_safe_grow (vn_reference_op_s, heap, shared_lookup_references,
+                VEC_length (vn_reference_op_s, operands));
+  memcpy (VEC_address (vn_reference_op_s, shared_lookup_references),
+         VEC_address (vn_reference_op_s, operands),
+         sizeof (vn_reference_op_s)
+         * VEC_length (vn_reference_op_s, operands));
+  vr1.operands = operands = shared_lookup_references
+    = valueize_refs (shared_lookup_references);
   vr1.hashcode = vn_reference_compute_hash (&vr1);
   vn_reference_lookup_1 (&vr1, vnresult);
 
@@ -967,11 +1118,13 @@ vn_reference_lookup_pieces (tree vuse,
       && vr1.vuse)
     {
       tree ref = get_ref_from_reference_ops (operands);
-      if (!ref)
-       return NULL_TREE;
-      *vnresult =
-       (vn_reference_t)walk_non_aliased_vuses (ref, vr1.vuse,
-                                               vn_reference_lookup_2, &vr1);
+      if (ref)
+       *vnresult =
+         (vn_reference_t)walk_non_aliased_vuses (ref, vr1.vuse,
+                                                 vn_reference_lookup_2,
+                                                 vn_reference_lookup_3, &vr1);
+      if (vr1.operands != operands)
+       VEC_free (vn_reference_op_s, heap, vr1.operands);
     }
 
   if (*vnresult)
@@ -990,13 +1143,14 @@ tree
 vn_reference_lookup (tree op, tree vuse, bool maywalk,
                     vn_reference_t *vnresult)
 {
+  VEC (vn_reference_op_s, heap) *operands;
   struct vn_reference_s vr1;
 
   if (vnresult)
     *vnresult = NULL;
 
   vr1.vuse = vuse ? SSA_VAL (vuse) : NULL_TREE;
-  vr1.operands = valueize_shared_reference_ops_from_ref (op);
+  vr1.operands = operands = valueize_shared_reference_ops_from_ref (op);
   vr1.hashcode = vn_reference_compute_hash (&vr1);
 
   if (maywalk
@@ -1005,7 +1159,10 @@ vn_reference_lookup (tree op, tree vuse, bool maywalk,
       vn_reference_t wvnresult;
       wvnresult =
        (vn_reference_t)walk_non_aliased_vuses (op, vr1.vuse,
-                                               vn_reference_lookup_2, &vr1);
+                                               vn_reference_lookup_2,
+                                               vn_reference_lookup_3, &vr1);
+      if (vr1.operands != operands)
+       VEC_free (vn_reference_op_s, heap, vr1.operands);
       if (wvnresult)
        {
          if (vnresult)