====================
sparc: Fix stack references in return delay slot.
gcc/
* config/sparc/sparc.md (UNSPEC_TIE): New unspec.
(stack_tie): New pattern.
* config/sparc/sparc.c (sparc_emit_stack_tie): New function.
(sparc_expand_prologue): Call it if function uses alloca.
gcc/testsuite/
* gcc.target/sparc/sparc-ret-3.c: New test.
---
gcc/config/sparc/sparc.c | 15 ++++++++
gcc/config/sparc/sparc.md | 11 ++++++
gcc/testsuite/gcc.target/sparc/sparc-ret-3.c | 53 ++++++++++++++++++++++++++++
3 files changed, 79 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/sparc/sparc-ret-3.c
@@ -5784,6 +5784,18 @@ sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
sparc_output_scratch_registers (file);
}
+/* This ties together stack memory (MEM with an alias set of frame_alias_set)
+ and the change to the stack pointer. */
+
+static void
+sparc_emit_stack_tie (void)
+{
+ rtx mem = gen_frame_mem (BLKmode,
+ gen_rtx_REG (Pmode, STACK_POINTER_REGNUM));
+
+ emit_insn (gen_stack_tie (mem));
+}
+
/* Expand the function epilogue, either normal or part of a sibcall.
We emit all the instructions except the return or the call. */
@@ -5792,6 +5804,9 @@ sparc_expand_epilogue (bool for_eh)
{
HOST_WIDE_INT size = sparc_frame_size;
+ if (cfun->calls_alloca)
+ sparc_emit_stack_tie ();
+
if (sparc_n_global_fp_regs > 0)
emit_save_or_restore_global_fp_regs (sparc_frame_base_reg,
sparc_frame_base_offset
@@ -94,6 +94,8 @@
UNSPEC_ADDV
UNSPEC_SUBV
UNSPEC_NEGV
+
+ UNSPEC_TIE
])
(define_c_enum "unspecv" [
@@ -8473,6 +8475,15 @@
[(set_attr "type" "multi")
(set_attr "length" "4")])
+;; This is used in sparc_expand_epilogue in order to prevent insns
+;; referencing the stack from being placed after the deallocation of
+;; the stack frame.
+(define_insn "stack_tie"
+ [(set (match_operand:BLK 0 "memory_operand" "+m")
+ (unspec:BLK [(match_dup 0)] UNSPEC_TIE))]
+ ""
+ ""
+ [(set_attr "length" "0")])
;; Vector instructions.
new file mode 100644
@@ -0,0 +1,53 @@
+/* PR target/80968 */
+/* { dg-do compile } */
+/* { dg-skip-if "no register windows" { *-*-* } { "-mflat" } { "" } } */
+/* { dg-require-effective-target ilp32 } */
+/* { dg-options "-mcpu=ultrasparc -O" } */
+
+/* Make sure references to the stack frame do not slip into the delay slot
+ of a return instruction. */
+
+struct crypto_shash {
+ unsigned int descsize;
+};
+struct crypto_shash *tfm;
+
+struct shash_desc {
+ struct crypto_shash *tfm;
+ unsigned int flags;
+
+ void *__ctx[] __attribute__((aligned(8)));
+};
+
+static inline unsigned int crypto_shash_descsize(struct crypto_shash *tfm)
+{
+ return tfm->descsize;
+}
+
+static inline void *shash_desc_ctx(struct shash_desc *desc)
+{
+ return desc->__ctx;
+}
+
+#define SHASH_DESC_ON_STACK(shash, ctx) \
+ char __##shash##_desc[sizeof(struct shash_desc) + \
+ crypto_shash_descsize(ctx)] __attribute__((aligned(8))); \
+ struct shash_desc *shash = (struct shash_desc *)__##shash##_desc
+
+extern int crypto_shash_update(struct shash_desc *, const void *, unsigned int);
+
+unsigned int bug(unsigned int crc, const void *address, unsigned int length)
+{
+ SHASH_DESC_ON_STACK(shash, tfm);
+ unsigned int *ctx = (unsigned int *)shash_desc_ctx(shash);
+ int err;
+
+ shash->tfm = tfm;
+ shash->flags = 0;
+ *ctx = crc;
+
+ err = crypto_shash_update(shash, address, length);
+
+ return *ctx;
+}
+/* { dg-final { scan-assembler "ld\[ \t\]*\\\[%i5\\+8\\\], %i0\n\[^\n\]*return\[ \t\]*%i7\\+8" } } */