aarch64: Fix segfault in aarch64_expand_epilogue [PR95361]
authorRichard Sandiford <richard.sandiford@arm.com>
Thu, 28 May 2020 12:18:12 +0000 (13:18 +0100)
committerRichard Sandiford <richard.sandiford@arm.com>
Thu, 28 May 2020 12:18:12 +0000 (13:18 +0100)
The stack frame for the function in the testcase consisted of two
SVE save slots.  Both saves had been shrink-wrapped, but for different
blocks, meaning that the stack allocation and deallocation were
separate from the saves themselves.  Before emitting the deallocation,
we tried to attach a REG_CFA_DEF_CFA note to the preceding instruction,
to redefine the CFA in terms of the stack pointer.  But in this case
there was no preceding instruction.

This in practice only happens for SVE because:

(a) We don't try to shrink-wrap wb_candidate* registers even when
    we've decided to treat them as normal saves and restores.
    I have a fix for that.

(b) Even with (a) fixed, we're (almost?) guaranteed to emit
    a stack tie for frames that are 64k or larger, so we end
    up hanging the REG_CFA_DEF_CFA note on that instead.

We should only need to redefine the CFA if it was previously
defined in terms of the frame pointer.  In other cases the CFA
should already be defined in terms of the stack pointer,
so redefining it is unnecessary but usually harmless.

2020-05-28  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
PR testsuite/95361
* config/aarch64/aarch64.c (aarch64_expand_epilogue): Assert that
we have at least some CFI operations when using a frame pointer.
Only redefine the CFA if we have CFI operations.

gcc/testsuite/
PR testsuite/95361
* gcc.target/aarch64/sve/pr95361.c: New test.

gcc/config/aarch64/aarch64.c
gcc/testsuite/gcc.target/aarch64/sve/pr95361.c [new file with mode: 0644]

index 78db0a5632326be9c6e20ff09b9dd17cfa231cf0..cffb945d7dde0181c8c9f0a0d0eccbd008ebf407 100644 (file)
@@ -8180,7 +8180,11 @@ aarch64_expand_epilogue (bool for_sibcall)
   if (callee_adjust != 0)
     aarch64_pop_regs (reg1, reg2, callee_adjust, &cfi_ops);
 
-  if (callee_adjust != 0 || maybe_gt (initial_adjust, 65536))
+  /* If we have no register restore information, the CFA must have been
+     defined in terms of the stack pointer since the end of the prologue.  */
+  gcc_assert (cfi_ops || !frame_pointer_needed);
+
+  if (cfi_ops && (callee_adjust != 0 || maybe_gt (initial_adjust, 65536)))
     {
       /* Emit delayed restores and set the CFA to be SP + initial_adjust.  */
       insn = get_last_insn ();
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pr95361.c b/gcc/testsuite/gcc.target/aarch64/sve/pr95361.c
new file mode 100644 (file)
index 0000000..ce70d0d
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-options "-O2" } */
+
+__SVInt8_t
+f (__SVInt8_t x, int y)
+{
+  if (y == 1)
+    asm volatile ("" ::: "z8");
+  if (y == 2)
+    asm volatile ("" ::: "z9");
+  return x;
+}