tree-optimization/104162 - CSE of &MEM[ptr].a[i] and ptr + CST
authorRichard Biener <rguenther@suse.de>
Wed, 26 Jan 2022 14:34:54 +0000 (15:34 +0100)
committerRichard Biener <rguenther@suse.de>
Thu, 5 May 2022 12:41:27 +0000 (14:41 +0200)
This adds the capability to value-numbering of treating complex
address expressions where the offset becomes invariant as equal
to a POINTER_PLUS_EXPR.  This restores CSE that is now prevented
by early lowering of &MEM[ptr + CST] to a POINTER_PLUS_EXPR.

Unfortunately this regresses gcc.dg/asan/pr99673.c again, so
the testcase is adjusted accordingly.

2022-01-26  Richard Biener  <rguenther@suse.de>

PR tree-optimization/104162
* tree-ssa-sccvn.cc (vn_reference_lookup): Handle
&MEM[_1 + 5].a[i] like a POINTER_PLUS_EXPR if the offset
becomes invariant.
(vn_reference_insert): Likewise.

* gcc.dg/tree-ssa/ssa-fre-99.c: New testcase.
* gcc.dg/asan/pr99673.c: Adjust.

gcc/testsuite/gcc.dg/asan/pr99673.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-99.c [new file with mode: 0644]
gcc/tree-ssa-sccvn.cc

index 05857fd..a1e9631 100644 (file)
@@ -1,4 +1,6 @@
 /* { dg-do compile } */
+/* Skip XPASS cases.  */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-O2 -flto" } { "" } } */
 /* { dg-additional-options "-Wstringop-overread" } */
 
 struct B {
@@ -22,6 +24,6 @@ void g (struct C *pc, struct D *pd, int i)
   pd->i = pb->i;
 
   const short *psa = pb->a[i].sa;
-  if (f (psa))
+  if (f (psa)) /* { dg-bogus "from a region of size" "pr99673" { xfail *-*-* } } */
     return;
 }
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-99.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-99.c
new file mode 100644 (file)
index 0000000..101d0d6
--- /dev/null
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* Disable FRE1 because that for the sake of __builtin_object_size
+   will not consider the equality but still valueize 'i', defeating
+   the purpose of the check.  */
+/* { dg-options "-O -fdump-tree-fre3 -fdisable-tree-fre1" } */
+
+struct S { int a[4]; };
+
+int i;
+int bar (struct S *p)
+{
+  char *q = (char *)p + 4;
+  i = 1;
+  int *r = &((struct S *)p)->a[i];
+  return q == (char *)r;
+}
+int baz (struct S *p)
+{
+  i = 1;
+  int *r = &((struct S *)p)->a[i];
+  char *q = (char *)p + 4;
+  return q == (char *)r;
+}
+
+/* Verify FRE can handle valueizing &p->a[i] and value-numbering it
+   equal to a POINTER_PLUS_EXPR.  */
+/* { dg-final { scan-tree-dump-times "return 1;" 2 "fre3" } } */
index 3c90c1e..7658763 100644 (file)
@@ -3666,6 +3666,38 @@ vn_reference_lookup (tree op, tree vuse, vn_lookup_kind kind,
   vr1.vuse = vuse_ssa_val (vuse);
   vr1.operands = operands
     = valueize_shared_reference_ops_from_ref (op, &valueized_anything);
+
+  /* Handle &MEM[ptr + 5].b[1].c as POINTER_PLUS_EXPR.  Avoid doing
+     this before the pass folding __builtin_object_size had a chance to run.  */
+  if ((cfun->curr_properties & PROP_objsz)
+      && operands[0].opcode == ADDR_EXPR
+      && operands.last ().opcode == SSA_NAME)
+    {
+      poly_int64 off = 0;
+      vn_reference_op_t vro;
+      unsigned i;
+      for (i = 1; operands.iterate (i, &vro); ++i)
+       {
+         if (vro->opcode == SSA_NAME)
+           break;
+         else if (known_eq (vro->off, -1))
+           break;
+         off += vro->off;
+       }
+      if (i == operands.length () - 1)
+       {
+         gcc_assert (operands[i-1].opcode == MEM_REF);
+         tree ops[2];
+         ops[0] = operands[i].op0;
+         ops[1] = wide_int_to_tree (sizetype, off);
+         tree res = vn_nary_op_lookup_pieces (2, POINTER_PLUS_EXPR,
+                                              TREE_TYPE (op), ops, NULL);
+         if (res)
+           return res;
+         return NULL_TREE;
+       }
+    }
+
   vr1.type = TREE_TYPE (op);
   ao_ref op_ref;
   ao_ref_init (&op_ref, op);
@@ -3757,13 +3789,45 @@ vn_reference_insert (tree op, tree result, tree vuse, tree vdef)
   vn_reference_t vr1;
   bool tem;
 
+  vec<vn_reference_op_s> operands
+    = valueize_shared_reference_ops_from_ref (op, &tem);
+  /* Handle &MEM[ptr + 5].b[1].c as POINTER_PLUS_EXPR.  Avoid doing this
+     before the pass folding __builtin_object_size had a chance to run.  */
+  if ((cfun->curr_properties & PROP_objsz)
+      && operands[0].opcode == ADDR_EXPR
+      && operands.last ().opcode == SSA_NAME)
+    {
+      poly_int64 off = 0;
+      vn_reference_op_t vro;
+      unsigned i;
+      for (i = 1; operands.iterate (i, &vro); ++i)
+       {
+         if (vro->opcode == SSA_NAME)
+           break;
+         else if (known_eq (vro->off, -1))
+           break;
+         off += vro->off;
+       }
+      if (i == operands.length () - 1)
+       {
+         gcc_assert (operands[i-1].opcode == MEM_REF);
+         tree ops[2];
+         ops[0] = operands[i].op0;
+         ops[1] = wide_int_to_tree (sizetype, off);
+         vn_nary_op_insert_pieces (2, POINTER_PLUS_EXPR,
+                                   TREE_TYPE (op), ops, result,
+                                   VN_INFO (result)->value_id);
+         return;
+       }
+    }
+
   vr1 = XOBNEW (&vn_tables_obstack, vn_reference_s);
   if (TREE_CODE (result) == SSA_NAME)
     vr1->value_id = VN_INFO (result)->value_id;
   else
     vr1->value_id = get_or_alloc_constant_value_id (result);
   vr1->vuse = vuse_ssa_val (vuse);
-  vr1->operands = valueize_shared_reference_ops_from_ref (op, &tem).copy ();
+  vr1->operands = operands.copy ();
   vr1->type = TREE_TYPE (op);
   vr1->punned = false;
   ao_ref op_ref;