[compiler-rt] [llvm] [RISC-V][Zicfiss] Move shadow stack ops to save/restore builtins (PR #222850)

Nemanja Ivanovic via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 10 23:13:49 PDT 2026


https://github.com/nemanjai created https://github.com/llvm/llvm-project/pull/222850

There is currently an incompatibility between save-restore and HW shadow stack protection. The callee-saved registers are saved/restored in the save/restore builtins, but the sspush/sspop are placed into the prologue/epilogue. This is less than ideal from a code size perspective since it emits the instructions in every prologue/epilogue. But even more importantly, it also means that the code is incorrect on any non-leaf function since the link register is restored after the sspopchk - which of coruse means that the sspopchk will fail.

This patch moves the instructions to where the registers are saved/restored. More specifically, the sspush is added to the places where the link register is saved and the sspopchk is added where the restore builtin returns.

>From d290824f76bef53757b4e4e1be07b44467d6787e Mon Sep 17 00:00:00 2001
From: Nemanja Ivanovic <nemanja.i.llvm at gmail.com>
Date: Fri, 11 Sep 2026 08:06:58 +0200
Subject: [PATCH] [RISC-V][Zicfiss] Move shadow stack ops to save/restore
 builtins

There is currently an incompatibility between save-restore
and HW shadow stack protection. The callee-saved registers
are saved/restored in the save/restore builtins, but the
sspush/sspop are placed into the prologue/epilogue. This is
less than ideal from a code size perspective since it emits
the instructions in every prologue/epilogue. But even more
importantly, it also means that the code is incorrect on
any non-leaf function since the link register is restored
after the sspopchk - which of coruse means that the sspopchk
will fail.

This patch moves the instructions to where the registers are
saved/restored. More specifically, the sspush is added to
the places where the link register is saved and the sspopchk
is added where the restore builtin returns.
---
 compiler-rt/lib/builtins/riscv/restore.S     |  12 +
 compiler-rt/lib/builtins/riscv/save.S        |  30 ++
 llvm/lib/Target/RISCV/RISCVFrameLowering.cpp |  21 +-
 llvm/test/CodeGen/RISCV/shadowcallstack.ll   | 288 +++++++++++++++++++
 4 files changed, 345 insertions(+), 6 deletions(-)

diff --git a/compiler-rt/lib/builtins/riscv/restore.S b/compiler-rt/lib/builtins/riscv/restore.S
index 7816f74ed497e..de3c496ffca49 100644
--- a/compiler-rt/lib/builtins/riscv/restore.S
+++ b/compiler-rt/lib/builtins/riscv/restore.S
@@ -89,6 +89,9 @@ __riscv_restore_0:
   lw      s0,  8(sp)
   lw      ra,  12(sp)
   addi    sp, sp, 16
+#if defined(__riscv_shadow_stack)
+  sspopchk ra
+#endif
   ret
 
 #else
@@ -112,6 +115,9 @@ __riscv_restore_1:
 __riscv_restore_0:
   lw      ra, 0(sp)
   addi    sp, sp, 4
+#if defined(__riscv_shadow_stack)
+  sspopchk ra
+#endif
   ret
 
 #endif
@@ -191,6 +197,9 @@ __riscv_restore_0:
   ld      s0,  0(sp)
   ld      ra,  8(sp)
   addi    sp, sp, 16
+#if defined(__riscv_shadow_stack)
+  sspopchk ra
+#endif
   ret
 
 #else
@@ -214,6 +223,9 @@ __riscv_restore_1:
 __riscv_restore_0:
   ld      ra, 0(sp)
   addi    sp, sp, 8
+#if defined(__riscv_shadow_stack)
+  sspopchk ra
+#endif
   ret
 
 #endif
diff --git a/compiler-rt/lib/builtins/riscv/save.S b/compiler-rt/lib/builtins/riscv/save.S
index 6b50bce022524..0e14a1585e194 100644
--- a/compiler-rt/lib/builtins/riscv/save.S
+++ b/compiler-rt/lib/builtins/riscv/save.S
@@ -72,6 +72,9 @@ __riscv_save_4:
   sw     s1, 52(sp)
   sw     s0, 56(sp)
   sw     ra, 60(sp)
+#if defined(__riscv_shadow_stack)
+  sspush ra
+#endif
   add    sp, sp, t1
   jr     t0
 
@@ -92,6 +95,9 @@ __riscv_save_0:
   sw      s1,  4(sp)
   sw      s0,  8(sp)
   sw      ra,  12(sp)
+#if defined(__riscv_shadow_stack)
+  sspush ra
+#endif
   jr      t0
 
 #else
@@ -103,6 +109,9 @@ __riscv_save_2:
   sw      s1,  0(sp)
   sw      s0,  4(sp)
   sw      ra,  8(sp)
+#if defined(__riscv_shadow_stack)
+  sspush ra
+#endif
   jr      t0
 
   .globl  __riscv_save_1
@@ -111,6 +120,9 @@ __riscv_save_1:
   addi    sp, sp, -8
   sw      s0,  0(sp)
   sw      ra,  4(sp)
+#if defined(__riscv_shadow_stack)
+  sspush ra
+#endif
   jr      t0
 
   .globl  __riscv_save_0
@@ -118,6 +130,9 @@ __riscv_save_1:
 __riscv_save_0:
   addi    sp, sp, -4
   sw      ra,  0(sp)
+#if defined(__riscv_shadow_stack)
+  sspush ra
+#endif
   jr      t0
 
 #endif
@@ -199,6 +214,9 @@ __riscv_save_2:
   sd     s1, 88(sp)
   sd     s0, 96(sp)
   sd     ra, 104(sp)
+#if defined(__riscv_shadow_stack)
+  sspush ra
+#endif
   add    sp, sp, t1
   jr     t0
 
@@ -211,6 +229,9 @@ __riscv_save_0:
   addi   sp, sp, -16
   sd     s0, 0(sp)
   sd     ra, 8(sp)
+#if defined(__riscv_shadow_stack)
+  sspush ra
+#endif
   jr     t0
 
 #else
@@ -222,6 +243,9 @@ __riscv_save_2:
   sw      s1, 0(sp)
   sw      s0, 8(sp)
   sw      ra, 16(sp)
+#if defined(__riscv_shadow_stack)
+  sspush ra
+#endif
   jr      t0
 
   .globl  __riscv_save_1
@@ -230,6 +254,9 @@ __riscv_save_1:
   addi    sp, sp, -16
   sw      s0, 0(sp)
   sw      ra, 8(sp)
+#if defined(__riscv_shadow_stack)
+  sspush ra
+#endif
   jr      t0
 
   .globl  __riscv_save_0
@@ -237,6 +264,9 @@ __riscv_save_1:
 __riscv_save_0:
   addi    sp, sp, -8
   sw      ra,  0(sp)
+#if defined(__riscv_shadow_stack)
+  sspush ra
+#endif
   jr      t0
 
 #endif
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index b50a18b539555..86d137a5b875d 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -1005,8 +1005,14 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
   // SiFive CLIC needs to swap `sp` into `sf.mscratchcsw`
   emitSiFiveCLICStackSwap(MF, MBB, MBBI, DL, MachineInstr::FrameSetup);
 
-  // Emit prologue for shadow call stack.
-  emitSCSPrologue(MF, MBB, MBBI, DL);
+  bool HasHWShadowStack = MF.getFunction().hasFnAttribute("hw-shadow-stack") &&
+                          STI.hasStdExtZimop();
+  const auto &CSI = MFI.getCalleeSavedInfo();
+
+  // Emit prologue for shadow call stack except with save-restore (in which case
+  // that is deferred to the save-restore library routines).
+  if (!HasHWShadowStack || getLibCallID(MF, CSI) == -1)
+    emitSCSPrologue(MF, MBB, MBBI, DL);
 
   // We keep track of the first instruction because it might be a
   // `(QC.)CM.PUSH(FP)`, and we may need to adjust the immediate rather than
@@ -1020,8 +1026,6 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
   // Determine the correct frame layout
   determineFrameLayout(MF);
 
-  const auto &CSI = MFI.getCalleeSavedInfo();
-
   // Skip to before the spills of scalar callee-saved registers
   // FIXME: assumes exactly one instruction is used to restore each
   // callee-saved register.
@@ -1415,8 +1419,13 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
       deallocateStack(MF, MBB, MBBI, DL, StackSize,
                       RVFI->getLibCallStackSize());
 
-    // Emit epilogue for shadow call stack.
-    emitSCSEpilogue(MF, MBB, MBBI, DL);
+    bool HasHWShadowStack =
+        MF.getFunction().hasFnAttribute("hw-shadow-stack") &&
+        STI.hasStdExtZimop();
+    // Emit epilogue for SW shadow call stack. For HW shadow stack, it is up to
+    // the library routines to perform these.
+    if (!HasHWShadowStack)
+      emitSCSEpilogue(MF, MBB, MBBI, DL);
     return;
   }
 
diff --git a/llvm/test/CodeGen/RISCV/shadowcallstack.ll b/llvm/test/CodeGen/RISCV/shadowcallstack.ll
index 24fa8037f3502..c4b3e326e62e9 100644
--- a/llvm/test/CodeGen/RISCV/shadowcallstack.ll
+++ b/llvm/test/CodeGen/RISCV/shadowcallstack.ll
@@ -13,8 +13,12 @@
 ; RUN:   -verify-machineinstrs | FileCheck %s --check-prefixes=RV64-ZICFISS,RV64-NOZCMOP
 ; RUN: llc -mtriple=riscv32 -mattr=+zimop,+zcmop < %s -M no-aliases \
 ; RUN:   -verify-machineinstrs | FileCheck %s --check-prefixes=RV32-ZICFISS,RV32-ZCMOP
+; RUN: llc -mtriple=riscv32 -mattr=+zimop,+zcmop,+save-restore < %s -M no-aliases \
+; RUN:   -verify-machineinstrs | FileCheck %s --check-prefixes=RV32-SR
 ; RUN: llc -mtriple=riscv64 -mattr=+zimop,+zcmop < %s -M no-aliases \
 ; RUN:   -verify-machineinstrs | FileCheck %s --check-prefixes=RV64-ZICFISS,RV64-ZCMOP
+; RUN: llc -mtriple=riscv64 -mattr=+zimop,+zcmop,+save-restore < %s -M no-aliases \
+; RUN:   -verify-machineinstrs | FileCheck %s --check-prefix=RV64-SR
 
 define void @f1() shadowcallstack {
 ; RV32-LABEL: f1:
@@ -45,9 +49,17 @@ define void @f1() shadowcallstack {
 ; RV32-ZCMOP:       # %bb.0:
 ; RV32-ZCMOP-NEXT:    c.jr ra
 ;
+; RV32-SR-LABEL: f1:
+; RV32-SR:       # %bb.0:
+; RV32-SR-NEXT:    c.jr ra
+;
 ; RV64-ZCMOP-LABEL: f1:
 ; RV64-ZCMOP:       # %bb.0:
 ; RV64-ZCMOP-NEXT:    c.jr ra
+;
+; RV64-SR-LABEL: f1:
+; RV64-SR:       # %bb.0:
+; RV64-SR-NEXT:    c.jr ra
   ret void
 }
 
@@ -77,6 +89,14 @@ define void @f2() shadowcallstack {
 ; RV64-ZICFISS-LABEL: f2:
 ; RV64-ZICFISS:       # %bb.0:
 ; RV64-ZICFISS-NEXT:    tail foo
+;
+; RV32-SR-LABEL: f2:
+; RV32-SR:       # %bb.0:
+; RV32-SR-NEXT:    tail foo
+;
+; RV64-SR-LABEL: f2:
+; RV64-SR:       # %bb.0:
+; RV64-SR-NEXT:    tail foo
   tail call void @foo()
   ret void
 }
@@ -209,6 +229,20 @@ define i32 @f3() shadowcallstack {
 ; RV32-ZCMOP-NEXT:    .cfi_restore gp
 ; RV32-ZCMOP-NEXT:    c.jr ra
 ;
+; RV32-SR-LABEL: f3:
+; RV32-SR:       # %bb.0:
+; RV32-SR-NEXT:    c.addi gp, 4
+; RV32-SR-NEXT:    sw ra, -4(gp)
+; RV32-SR-NEXT:    .cfi_escape 0x16, 0x03, 0x02, 0x73, 0x7c #
+; RV32-SR-NEXT:    call t0, __riscv_save_0
+; RV32-SR-NEXT:    .cfi_def_cfa_offset 16
+; RV32-SR-NEXT:    .cfi_offset ra, -4
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    lw ra, -4(gp)
+; RV32-SR-NEXT:    c.addi gp, -4
+; RV32-SR-NEXT:    .cfi_restore gp
+; RV32-SR-NEXT:    tail __riscv_restore_0
+;
 ; RV64-ZCMOP-LABEL: f3:
 ; RV64-ZCMOP:       # %bb.0:
 ; RV64-ZCMOP-NEXT:    c.addi gp, 8
@@ -227,6 +261,20 @@ define i32 @f3() shadowcallstack {
 ; RV64-ZCMOP-NEXT:    c.addi gp, -8
 ; RV64-ZCMOP-NEXT:    .cfi_restore gp
 ; RV64-ZCMOP-NEXT:    c.jr ra
+;
+; RV64-SR-LABEL: f3:
+; RV64-SR:       # %bb.0:
+; RV64-SR-NEXT:    c.addi gp, 8
+; RV64-SR-NEXT:    sd ra, -8(gp)
+; RV64-SR-NEXT:    .cfi_escape 0x16, 0x03, 0x02, 0x73, 0x78 #
+; RV64-SR-NEXT:    call t0, __riscv_save_0
+; RV64-SR-NEXT:    .cfi_def_cfa_offset 16
+; RV64-SR-NEXT:    .cfi_offset ra, -8
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    ld ra, -8(gp)
+; RV64-SR-NEXT:    c.addi gp, -8
+; RV64-SR-NEXT:    .cfi_restore gp
+; RV64-SR-NEXT:    tail __riscv_restore_0
   %res = call i32 @bar()
   %res1 = add i32 %res, 1
   ret i32 %res
@@ -487,6 +535,32 @@ define i32 @f4() shadowcallstack {
 ; RV32-ZCMOP-NEXT:    .cfi_restore gp
 ; RV32-ZCMOP-NEXT:    c.jr ra
 ;
+; RV32-SR-LABEL: f4:
+; RV32-SR:       # %bb.0:
+; RV32-SR-NEXT:    c.addi gp, 4
+; RV32-SR-NEXT:    sw ra, -4(gp)
+; RV32-SR-NEXT:    .cfi_escape 0x16, 0x03, 0x02, 0x73, 0x7c #
+; RV32-SR-NEXT:    call t0, __riscv_save_3
+; RV32-SR-NEXT:    .cfi_def_cfa_offset 16
+; RV32-SR-NEXT:    .cfi_offset ra, -4
+; RV32-SR-NEXT:    .cfi_offset s0, -8
+; RV32-SR-NEXT:    .cfi_offset s1, -12
+; RV32-SR-NEXT:    .cfi_offset s2, -16
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    c.mv s0, a0
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    c.mv s1, a0
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    c.mv s2, a0
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    c.add s0, s1
+; RV32-SR-NEXT:    c.add a0, s2
+; RV32-SR-NEXT:    c.add a0, s0
+; RV32-SR-NEXT:    lw ra, -4(gp)
+; RV32-SR-NEXT:    c.addi gp, -4
+; RV32-SR-NEXT:    .cfi_restore gp
+; RV32-SR-NEXT:    tail __riscv_restore_3
+;
 ; RV64-ZCMOP-LABEL: f4:
 ; RV64-ZCMOP:       # %bb.0:
 ; RV64-ZCMOP-NEXT:    c.addi gp, 8
@@ -526,6 +600,32 @@ define i32 @f4() shadowcallstack {
 ; RV64-ZCMOP-NEXT:    c.addi gp, -8
 ; RV64-ZCMOP-NEXT:    .cfi_restore gp
 ; RV64-ZCMOP-NEXT:    c.jr ra
+;
+; RV64-SR-LABEL: f4:
+; RV64-SR:       # %bb.0:
+; RV64-SR-NEXT:    c.addi gp, 8
+; RV64-SR-NEXT:    sd ra, -8(gp)
+; RV64-SR-NEXT:    .cfi_escape 0x16, 0x03, 0x02, 0x73, 0x78 #
+; RV64-SR-NEXT:    call t0, __riscv_save_3
+; RV64-SR-NEXT:    .cfi_def_cfa_offset 32
+; RV64-SR-NEXT:    .cfi_offset ra, -8
+; RV64-SR-NEXT:    .cfi_offset s0, -16
+; RV64-SR-NEXT:    .cfi_offset s1, -24
+; RV64-SR-NEXT:    .cfi_offset s2, -32
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    c.mv s0, a0
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    c.mv s1, a0
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    c.mv s2, a0
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    c.add s0, s1
+; RV64-SR-NEXT:    c.add a0, s2
+; RV64-SR-NEXT:    c.addw a0, s0
+; RV64-SR-NEXT:    ld ra, -8(gp)
+; RV64-SR-NEXT:    c.addi gp, -8
+; RV64-SR-NEXT:    .cfi_restore gp
+; RV64-SR-NEXT:    tail __riscv_restore_3
   %res1 = call i32 @bar()
   %res2 = call i32 @bar()
   %res3 = call i32 @bar()
@@ -624,6 +724,16 @@ define i32 @f5() shadowcallstack nounwind {
 ; RV32-ZCMOP-NEXT:    c.addi gp, -4
 ; RV32-ZCMOP-NEXT:    c.jr ra
 ;
+; RV32-SR-LABEL: f5:
+; RV32-SR:       # %bb.0:
+; RV32-SR-NEXT:    c.addi gp, 4
+; RV32-SR-NEXT:    sw ra, -4(gp)
+; RV32-SR-NEXT:    call t0, __riscv_save_0
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    lw ra, -4(gp)
+; RV32-SR-NEXT:    c.addi gp, -4
+; RV32-SR-NEXT:    tail __riscv_restore_0
+;
 ; RV64-ZCMOP-LABEL: f5:
 ; RV64-ZCMOP:       # %bb.0:
 ; RV64-ZCMOP-NEXT:    c.addi gp, 8
@@ -636,6 +746,16 @@ define i32 @f5() shadowcallstack nounwind {
 ; RV64-ZCMOP-NEXT:    ld ra, -8(gp)
 ; RV64-ZCMOP-NEXT:    c.addi gp, -8
 ; RV64-ZCMOP-NEXT:    c.jr ra
+;
+; RV64-SR-LABEL: f5:
+; RV64-SR:       # %bb.0:
+; RV64-SR-NEXT:    c.addi gp, 8
+; RV64-SR-NEXT:    sd ra, -8(gp)
+; RV64-SR-NEXT:    call t0, __riscv_save_0
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    ld ra, -8(gp)
+; RV64-SR-NEXT:    c.addi gp, -8
+; RV64-SR-NEXT:    tail __riscv_restore_0
   %res = call i32 @bar()
   %res1 = add i32 %res, 1
   ret i32 %res
@@ -670,9 +790,17 @@ define void @f1_hw() "hw-shadow-stack" {
 ; RV32-ZCMOP:       # %bb.0:
 ; RV32-ZCMOP-NEXT:    c.jr ra
 ;
+; RV32-SR-LABEL: f1_hw:
+; RV32-SR:       # %bb.0:
+; RV32-SR-NEXT:    c.jr ra
+;
 ; RV64-ZCMOP-LABEL: f1_hw:
 ; RV64-ZCMOP:       # %bb.0:
 ; RV64-ZCMOP-NEXT:    c.jr ra
+;
+; RV64-SR-LABEL: f1_hw:
+; RV64-SR:       # %bb.0:
+; RV64-SR-NEXT:    c.jr ra
   ret void
 }
 
@@ -700,6 +828,14 @@ define void @f2_hw() "hw-shadow-stack" {
 ; RV64-ZICFISS-LABEL: f2_hw:
 ; RV64-ZICFISS:       # %bb.0:
 ; RV64-ZICFISS-NEXT:    tail foo
+;
+; RV32-SR-LABEL: f2_hw:
+; RV32-SR:       # %bb.0:
+; RV32-SR-NEXT:    tail foo
+;
+; RV64-SR-LABEL: f2_hw:
+; RV64-SR:       # %bb.0:
+; RV64-SR-NEXT:    tail foo
   tail call void @foo()
   ret void
 }
@@ -798,6 +934,14 @@ define i32 @f3_hw() "hw-shadow-stack" {
 ; RV32-ZCMOP-NEXT:    sspopchk ra
 ; RV32-ZCMOP-NEXT:    c.jr ra
 ;
+; RV32-SR-LABEL: f3_hw:
+; RV32-SR:       # %bb.0:
+; RV32-SR-NEXT:    call t0, __riscv_save_0
+; RV32-SR-NEXT:    .cfi_def_cfa_offset 16
+; RV32-SR-NEXT:    .cfi_offset ra, -4
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    tail __riscv_restore_0
+;
 ; RV64-ZCMOP-LABEL: f3_hw:
 ; RV64-ZCMOP:       # %bb.0:
 ; RV64-ZCMOP-NEXT:    c.sspush ra
@@ -812,6 +956,14 @@ define i32 @f3_hw() "hw-shadow-stack" {
 ; RV64-ZCMOP-NEXT:    .cfi_def_cfa_offset 0
 ; RV64-ZCMOP-NEXT:    sspopchk ra
 ; RV64-ZCMOP-NEXT:    c.jr ra
+;
+; RV64-SR-LABEL: f3_hw:
+; RV64-SR:       # %bb.0:
+; RV64-SR-NEXT:    call t0, __riscv_save_0
+; RV64-SR-NEXT:    .cfi_def_cfa_offset 16
+; RV64-SR-NEXT:    .cfi_offset ra, -8
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    tail __riscv_restore_0
   %res = call i32 @bar()
   %res1 = add i32 %res, 1
   ret i32 %res
@@ -1040,6 +1192,26 @@ define i32 @f4_hw() "hw-shadow-stack" {
 ; RV32-ZCMOP-NEXT:    sspopchk ra
 ; RV32-ZCMOP-NEXT:    c.jr ra
 ;
+; RV32-SR-LABEL: f4_hw:
+; RV32-SR:       # %bb.0:
+; RV32-SR-NEXT:    call t0, __riscv_save_3
+; RV32-SR-NEXT:    .cfi_def_cfa_offset 16
+; RV32-SR-NEXT:    .cfi_offset ra, -4
+; RV32-SR-NEXT:    .cfi_offset s0, -8
+; RV32-SR-NEXT:    .cfi_offset s1, -12
+; RV32-SR-NEXT:    .cfi_offset s2, -16
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    c.mv s0, a0
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    c.mv s1, a0
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    c.mv s2, a0
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    c.add s0, s1
+; RV32-SR-NEXT:    c.add a0, s2
+; RV32-SR-NEXT:    c.add a0, s0
+; RV32-SR-NEXT:    tail __riscv_restore_3
+;
 ; RV64-ZCMOP-LABEL: f4_hw:
 ; RV64-ZCMOP:       # %bb.0:
 ; RV64-ZCMOP-NEXT:    c.sspush ra
@@ -1075,6 +1247,26 @@ define i32 @f4_hw() "hw-shadow-stack" {
 ; RV64-ZCMOP-NEXT:    .cfi_def_cfa_offset 0
 ; RV64-ZCMOP-NEXT:    sspopchk ra
 ; RV64-ZCMOP-NEXT:    c.jr ra
+;
+; RV64-SR-LABEL: f4_hw:
+; RV64-SR:       # %bb.0:
+; RV64-SR-NEXT:    call t0, __riscv_save_3
+; RV64-SR-NEXT:    .cfi_def_cfa_offset 32
+; RV64-SR-NEXT:    .cfi_offset ra, -8
+; RV64-SR-NEXT:    .cfi_offset s0, -16
+; RV64-SR-NEXT:    .cfi_offset s1, -24
+; RV64-SR-NEXT:    .cfi_offset s2, -32
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    c.mv s0, a0
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    c.mv s1, a0
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    c.mv s2, a0
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    c.add s0, s1
+; RV64-SR-NEXT:    c.add a0, s2
+; RV64-SR-NEXT:    c.addw a0, s0
+; RV64-SR-NEXT:    tail __riscv_restore_3
   %res1 = call i32 @bar()
   %res2 = call i32 @bar()
   %res3 = call i32 @bar()
@@ -1155,6 +1347,12 @@ define i32 @f5_hw() "hw-shadow-stack" nounwind {
 ; RV32-ZCMOP-NEXT:    sspopchk ra
 ; RV32-ZCMOP-NEXT:    c.jr ra
 ;
+; RV32-SR-LABEL: f5_hw:
+; RV32-SR:       # %bb.0:
+; RV32-SR-NEXT:    call t0, __riscv_save_0
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    tail __riscv_restore_0
+;
 ; RV64-ZCMOP-LABEL: f5_hw:
 ; RV64-ZCMOP:       # %bb.0:
 ; RV64-ZCMOP-NEXT:    c.sspush ra
@@ -1165,6 +1363,12 @@ define i32 @f5_hw() "hw-shadow-stack" nounwind {
 ; RV64-ZCMOP-NEXT:    c.addi sp, 16
 ; RV64-ZCMOP-NEXT:    sspopchk ra
 ; RV64-ZCMOP-NEXT:    c.jr ra
+;
+; RV64-SR-LABEL: f5_hw:
+; RV64-SR:       # %bb.0:
+; RV64-SR-NEXT:    call t0, __riscv_save_0
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    tail __riscv_restore_0
   %res = call i32 @bar()
   %res1 = add i32 %res, 1
   ret i32 %res
@@ -1199,9 +1403,17 @@ define void @f1_both() "hw-shadow-stack" shadowcallstack {
 ; RV32-ZCMOP:       # %bb.0:
 ; RV32-ZCMOP-NEXT:    c.jr ra
 ;
+; RV32-SR-LABEL: f1_both:
+; RV32-SR:       # %bb.0:
+; RV32-SR-NEXT:    c.jr ra
+;
 ; RV64-ZCMOP-LABEL: f1_both:
 ; RV64-ZCMOP:       # %bb.0:
 ; RV64-ZCMOP-NEXT:    c.jr ra
+;
+; RV64-SR-LABEL: f1_both:
+; RV64-SR:       # %bb.0:
+; RV64-SR-NEXT:    c.jr ra
   ret void
 }
 
@@ -1229,6 +1441,14 @@ define void @f2_both() "hw-shadow-stack" shadowcallstack {
 ; RV64-ZICFISS-LABEL: f2_both:
 ; RV64-ZICFISS:       # %bb.0:
 ; RV64-ZICFISS-NEXT:    tail foo
+;
+; RV32-SR-LABEL: f2_both:
+; RV32-SR:       # %bb.0:
+; RV32-SR-NEXT:    tail foo
+;
+; RV64-SR-LABEL: f2_both:
+; RV64-SR:       # %bb.0:
+; RV64-SR-NEXT:    tail foo
   tail call void @foo()
   ret void
 }
@@ -1339,6 +1559,14 @@ define i32 @f3_both() "hw-shadow-stack" shadowcallstack {
 ; RV32-ZCMOP-NEXT:    sspopchk ra
 ; RV32-ZCMOP-NEXT:    c.jr ra
 ;
+; RV32-SR-LABEL: f3_both:
+; RV32-SR:       # %bb.0:
+; RV32-SR-NEXT:    call t0, __riscv_save_0
+; RV32-SR-NEXT:    .cfi_def_cfa_offset 16
+; RV32-SR-NEXT:    .cfi_offset ra, -4
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    tail __riscv_restore_0
+;
 ; RV64-ZCMOP-LABEL: f3_both:
 ; RV64-ZCMOP:       # %bb.0:
 ; RV64-ZCMOP-NEXT:    c.sspush ra
@@ -1353,6 +1581,14 @@ define i32 @f3_both() "hw-shadow-stack" shadowcallstack {
 ; RV64-ZCMOP-NEXT:    .cfi_def_cfa_offset 0
 ; RV64-ZCMOP-NEXT:    sspopchk ra
 ; RV64-ZCMOP-NEXT:    c.jr ra
+;
+; RV64-SR-LABEL: f3_both:
+; RV64-SR:       # %bb.0:
+; RV64-SR-NEXT:    call t0, __riscv_save_0
+; RV64-SR-NEXT:    .cfi_def_cfa_offset 16
+; RV64-SR-NEXT:    .cfi_offset ra, -8
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    tail __riscv_restore_0
   %res = call i32 @bar()
   %res1 = add i32 %res, 1
   ret i32 %res
@@ -1593,6 +1829,26 @@ define i32 @f4_both() "hw-shadow-stack" shadowcallstack {
 ; RV32-ZCMOP-NEXT:    sspopchk ra
 ; RV32-ZCMOP-NEXT:    c.jr ra
 ;
+; RV32-SR-LABEL: f4_both:
+; RV32-SR:       # %bb.0:
+; RV32-SR-NEXT:    call t0, __riscv_save_3
+; RV32-SR-NEXT:    .cfi_def_cfa_offset 16
+; RV32-SR-NEXT:    .cfi_offset ra, -4
+; RV32-SR-NEXT:    .cfi_offset s0, -8
+; RV32-SR-NEXT:    .cfi_offset s1, -12
+; RV32-SR-NEXT:    .cfi_offset s2, -16
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    c.mv s0, a0
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    c.mv s1, a0
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    c.mv s2, a0
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    c.add s0, s1
+; RV32-SR-NEXT:    c.add a0, s2
+; RV32-SR-NEXT:    c.add a0, s0
+; RV32-SR-NEXT:    tail __riscv_restore_3
+;
 ; RV64-ZCMOP-LABEL: f4_both:
 ; RV64-ZCMOP:       # %bb.0:
 ; RV64-ZCMOP-NEXT:    c.sspush ra
@@ -1628,6 +1884,26 @@ define i32 @f4_both() "hw-shadow-stack" shadowcallstack {
 ; RV64-ZCMOP-NEXT:    .cfi_def_cfa_offset 0
 ; RV64-ZCMOP-NEXT:    sspopchk ra
 ; RV64-ZCMOP-NEXT:    c.jr ra
+;
+; RV64-SR-LABEL: f4_both:
+; RV64-SR:       # %bb.0:
+; RV64-SR-NEXT:    call t0, __riscv_save_3
+; RV64-SR-NEXT:    .cfi_def_cfa_offset 32
+; RV64-SR-NEXT:    .cfi_offset ra, -8
+; RV64-SR-NEXT:    .cfi_offset s0, -16
+; RV64-SR-NEXT:    .cfi_offset s1, -24
+; RV64-SR-NEXT:    .cfi_offset s2, -32
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    c.mv s0, a0
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    c.mv s1, a0
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    c.mv s2, a0
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    c.add s0, s1
+; RV64-SR-NEXT:    c.add a0, s2
+; RV64-SR-NEXT:    c.addw a0, s0
+; RV64-SR-NEXT:    tail __riscv_restore_3
   %res1 = call i32 @bar()
   %res2 = call i32 @bar()
   %res3 = call i32 @bar()
@@ -1716,6 +1992,12 @@ define i32 @f5_both() "hw-shadow-stack" shadowcallstack nounwind {
 ; RV32-ZCMOP-NEXT:    sspopchk ra
 ; RV32-ZCMOP-NEXT:    c.jr ra
 ;
+; RV32-SR-LABEL: f5_both:
+; RV32-SR:       # %bb.0:
+; RV32-SR-NEXT:    call t0, __riscv_save_0
+; RV32-SR-NEXT:    call bar
+; RV32-SR-NEXT:    tail __riscv_restore_0
+;
 ; RV64-ZCMOP-LABEL: f5_both:
 ; RV64-ZCMOP:       # %bb.0:
 ; RV64-ZCMOP-NEXT:    c.sspush ra
@@ -1726,6 +2008,12 @@ define i32 @f5_both() "hw-shadow-stack" shadowcallstack nounwind {
 ; RV64-ZCMOP-NEXT:    c.addi sp, 16
 ; RV64-ZCMOP-NEXT:    sspopchk ra
 ; RV64-ZCMOP-NEXT:    c.jr ra
+;
+; RV64-SR-LABEL: f5_both:
+; RV64-SR:       # %bb.0:
+; RV64-SR-NEXT:    call t0, __riscv_save_0
+; RV64-SR-NEXT:    call bar
+; RV64-SR-NEXT:    tail __riscv_restore_0
   %res = call i32 @bar()
   %res1 = add i32 %res, 1
   ret i32 %res



More information about the llvm-commits mailing list