]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-optimization/121405 - missed VN with aggregate copy
authorRichard Biener <rguenther@suse.de>
Wed, 6 Aug 2025 10:31:13 +0000 (12:31 +0200)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 7 Aug 2025 11:57:18 +0000 (13:57 +0200)
The following handles value-numbering of a BIT_FIELD_REF of
a register that's defined by a load by looking up a subset
load similar to how we handle bit-and masked loads.  This
allows the testcase to be simplified by two FRE passes,
the first one will create the BIT_FIELD_REF.

PR tree-optimization/121405
* tree-ssa-sccvn.cc (visit_nary_op): Handle BIT_FIELD_REF
with reference def by looking up a combination of both.

* gcc.dg/tree-ssa/ssa-fre-107.c: New testcase.
* gcc.target/i386/pr90579.c: Adjust.

gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-107.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr90579.c
gcc/tree-ssa-sccvn.cc

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-107.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-107.c
new file mode 100644 (file)
index 0000000..f80baf3
--- /dev/null
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-optimized" } */
+
+struct vec_char_16
+{
+  unsigned char raw[2];
+};
+
+static inline struct vec_char_16
+Dup128VecFromValues(unsigned char t0, unsigned char t1)
+{
+  struct vec_char_16 result;
+  result.raw[0] = t0;
+  result.raw[1] = t1;
+  return result;
+}
+
+int f(unsigned char t0, unsigned char t1)
+{
+  struct vec_char_16 a = Dup128VecFromValues(t0, t1);
+  struct vec_char_16 b;
+  __builtin_memcpy(&b, &a, sizeof(a));
+  return b.raw[0] + b.raw[1];
+}
+
+/* Ideally we'd optimize this at FRE1 time but we only replace
+   the loads from b.raw[] with BIT_FIELD_REFs which get optimized
+   only later in the next FRE.  */
+/* { dg-final { scan-tree-dump-not "MEM" "optimized" } } */
index ab48a44063c322b8813193dbed999168dfdc5e53..bd2fd3378e13ba4c4a84c5e9fa02d942f2868231 100644 (file)
@@ -16,8 +16,5 @@ loop (int k, double x)
   return t;
 }
 
-/* Verify we end up with scalar loads from r for the final sum.  */
-/* { dg-final { scan-assembler "vaddsd\tr\\\+40" } } */
-/* { dg-final { scan-assembler "vaddsd\tr\\\+32" } } */
-/* { dg-final { scan-assembler "vaddsd\tr\\\+24" } } */
-/* { dg-final { scan-assembler "vaddsd\tr\\\+16" } } */
+/* Verify we end up with no loads from r.  */
+/* { dg-final { scan-assembler-not "v\[ma\]\[^\t \]+\tr" } } */
index 00315d154e4edbd137dd7de8e886a021121a9fff..1c113f848ebb4b48929f2e14f9623b42ebbba735 100644 (file)
@@ -5633,6 +5633,28 @@ visit_nary_op (tree lhs, gassign *stmt)
            }
        }
       break;
+    case BIT_FIELD_REF:
+      if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == SSA_NAME)
+       {
+         tree op0 = TREE_OPERAND (rhs1, 0);
+         gassign *ass = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (op0));
+         if (ass
+             && !gimple_has_volatile_ops (ass)
+             && vn_get_stmt_kind (ass) == VN_REFERENCE)
+           {
+             tree last_vuse = gimple_vuse (ass);
+             tree op = build3 (BIT_FIELD_REF, TREE_TYPE (rhs1),
+                               gimple_assign_rhs1 (ass),
+                               TREE_OPERAND (rhs1, 1), TREE_OPERAND (rhs1, 2));
+             tree result = vn_reference_lookup (op, gimple_vuse (ass),
+                                                default_vn_walk_kind,
+                                                NULL, true, &last_vuse);
+             if (result
+                 && useless_type_conversion_p (type, TREE_TYPE (result)))
+               return set_ssa_val_to (lhs, result);
+           }
+       }
+      break;
     case TRUNC_DIV_EXPR:
       if (TYPE_UNSIGNED (type))
        break;