aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2024-02-13 11:10:57 +0100
committerRichard Biener <rguenther@suse.de>2024-02-13 13:42:02 +0100
commit94225dfb5623725fa519eac69338f7a632a509ae (patch)
treec6369fed1a1833157ede8eb92f94f18da8dafc14 /gcc
parentefc71fd57539421c3939b1fe7594862d0fc66cdb (diff)
downloadgcc-94225dfb5623725fa519eac69338f7a632a509ae.zip
gcc-94225dfb5623725fa519eac69338f7a632a509ae.tar.gz
gcc-94225dfb5623725fa519eac69338f7a632a509ae.tar.bz2
tree-optimization/113895 - copy_reference_ops_from_ref vs. bitfields
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr113895-1.c16
-rw-r--r--gcc/tree-ssa-sccvn.cc26
2 files changed, 39 insertions, 3 deletions
diff --git a/gcc/testsuite/gcc.dg/torture/pr113895-1.c b/gcc/testsuite/gcc.dg/torture/pr113895-1.c
new file mode 100644
index 0000000..e96cb2f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr113895-1.c
@@ -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;
+}
diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc
index 95670ae..d6b8c73 100644
--- a/gcc/tree-ssa-sccvn.cc
+++ b/gcc/tree-ssa-sccvn.cc
@@ -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;
}
}
}