[llvm] [RISCV] Use sspush/sspopchk mnemonics for shadow stack codegen (PR #200182)
Sergey Stepanov via llvm-commits
llvm-commits at lists.llvm.org
Thu May 28 06:49:14 PDT 2026
https://github.com/stepanof created https://github.com/llvm/llvm-project/pull/200182
After PR #178609, SSPUSH and SSPOPCHK are encodable under the Zimop predicate alone (the Zicfiss requirement was switched to Zimop).
However the hw-shadow-stack codegen path introduced in PR #152251 still expands PseudoMOP_SSPUSH/PseudoMOP_SSPOPCHK to the base MOP_RR_7/MOP_R_28 instructions.
That workaround was needed before PR #178609 to bypass SSPUSH/SSPOPCHK's old Zicfiss predicate, but it also means that the assembler output for hw-shadow-stack functions prints "mop.rr.7 zero, zero, ra"/"mop.r.28 zero, ra" instead of the proper "sspush ra"/"sspopchk ra" mnemonics defined in the CFI RISC-V spec.
The disassembler, by contrast, prints sspush/sspopchk for the same byte sequences, so there is an asymmetry between assembler and disassembler output.
This change updates PseudoMOP_SSPUSH/PseudoMOP_SSPOPCHK to expand directly to SSPUSH/SSPOPCHK.
Encodings are byte-identical (the MOP-based instructions reuse the MOP_RR_7/MOP_R_28 encoding by design), so this change is mostly for the asm-printer.
The compressed counterpart PseudoMOP_C_SSPUSH already expands to C_SSPUSH (not C_MOP_1); this brings the uncompressed forms to parity.
>From eb3d56af7f4101fee64fdcea94be4749704d4a29 Mon Sep 17 00:00:00 2001
From: stepanof <23sas32 at gmail.com>
Date: Tue, 26 May 2026 11:00:05 -0700
Subject: [PATCH] [RISCV] Use sspush/sspopchk mnemonics for shadow stack
codegen
After PR #178609, SSPUSH and SSPOPCHK are encodable under the Zimop
predicate alone (the Zicfiss requirement was switched to Zimop).
The hw-shadow-stack codegen path introduced in PR #152251 still expands
PseudoMOP_SSPUSH/PseudoMOP_SSPOPCHK to the base MOP_RR_7/MOP_R_28
instructions. That workaround was needed before PR #178609 to bypass
SSPUSH/SSPOPCHK's old Zicfiss predicate, but it also means that the
assembler output for hw-shadow-stack functions prints
"mop.rr.7 zero, zero, ra"/"mop.r.28 zero, ra" instead of the proper
"sspush ra"/"sspopchk ra" mnemonics defined in the CFI RISC-V spec.
The disassembler, by contrast, prints sspush/sspopchk for the same
byte sequences, creating an asymmetry between assembler and
disassembler output.
This change updates PseudoMOP_SSPUSH/PseudoMOP_SSPOPCHK to expand
directly to SSPUSH/SSPOPCHK. Encodings are byte-identical (the
MOP-based instructions reuse the MOP_RR_7/MOP_R_28 encoding by
design), so this is purely a textual change for the asm-printer. The
compressed counterpart PseudoMOP_C_SSPUSH already expands to C_SSPUSH
(not C_MOP_1); this brings the uncompressed forms to parity.
---
.../lib/Target/RISCV/RISCVInstrInfoZicfiss.td | 4 +-
llvm/test/CodeGen/RISCV/shadowcallstack.ll | 48 +++++++++----------
2 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td
index 38440e0301aa1..5516a345ddb9f 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td
@@ -71,10 +71,10 @@ defm SSAMOSWAP_D : AMO_rr_aq_rl<0b01001, 0b011, "ssamoswap.d">;
let Predicates = [HasStdExtZimop] in {
let hasSideEffects = 1, mayLoad = 0, mayStore = 1 in
def PseudoMOP_SSPUSH : Pseudo<(outs), (ins GPRX1X5:$rs2), []>,
- PseudoInstExpansion<(MOP_RR_7 X0, X0, GPR:$rs2)>;
+ PseudoInstExpansion<(SSPUSH GPRX1X5:$rs2)>;
let hasSideEffects = 1, mayLoad = 1, mayStore = 0 in
def PseudoMOP_SSPOPCHK : Pseudo<(outs), (ins GPRX1X5:$rs1), []>,
- PseudoInstExpansion<(MOP_R_28 X0, GPR:$rs1)>;
+ PseudoInstExpansion<(SSPOPCHK GPRX1X5:$rs1)>;
} // Predicates = [HasStdExtZimop]
let Predicates = [HasStdExtZcmop] in {
diff --git a/llvm/test/CodeGen/RISCV/shadowcallstack.ll b/llvm/test/CodeGen/RISCV/shadowcallstack.ll
index 5d4ecbf21790a..03acd9491fed8 100644
--- a/llvm/test/CodeGen/RISCV/shadowcallstack.ll
+++ b/llvm/test/CodeGen/RISCV/shadowcallstack.ll
@@ -427,7 +427,7 @@ define i32 @f3_hw() "hw-shadow-stack" {
;
; RV32-ZICFISS-LABEL: f3_hw:
; RV32-ZICFISS: # %bb.0:
-; RV32-ZICFISS-NEXT: mop.rr.7 zero, zero, ra
+; RV32-ZICFISS-NEXT: sspush ra
; RV32-ZICFISS-NEXT: addi sp, sp, -16
; RV32-ZICFISS-NEXT: .cfi_def_cfa_offset 16
; RV32-ZICFISS-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
@@ -437,12 +437,12 @@ define i32 @f3_hw() "hw-shadow-stack" {
; RV32-ZICFISS-NEXT: .cfi_restore ra
; RV32-ZICFISS-NEXT: addi sp, sp, 16
; RV32-ZICFISS-NEXT: .cfi_def_cfa_offset 0
-; RV32-ZICFISS-NEXT: mop.r.28 zero, ra
+; RV32-ZICFISS-NEXT: sspopchk ra
; RV32-ZICFISS-NEXT: ret
;
; RV64-ZICFISS-LABEL: f3_hw:
; RV64-ZICFISS: # %bb.0:
-; RV64-ZICFISS-NEXT: mop.rr.7 zero, zero, ra
+; RV64-ZICFISS-NEXT: sspush ra
; RV64-ZICFISS-NEXT: addi sp, sp, -16
; RV64-ZICFISS-NEXT: .cfi_def_cfa_offset 16
; RV64-ZICFISS-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
@@ -452,7 +452,7 @@ define i32 @f3_hw() "hw-shadow-stack" {
; RV64-ZICFISS-NEXT: .cfi_restore ra
; RV64-ZICFISS-NEXT: addi sp, sp, 16
; RV64-ZICFISS-NEXT: .cfi_def_cfa_offset 0
-; RV64-ZICFISS-NEXT: mop.r.28 zero, ra
+; RV64-ZICFISS-NEXT: sspopchk ra
; RV64-ZICFISS-NEXT: ret
%res = call i32 @bar()
%res1 = add i32 %res, 1
@@ -530,7 +530,7 @@ define i32 @f4_hw() "hw-shadow-stack" {
;
; RV32-ZICFISS-LABEL: f4_hw:
; RV32-ZICFISS: # %bb.0:
-; RV32-ZICFISS-NEXT: mop.rr.7 zero, zero, ra
+; RV32-ZICFISS-NEXT: sspush ra
; RV32-ZICFISS-NEXT: addi sp, sp, -16
; RV32-ZICFISS-NEXT: .cfi_def_cfa_offset 16
; RV32-ZICFISS-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
@@ -561,12 +561,12 @@ define i32 @f4_hw() "hw-shadow-stack" {
; RV32-ZICFISS-NEXT: .cfi_restore s2
; RV32-ZICFISS-NEXT: addi sp, sp, 16
; RV32-ZICFISS-NEXT: .cfi_def_cfa_offset 0
-; RV32-ZICFISS-NEXT: mop.r.28 zero, ra
+; RV32-ZICFISS-NEXT: sspopchk ra
; RV32-ZICFISS-NEXT: ret
;
; RV64-ZICFISS-LABEL: f4_hw:
; RV64-ZICFISS: # %bb.0:
-; RV64-ZICFISS-NEXT: mop.rr.7 zero, zero, ra
+; RV64-ZICFISS-NEXT: sspush ra
; RV64-ZICFISS-NEXT: addi sp, sp, -32
; RV64-ZICFISS-NEXT: .cfi_def_cfa_offset 32
; RV64-ZICFISS-NEXT: sd ra, 24(sp) # 8-byte Folded Spill
@@ -597,7 +597,7 @@ define i32 @f4_hw() "hw-shadow-stack" {
; RV64-ZICFISS-NEXT: .cfi_restore s2
; RV64-ZICFISS-NEXT: addi sp, sp, 32
; RV64-ZICFISS-NEXT: .cfi_def_cfa_offset 0
-; RV64-ZICFISS-NEXT: mop.r.28 zero, ra
+; RV64-ZICFISS-NEXT: sspopchk ra
; RV64-ZICFISS-NEXT: ret
%res1 = call i32 @bar()
%res2 = call i32 @bar()
@@ -630,24 +630,24 @@ define i32 @f5_hw() "hw-shadow-stack" nounwind {
;
; RV32-ZICFISS-LABEL: f5_hw:
; RV32-ZICFISS: # %bb.0:
-; RV32-ZICFISS-NEXT: mop.rr.7 zero, zero, ra
+; RV32-ZICFISS-NEXT: sspush ra
; RV32-ZICFISS-NEXT: addi sp, sp, -16
; RV32-ZICFISS-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
; RV32-ZICFISS-NEXT: call bar
; RV32-ZICFISS-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
; RV32-ZICFISS-NEXT: addi sp, sp, 16
-; RV32-ZICFISS-NEXT: mop.r.28 zero, ra
+; RV32-ZICFISS-NEXT: sspopchk ra
; RV32-ZICFISS-NEXT: ret
;
; RV64-ZICFISS-LABEL: f5_hw:
; RV64-ZICFISS: # %bb.0:
-; RV64-ZICFISS-NEXT: mop.rr.7 zero, zero, ra
+; RV64-ZICFISS-NEXT: sspush ra
; RV64-ZICFISS-NEXT: addi sp, sp, -16
; RV64-ZICFISS-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
; RV64-ZICFISS-NEXT: call bar
; RV64-ZICFISS-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
; RV64-ZICFISS-NEXT: addi sp, sp, 16
-; RV64-ZICFISS-NEXT: mop.r.28 zero, ra
+; RV64-ZICFISS-NEXT: sspopchk ra
; RV64-ZICFISS-NEXT: ret
%res = call i32 @bar()
%res1 = add i32 %res, 1
@@ -734,7 +734,7 @@ define i32 @f3_both() "hw-shadow-stack" shadowcallstack {
;
; RV32-ZICFISS-LABEL: f3_both:
; RV32-ZICFISS: # %bb.0:
-; RV32-ZICFISS-NEXT: mop.rr.7 zero, zero, ra
+; RV32-ZICFISS-NEXT: sspush ra
; RV32-ZICFISS-NEXT: addi sp, sp, -16
; RV32-ZICFISS-NEXT: .cfi_def_cfa_offset 16
; RV32-ZICFISS-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
@@ -744,12 +744,12 @@ define i32 @f3_both() "hw-shadow-stack" shadowcallstack {
; RV32-ZICFISS-NEXT: .cfi_restore ra
; RV32-ZICFISS-NEXT: addi sp, sp, 16
; RV32-ZICFISS-NEXT: .cfi_def_cfa_offset 0
-; RV32-ZICFISS-NEXT: mop.r.28 zero, ra
+; RV32-ZICFISS-NEXT: sspopchk ra
; RV32-ZICFISS-NEXT: ret
;
; RV64-ZICFISS-LABEL: f3_both:
; RV64-ZICFISS: # %bb.0:
-; RV64-ZICFISS-NEXT: mop.rr.7 zero, zero, ra
+; RV64-ZICFISS-NEXT: sspush ra
; RV64-ZICFISS-NEXT: addi sp, sp, -16
; RV64-ZICFISS-NEXT: .cfi_def_cfa_offset 16
; RV64-ZICFISS-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
@@ -759,7 +759,7 @@ define i32 @f3_both() "hw-shadow-stack" shadowcallstack {
; RV64-ZICFISS-NEXT: .cfi_restore ra
; RV64-ZICFISS-NEXT: addi sp, sp, 16
; RV64-ZICFISS-NEXT: .cfi_def_cfa_offset 0
-; RV64-ZICFISS-NEXT: mop.r.28 zero, ra
+; RV64-ZICFISS-NEXT: sspopchk ra
; RV64-ZICFISS-NEXT: ret
%res = call i32 @bar()
%res1 = add i32 %res, 1
@@ -849,7 +849,7 @@ define i32 @f4_both() "hw-shadow-stack" shadowcallstack {
;
; RV32-ZICFISS-LABEL: f4_both:
; RV32-ZICFISS: # %bb.0:
-; RV32-ZICFISS-NEXT: mop.rr.7 zero, zero, ra
+; RV32-ZICFISS-NEXT: sspush ra
; RV32-ZICFISS-NEXT: addi sp, sp, -16
; RV32-ZICFISS-NEXT: .cfi_def_cfa_offset 16
; RV32-ZICFISS-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
@@ -880,12 +880,12 @@ define i32 @f4_both() "hw-shadow-stack" shadowcallstack {
; RV32-ZICFISS-NEXT: .cfi_restore s2
; RV32-ZICFISS-NEXT: addi sp, sp, 16
; RV32-ZICFISS-NEXT: .cfi_def_cfa_offset 0
-; RV32-ZICFISS-NEXT: mop.r.28 zero, ra
+; RV32-ZICFISS-NEXT: sspopchk ra
; RV32-ZICFISS-NEXT: ret
;
; RV64-ZICFISS-LABEL: f4_both:
; RV64-ZICFISS: # %bb.0:
-; RV64-ZICFISS-NEXT: mop.rr.7 zero, zero, ra
+; RV64-ZICFISS-NEXT: sspush ra
; RV64-ZICFISS-NEXT: addi sp, sp, -32
; RV64-ZICFISS-NEXT: .cfi_def_cfa_offset 32
; RV64-ZICFISS-NEXT: sd ra, 24(sp) # 8-byte Folded Spill
@@ -916,7 +916,7 @@ define i32 @f4_both() "hw-shadow-stack" shadowcallstack {
; RV64-ZICFISS-NEXT: .cfi_restore s2
; RV64-ZICFISS-NEXT: addi sp, sp, 32
; RV64-ZICFISS-NEXT: .cfi_def_cfa_offset 0
-; RV64-ZICFISS-NEXT: mop.r.28 zero, ra
+; RV64-ZICFISS-NEXT: sspopchk ra
; RV64-ZICFISS-NEXT: ret
%res1 = call i32 @bar()
%res2 = call i32 @bar()
@@ -957,24 +957,24 @@ define i32 @f5_both() "hw-shadow-stack" shadowcallstack nounwind {
;
; RV32-ZICFISS-LABEL: f5_both:
; RV32-ZICFISS: # %bb.0:
-; RV32-ZICFISS-NEXT: mop.rr.7 zero, zero, ra
+; RV32-ZICFISS-NEXT: sspush ra
; RV32-ZICFISS-NEXT: addi sp, sp, -16
; RV32-ZICFISS-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
; RV32-ZICFISS-NEXT: call bar
; RV32-ZICFISS-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
; RV32-ZICFISS-NEXT: addi sp, sp, 16
-; RV32-ZICFISS-NEXT: mop.r.28 zero, ra
+; RV32-ZICFISS-NEXT: sspopchk ra
; RV32-ZICFISS-NEXT: ret
;
; RV64-ZICFISS-LABEL: f5_both:
; RV64-ZICFISS: # %bb.0:
-; RV64-ZICFISS-NEXT: mop.rr.7 zero, zero, ra
+; RV64-ZICFISS-NEXT: sspush ra
; RV64-ZICFISS-NEXT: addi sp, sp, -16
; RV64-ZICFISS-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
; RV64-ZICFISS-NEXT: call bar
; RV64-ZICFISS-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
; RV64-ZICFISS-NEXT: addi sp, sp, 16
-; RV64-ZICFISS-NEXT: mop.r.28 zero, ra
+; RV64-ZICFISS-NEXT: sspopchk ra
; RV64-ZICFISS-NEXT: ret
%res = call i32 @bar()
%res1 = add i32 %res, 1
More information about the llvm-commits
mailing list