When RTL expansion of an out-of-bound access of a register falls
back to a BIT_FIELD_REF we have to ensure that's valid. The
following avoids negative offsets by expanding through a stack
temporary.
Bootstrap and regtest running on x86_64-unknown-linux-gnu.
OK if that succeeds?
Thanks,
Richard.
PR middle-end/118643
* expr.cc (expand_expr_real_1): Avoid falling back to BIT_FIELD_REF
expansion for negative offset.
* gcc.dg/pr118643.c: New testcase.
---
gcc/expr.cc | 8 +++++---
gcc/testsuite/gcc.dg/pr118643.c | 11 +++++++++++
2 files changed, 16 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/pr118643.c
diff --git a/gcc/expr.cc b/gcc/expr.cc
index a310b2d9131..4bfcde54523 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -11796,13 +11796,15 @@ expand_expr_real_1 (tree exp, rtx target,
machine_mode tmode,
&& known_eq (GET_MODE_BITSIZE (DECL_MODE (base)), type_size))
return expand_expr (build1 (VIEW_CONVERT_EXPR, type, base),
target, tmode, modifier);
- if (TYPE_MODE (type) == BLKmode)
+ if (TYPE_MODE (type) == BLKmode
+ || maybe_lt (offset, 0))
{
temp = assign_stack_temp (DECL_MODE (base),
GET_MODE_SIZE (DECL_MODE (base)));
store_expr (base, temp, 0, false, false);
- temp = adjust_address (temp, BLKmode, offset);
- set_mem_size (temp, int_size_in_bytes (type));
+ temp = adjust_address (temp, TYPE_MODE (type), offset);
+ if (TYPE_MODE (type) == BLKmode)
+ set_mem_size (temp, int_size_in_bytes (type));
return temp;
}
exp = build3 (BIT_FIELD_REF, type, base, TYPE_SIZE (type),
diff --git a/gcc/testsuite/gcc.dg/pr118643.c b/gcc/testsuite/gcc.dg/pr118643.c
new file mode 100644
index 00000000000..ff2b081ae0b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr118643.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+typedef __attribute__((__vector_size__(1))) unsigned char V;
+
+V x;
+void foo()
+{
+ V v = x;
+ x = *(V *)(&v - 1);
+}
--
2.43.0