]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-optimization/113895 - copy_reference_ops_from_ref vs. bitfields
authorRichard Biener <rguenther@suse.de>
Tue, 13 Feb 2024 10:10:57 +0000 (11:10 +0100)
committerRichard Biener <rguenther@suse.de>
Tue, 13 Feb 2024 12:42:02 +0000 (13:42 +0100)
The recent enhancement to discover constant array indices by range
info used by get_ref_base_and_extent doesn't work when the outermost
component reference is to a bitfield because we track the running
offset in the reference ops as bytes.  The following does as
ao_ref_init_from_vn_reference and recovers that manually, tracking
the offset for the purpose of discovering the constant array index
in bits instead.

PR tree-optimization/113895
* tree-ssa-sccvn.cc (copy_reference_ops_from_ref): Track
offset to discover constant array indices in bits, handle
COMPONENT_REF to bitfields.

* gcc.dg/torture/pr113895-1.c: New testcase.

gcc/testsuite/gcc.dg/torture/pr113895-1.c [new file with mode: 0644]
gcc/tree-ssa-sccvn.cc

diff --git a/gcc/testsuite/gcc.dg/torture/pr113895-1.c b/gcc/testsuite/gcc.dg/torture/pr113895-1.c
new file mode 100644 (file)
index 0000000..e96cb2f
--- /dev/null
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+
+int main_i;
+void transparent_crc(int);
+#pragma pack(1)
+struct {
+  signed : 17;
+  signed : 6;
+  unsigned : 13;
+  unsigned f6 : 12;
+} g_20[1];
+int main()
+{
+  transparent_crc(g_20[main_i].f6);
+  return 0;
+}
index 95670ae2ed6d5d09737b4ba31d427a2d56992a57..d6b8c734e7bad80aabb032353df62f98a80dd46d 100644 (file)
@@ -1119,14 +1119,14 @@ copy_reference_ops_from_ref (tree ref, vec<vn_reference_op_s> *result)
              unsigned HOST_WIDE_INT elsz
                = tree_to_uhwi (op.op2) * vn_ref_op_align_unit (&op);
              unsigned HOST_WIDE_INT idx
-               = (coffset / BITS_PER_UNIT - off.to_constant ()) / elsz;
+               = (coffset - off.to_constant ()) / BITS_PER_UNIT / elsz;
              if (idx == 0)
                op.op0 = op.op1;
              else
                op.op0 = wide_int_to_tree (TREE_TYPE (op.op0),
                                           wi::to_poly_wide (op.op1) + idx);
              op.off = idx * elsz;
-             off += op.off;
+             off += op.off * BITS_PER_UNIT;
            }
          else
            {
@@ -1140,10 +1140,30 @@ copy_reference_ops_from_ref (tree ref, vec<vn_reference_op_s> *result)
                       || TREE_CODE_CLASS (op.opcode) == tcc_constant)
                /* end-of ref.  */
                gcc_assert (i == result->length ());
+             else if (op.opcode == COMPONENT_REF)
+               {
+                 /* op.off is tracked in bytes, re-do it manually
+                    because of bitfields.  */
+                 tree field = op.op0;
+                 /* We do not have a complete COMPONENT_REF tree here so we
+                    cannot use component_ref_field_offset.  Do the interesting
+                    parts manually.  */
+                 tree this_offset = DECL_FIELD_OFFSET (field);
+                 if (op.op1 || !poly_int_tree_p (this_offset))
+                   gcc_unreachable ();
+                 else
+                   {
+                     poly_offset_int woffset
+                       = (wi::to_poly_offset (this_offset)
+                          << LOG2_BITS_PER_UNIT);
+                     woffset += wi::to_offset (DECL_FIELD_BIT_OFFSET (field));
+                     off += woffset.force_shwi ();
+                   }
+               }
              else
                {
                  gcc_assert (known_ne (op.off, -1));
-                 off += op.off;
+                 off += op.off * BITS_PER_UNIT;
                }
            }
        }