[gcc(refs/vendors/ARM/heads/morello)] morello: Adjust aarch64_legitimize_address for capabilities
Matthew Malcomson
matmal01@gcc.gnu.org
Wed Apr 6 09:59:48 GMT 2022
https://gcc.gnu.org/g:7eb0aa658f9337d1585a28bb469fc26d55072274
commit 7eb0aa658f9337d1585a28bb469fc26d55072274
Author: Alex Coplan <alex.coplan@arm.com>
Date: Tue Mar 15 22:27:57 2022 +0000
morello: Adjust aarch64_legitimize_address for capabilities
The execution test added with this patch would previously fail at
runtime, since we would emit the following code for f at -O2 on purecap
Morello:
f:
sub c0, c0, #65536
ldr c0, [c0, 65264]
ret
This codegen is due to the aarch64_anchor_offset optimization. While
valid for standard AArch64, the large subtraction can cause the
capability to become invalid, and the subsequent load will then trap.
This patch avoids performing this transformation in
aarch64_legitimize_address if the base pointer has a capability mode. We
adjust aarch64_anchor_offset to only perform adjustments that should not
take us out of bounds. With the patch, we now generate:
f:
sub c0, c0, #272
ldr c0, [c0]
ret
and the execution test passes.
gcc/ChangeLog:
* config/aarch64/aarch64.c (aarch64_anchor_offset): Add cap
parameter. If this flag is set, only produce an anchor that's
guaranteed to be in bounds of the original base.
(aarch64_legitimize_address): Update call to
aarch64_anchor_offset to set new cap flag.
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/morello/bounds-anchor.c: New test.
Diff:
---
gcc/config/aarch64/aarch64.c | 22 +++++++++++++++++-----
.../gcc.target/aarch64/morello/bounds-anchor.c | 18 ++++++++++++++++++
2 files changed, 35 insertions(+), 5 deletions(-)
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 5f9b51e03b3..734c9b88f28 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -11388,16 +11388,25 @@ aarch64_regno_regclass (unsigned regno)
static HOST_WIDE_INT
aarch64_anchor_offset (HOST_WIDE_INT offset, HOST_WIDE_INT size,
- machine_mode mode)
+ machine_mode mode, bool cap)
{
+ /* If the base is a capability, punt on negative offsets for now to
+ avoid invalidating the capability: we could potentially add some
+ round-towards-zero behaviour for negative offsets later on. */
+ if (cap && offset < 0)
+ return 0;
+
/* Does it look like we'll need a 16-byte load/store-pair operation? */
if (size > 16)
- return (offset + 0x400) & ~0x7f0;
+ return cap ? (offset & ~0x3f0) : ((offset + 0x400) & ~0x7f0);
/* For offsets that aren't a multiple of the access size, the limit is
-256...255. */
if (offset & (size - 1))
{
+ if (cap)
+ return offset & ((mode == BLKmode) ? ~0x1ff : ~0xff);
+
/* BLKmode typically uses LDP of X-registers. */
if (mode == BLKmode)
return (offset + 512) & ~0x3ff;
@@ -11409,7 +11418,7 @@ aarch64_anchor_offset (HOST_WIDE_INT offset, HOST_WIDE_INT size,
return 0;
if (mode == TImode || mode == TFmode)
- return (offset + 0x100) & ~0x1ff;
+ return cap ? (offset & ~0xff) : ((offset + 0x100) & ~0x1ff);
/* Use 12-bit offset by access size. */
return offset & (~0xfff * size);
@@ -11470,8 +11479,11 @@ aarch64_legitimize_address (rtx x, rtx /* orig_x */, machine_mode mode)
HOST_WIDE_INT size;
if (GET_MODE_SIZE (mode).is_constant (&size))
{
- HOST_WIDE_INT base_offset = aarch64_anchor_offset (offset, size,
- mode);
+ bool cap = CAPABILITY_MODE_P (GET_MODE (base));
+ HOST_WIDE_INT base_offset = aarch64_anchor_offset (offset,
+ size,
+ mode,
+ cap);
if (base_offset != 0)
{
base = plus_constant (Pmode, base, base_offset);
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/bounds-anchor.c b/gcc/testsuite/gcc.target/aarch64/morello/bounds-anchor.c
new file mode 100644
index 00000000000..56215a89531
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/bounds-anchor.c
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+
+/* This function previously caused aarch64_anchor_offset to emit a large
+ sub followed by a large indexed load, which means we end up
+ dereferencing an invalid capability. */
+__attribute__((noipa))
+int *f(int **p) {
+ return p[-17];
+}
+
+int *arr[18];
+int main(void) {
+ int x = 42;
+ arr[0] = &x;
+ if (*f(arr + 17) != 42)
+ __builtin_abort ();
+ return 0;
+}
More information about the Gcc-cvs
mailing list