https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/226322
Backport 255162ae0ebe805df151c5c4b48e1a47a5dd74f0 f24da9d03ba5d25c523e050da2ca3c4060ca23d5 Requested by: @lenary >From 44f8099e26679bcf617932e4c080c2029666c60b Mon Sep 17 00:00:00 2001 From: Nemanja Ivanovic <[email protected]> Date: Tue, 28 Jul 2026 21:59:19 +0200 Subject: [PATCH 1/2] [RISC-V] Do not emit cm.popret[z] with zicfiss (#196267) When emitting shadow call stack protection instructions, the push/pop optimization needs to be turned off because an sspopchk before a cm.popret[z] is guaranteed to fail in a non-leaf function. In addition, the sspopchk must be emitted after a cm.pop so that the ra has the correct value when the check is performed. Fixes: https://github.com/llvm/llvm-project/issues/196261 Co-authored-by: Nemanja Ivanovic <[email protected]> (cherry picked from commit 255162ae0ebe805df151c5c4b48e1a47a5dd74f0) --- llvm/lib/Target/RISCV/RISCVFrameLowering.cpp | 4 + .../Target/RISCV/RISCVPushPopOptimizer.cpp | 9 + llvm/test/CodeGen/RISCV/shadow-stack-zcmp.ll | 57 +++ llvm/test/CodeGen/RISCV/shadowcallstack.ll | 330 ++++++++++++++++++ 4 files changed, 400 insertions(+) create mode 100644 llvm/test/CodeGen/RISCV/shadow-stack-zcmp.ll diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp index bbd1738cd51171..516cb557feaba6 100644 --- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp @@ -12,6 +12,7 @@ #include "RISCVFrameLowering.h" #include "MCTargetDesc/RISCVBaseInfo.h" +#include "MCTargetDesc/RISCVMCTargetDesc.h" #include "RISCVMachineFunctionInfo.h" #include "RISCVSubtarget.h" #include "llvm/BinaryFormat/Dwarf.h" @@ -193,6 +194,9 @@ static void emitSCSEpilogue(MachineFunction &MF, MachineBasicBlock &MBB, CSI, [&](CalleeSavedInfo &CSR) { return CSR.getReg() == RAReg; })) return; + // The shadow call stack popchk needs to happen after cm.pop that loads ra. + if (MI->getOpcode() == RISCV::CM_POP || MI->getOpcode() == RISCV::QC_CM_POP) + ++MI; const RISCVInstrInfo *TII = STI.getInstrInfo(); if (HasHWShadowStack) { BuildMI(MBB, MI, DL, TII->get(RISCV::SSPOPCHK)) diff --git a/llvm/lib/Target/RISCV/RISCVPushPopOptimizer.cpp b/llvm/lib/Target/RISCV/RISCVPushPopOptimizer.cpp index eae7e8697f0ad7..46acc5a6874ef8 100644 --- a/llvm/lib/Target/RISCV/RISCVPushPopOptimizer.cpp +++ b/llvm/lib/Target/RISCV/RISCVPushPopOptimizer.cpp @@ -138,6 +138,15 @@ bool RISCVPushPopOpt::runOnMachineFunction(MachineFunction &Fn) { if (!Subtarget->hasStdExtZcmp() && !Subtarget->hasVendorXqccmp()) return false; + // We don't want any popret[z] instructions when emitting code with shadow + // stack protection. Note that this pass would actually fail to insert any + // popret[z] instructions in this case since the cm.pop and ret will not be + // adjacent. But there's no point in running a pass that won't do anything. + if ((Fn.getFunction().hasFnAttribute("hw-shadow-stack") && + Subtarget->hasStdExtZimop()) || + Fn.getFunction().hasFnAttribute(Attribute::ShadowCallStack)) + return false; + TII = Subtarget->getInstrInfo(); TRI = Subtarget->getRegisterInfo(); diff --git a/llvm/test/CodeGen/RISCV/shadow-stack-zcmp.ll b/llvm/test/CodeGen/RISCV/shadow-stack-zcmp.ll new file mode 100644 index 00000000000000..77feb850369813 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/shadow-stack-zcmp.ll @@ -0,0 +1,57 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s --check-prefix=RV32 [email protected] = private unnamed_addr constant [13 x i8] c"Val[%d]: %d\0A\00", align 1 + +define i32 @printSomething(ptr %arr, i32 %len) #0 { +; RV32-LABEL: printSomething: +; RV32: # %bb.0: # %entry +; RV32-NEXT: sspush ra +; RV32-NEXT: cm.push {ra, s0-s3}, -32 +; RV32-NEXT: .cfi_def_cfa_offset 32 +; RV32-NEXT: .cfi_offset ra, -20 +; RV32-NEXT: .cfi_offset s0, -16 +; RV32-NEXT: .cfi_offset s1, -12 +; RV32-NEXT: .cfi_offset s2, -8 +; RV32-NEXT: .cfi_offset s3, -4 +; RV32-NEXT: mv s0, a1 +; RV32-NEXT: blez a1, .LBB0_3 +; RV32-NEXT: # %bb.1: # %for.body.preheader +; RV32-NEXT: mv s1, a0 +; RV32-NEXT: li s2, 0 +; RV32-NEXT: lui s3, %hi(.L.str) +; RV32-NEXT: addi s3, s3, %lo(.L.str) +; RV32-NEXT: .LBB0_2: # %for.body +; RV32-NEXT: # =>This Inner Loop Header: Depth=1 +; RV32-NEXT: lw a2, 0(s1) +; RV32-NEXT: cm.mva01s s3, s2 +; RV32-NEXT: call printf +; RV32-NEXT: addi s2, s2, 1 +; RV32-NEXT: addi s1, s1, 4 +; RV32-NEXT: bne s0, s2, .LBB0_2 +; RV32-NEXT: .LBB0_3: # %for.cond.cleanup +; RV32-NEXT: mv a0, s0 +; RV32-NEXT: cm.pop {ra, s0-s3}, 32 +; RV32-NEXT: sspopchk ra +; RV32-NEXT: ret +entry: + %cmp5 = icmp sgt i32 %len, 0 + br i1 %cmp5, label %for.body, label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.body, %entry + ret i32 %len + +for.body: ; preds = %entry, %for.body + %i.06 = phi i32 [ %inc, %for.body ], [ 0, %entry ] + %arrayidx = getelementptr inbounds nuw [4 x i8], ptr %arr, i32 %i.06 + %0 = load i32, ptr %arrayidx, align 4 + %call = tail call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(1) @.str, i32 noundef %i.06, i32 noundef %0) + %inc = add nuw nsw i32 %i.06, 1 + %exitcond.not = icmp eq i32 %inc, %len + br i1 %exitcond.not, label %for.cond.cleanup, label %for.body +} + +; Function Attrs: nofree nounwind +declare dso_local noundef i32 @printf(ptr noundef readonly captures(none), ...) local_unnamed_addr #0 + +attributes #0 = { "hw-shadow-stack" "target-features"="+experimental-zicfiss,+zcmop,+zcmp" } diff --git a/llvm/test/CodeGen/RISCV/shadowcallstack.ll b/llvm/test/CodeGen/RISCV/shadowcallstack.ll index e68331b86371b9..82a5e70e2977d1 100644 --- a/llvm/test/CodeGen/RISCV/shadowcallstack.ll +++ b/llvm/test/CodeGen/RISCV/shadowcallstack.ll @@ -3,6 +3,10 @@ ; RUN: | FileCheck %s --check-prefix=RV32 ; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ ; RUN: | FileCheck %s --check-prefix=RV64 +; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ +; RUN: -mattr=+zcmp,+experimental-zicfiss,+zcmop | FileCheck %s --check-prefix=RV64-ZCMP +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: -mattr=+zcmp,+experimental-zicfiss | FileCheck %s --check-prefix=RV32-ZCMP-NOZCMOP ; RUN: llc -mtriple=riscv32 -mattr=+experimental-zicfiss < %s \ ; RUN: -verify-machineinstrs | FileCheck %s --check-prefixes=RV32-ZICFISS,RV32-NOZCMOP ; RUN: llc -mtriple=riscv64 -mattr=+experimental-zicfiss < %s \ @@ -21,6 +25,14 @@ define void @f1() shadowcallstack { ; RV64: # %bb.0: ; RV64-NEXT: ret ; +; RV64-ZCMP-LABEL: f1: +; RV64-ZCMP: # %bb.0: +; RV64-ZCMP-NEXT: ret +; +; RV32-ZCMP-NOZCMOP-LABEL: f1: +; RV32-ZCMP-NOZCMOP: # %bb.0: +; RV32-ZCMP-NOZCMOP-NEXT: ret +; ; RV32-NOZCMOP-LABEL: f1: ; RV32-NOZCMOP: # %bb.0: ; RV32-NOZCMOP-NEXT: ret @@ -50,6 +62,14 @@ define void @f2() shadowcallstack { ; RV64: # %bb.0: ; RV64-NEXT: tail foo ; +; RV64-ZCMP-LABEL: f2: +; RV64-ZCMP: # %bb.0: +; RV64-ZCMP-NEXT: tail foo +; +; RV32-ZCMP-NOZCMOP-LABEL: f2: +; RV32-ZCMP-NOZCMOP: # %bb.0: +; RV32-ZCMP-NOZCMOP-NEXT: tail foo +; ; RV32-ZICFISS-LABEL: f2: ; RV32-ZICFISS: # %bb.0: ; RV32-ZICFISS-NEXT: tail foo @@ -102,6 +122,36 @@ define i32 @f3() shadowcallstack { ; RV64-NEXT: .cfi_restore gp ; RV64-NEXT: ret ; +; RV64-ZCMP-LABEL: f3: +; RV64-ZCMP: # %bb.0: +; RV64-ZCMP-NEXT: addi gp, gp, 8 +; RV64-ZCMP-NEXT: sd ra, -8(gp) +; RV64-ZCMP-NEXT: .cfi_escape 0x16, 0x03, 0x02, 0x73, 0x78 # +; RV64-ZCMP-NEXT: cm.push {ra}, -16 +; RV64-ZCMP-NEXT: .cfi_def_cfa_offset 16 +; RV64-ZCMP-NEXT: .cfi_offset ra, -8 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: cm.pop {ra}, 16 +; RV64-ZCMP-NEXT: ld ra, -8(gp) +; RV64-ZCMP-NEXT: addi gp, gp, -8 +; RV64-ZCMP-NEXT: .cfi_restore gp +; RV64-ZCMP-NEXT: ret +; +; RV32-ZCMP-NOZCMOP-LABEL: f3: +; RV32-ZCMP-NOZCMOP: # %bb.0: +; RV32-ZCMP-NOZCMOP-NEXT: addi gp, gp, 4 +; RV32-ZCMP-NOZCMOP-NEXT: sw ra, -4(gp) +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_escape 0x16, 0x03, 0x02, 0x73, 0x7c # +; RV32-ZCMP-NOZCMOP-NEXT: cm.push {ra}, -16 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_def_cfa_offset 16 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_offset ra, -4 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: cm.pop {ra}, 16 +; RV32-ZCMP-NOZCMOP-NEXT: lw ra, -4(gp) +; RV32-ZCMP-NOZCMOP-NEXT: addi gp, gp, -4 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_restore gp +; RV32-ZCMP-NOZCMOP-NEXT: ret +; ; RV32-NOZCMOP-LABEL: f3: ; RV32-NOZCMOP: # %bb.0: ; RV32-NOZCMOP-NEXT: addi gp, gp, 4 @@ -263,6 +313,60 @@ define i32 @f4() shadowcallstack { ; RV64-NEXT: .cfi_restore gp ; RV64-NEXT: ret ; +; RV64-ZCMP-LABEL: f4: +; RV64-ZCMP: # %bb.0: +; RV64-ZCMP-NEXT: addi gp, gp, 8 +; RV64-ZCMP-NEXT: sd ra, -8(gp) +; RV64-ZCMP-NEXT: .cfi_escape 0x16, 0x03, 0x02, 0x73, 0x78 # +; RV64-ZCMP-NEXT: cm.push {ra, s0-s2}, -32 +; RV64-ZCMP-NEXT: .cfi_def_cfa_offset 32 +; RV64-ZCMP-NEXT: .cfi_offset ra, -32 +; RV64-ZCMP-NEXT: .cfi_offset s0, -24 +; RV64-ZCMP-NEXT: .cfi_offset s1, -16 +; RV64-ZCMP-NEXT: .cfi_offset s2, -8 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: mv s0, a0 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: mv s1, a0 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: mv s2, a0 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: add s0, s0, s1 +; RV64-ZCMP-NEXT: add a0, a0, s2 +; RV64-ZCMP-NEXT: addw a0, a0, s0 +; RV64-ZCMP-NEXT: cm.pop {ra, s0-s2}, 32 +; RV64-ZCMP-NEXT: ld ra, -8(gp) +; RV64-ZCMP-NEXT: addi gp, gp, -8 +; RV64-ZCMP-NEXT: .cfi_restore gp +; RV64-ZCMP-NEXT: ret +; +; RV32-ZCMP-NOZCMOP-LABEL: f4: +; RV32-ZCMP-NOZCMOP: # %bb.0: +; RV32-ZCMP-NOZCMOP-NEXT: addi gp, gp, 4 +; RV32-ZCMP-NOZCMOP-NEXT: sw ra, -4(gp) +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_escape 0x16, 0x03, 0x02, 0x73, 0x7c # +; RV32-ZCMP-NOZCMOP-NEXT: cm.push {ra, s0-s2}, -16 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_def_cfa_offset 16 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_offset ra, -16 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_offset s0, -12 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_offset s1, -8 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_offset s2, -4 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: mv s0, a0 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: mv s1, a0 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: mv s2, a0 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: add s0, s0, s1 +; RV32-ZCMP-NOZCMOP-NEXT: add a0, a0, s2 +; RV32-ZCMP-NOZCMOP-NEXT: add a0, a0, s0 +; RV32-ZCMP-NOZCMOP-NEXT: cm.pop {ra, s0-s2}, 16 +; RV32-ZCMP-NOZCMOP-NEXT: lw ra, -4(gp) +; RV32-ZCMP-NOZCMOP-NEXT: addi gp, gp, -4 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_restore gp +; RV32-ZCMP-NOZCMOP-NEXT: ret +; ; RV32-NOZCMOP-LABEL: f4: ; RV32-NOZCMOP: # %bb.0: ; RV32-NOZCMOP-NEXT: addi gp, gp, 4 @@ -459,6 +563,28 @@ define i32 @f5() shadowcallstack nounwind { ; RV64-NEXT: addi gp, gp, -8 ; RV64-NEXT: ret ; +; RV64-ZCMP-LABEL: f5: +; RV64-ZCMP: # %bb.0: +; RV64-ZCMP-NEXT: addi gp, gp, 8 +; RV64-ZCMP-NEXT: sd ra, -8(gp) +; RV64-ZCMP-NEXT: cm.push {ra}, -16 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: cm.pop {ra}, 16 +; RV64-ZCMP-NEXT: ld ra, -8(gp) +; RV64-ZCMP-NEXT: addi gp, gp, -8 +; RV64-ZCMP-NEXT: ret +; +; RV32-ZCMP-NOZCMOP-LABEL: f5: +; RV32-ZCMP-NOZCMOP: # %bb.0: +; RV32-ZCMP-NOZCMOP-NEXT: addi gp, gp, 4 +; RV32-ZCMP-NOZCMOP-NEXT: sw ra, -4(gp) +; RV32-ZCMP-NOZCMOP-NEXT: cm.push {ra}, -16 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: cm.pop {ra}, 16 +; RV32-ZCMP-NOZCMOP-NEXT: lw ra, -4(gp) +; RV32-ZCMP-NOZCMOP-NEXT: addi gp, gp, -4 +; RV32-ZCMP-NOZCMOP-NEXT: ret +; ; RV32-NOZCMOP-LABEL: f5: ; RV32-NOZCMOP: # %bb.0: ; RV32-NOZCMOP-NEXT: addi gp, gp, 4 @@ -524,6 +650,14 @@ define void @f1_hw() "hw-shadow-stack" { ; RV64: # %bb.0: ; RV64-NEXT: ret ; +; RV64-ZCMP-LABEL: f1_hw: +; RV64-ZCMP: # %bb.0: +; RV64-ZCMP-NEXT: ret +; +; RV32-ZCMP-NOZCMOP-LABEL: f1_hw: +; RV32-ZCMP-NOZCMOP: # %bb.0: +; RV32-ZCMP-NOZCMOP-NEXT: ret +; ; RV32-NOZCMOP-LABEL: f1_hw: ; RV32-NOZCMOP: # %bb.0: ; RV32-NOZCMOP-NEXT: ret @@ -551,6 +685,14 @@ define void @f2_hw() "hw-shadow-stack" { ; RV64: # %bb.0: ; RV64-NEXT: tail foo ; +; RV64-ZCMP-LABEL: f2_hw: +; RV64-ZCMP: # %bb.0: +; RV64-ZCMP-NEXT: tail foo +; +; RV32-ZCMP-NOZCMOP-LABEL: f2_hw: +; RV32-ZCMP-NOZCMOP: # %bb.0: +; RV32-ZCMP-NOZCMOP-NEXT: tail foo +; ; RV32-ZICFISS-LABEL: f2_hw: ; RV32-ZICFISS: # %bb.0: ; RV32-ZICFISS-NEXT: tail foo @@ -589,6 +731,28 @@ define i32 @f3_hw() "hw-shadow-stack" { ; RV64-NEXT: .cfi_def_cfa_offset 0 ; RV64-NEXT: ret ; +; RV64-ZCMP-LABEL: f3_hw: +; RV64-ZCMP: # %bb.0: +; RV64-ZCMP-NEXT: sspush ra +; RV64-ZCMP-NEXT: cm.push {ra}, -16 +; RV64-ZCMP-NEXT: .cfi_def_cfa_offset 16 +; RV64-ZCMP-NEXT: .cfi_offset ra, -8 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: cm.pop {ra}, 16 +; RV64-ZCMP-NEXT: sspopchk ra +; RV64-ZCMP-NEXT: ret +; +; RV32-ZCMP-NOZCMOP-LABEL: f3_hw: +; RV32-ZCMP-NOZCMOP: # %bb.0: +; RV32-ZCMP-NOZCMOP-NEXT: sspush ra +; RV32-ZCMP-NOZCMOP-NEXT: cm.push {ra}, -16 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_def_cfa_offset 16 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_offset ra, -4 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: cm.pop {ra}, 16 +; RV32-ZCMP-NOZCMOP-NEXT: sspopchk ra +; RV32-ZCMP-NOZCMOP-NEXT: ret +; ; RV32-NOZCMOP-LABEL: f3_hw: ; RV32-NOZCMOP: # %bb.0: ; RV32-NOZCMOP-NEXT: sspush ra @@ -722,6 +886,52 @@ define i32 @f4_hw() "hw-shadow-stack" { ; RV64-NEXT: .cfi_def_cfa_offset 0 ; RV64-NEXT: ret ; +; RV64-ZCMP-LABEL: f4_hw: +; RV64-ZCMP: # %bb.0: +; RV64-ZCMP-NEXT: sspush ra +; RV64-ZCMP-NEXT: cm.push {ra, s0-s2}, -32 +; RV64-ZCMP-NEXT: .cfi_def_cfa_offset 32 +; RV64-ZCMP-NEXT: .cfi_offset ra, -32 +; RV64-ZCMP-NEXT: .cfi_offset s0, -24 +; RV64-ZCMP-NEXT: .cfi_offset s1, -16 +; RV64-ZCMP-NEXT: .cfi_offset s2, -8 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: mv s0, a0 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: mv s1, a0 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: mv s2, a0 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: add s0, s0, s1 +; RV64-ZCMP-NEXT: add a0, a0, s2 +; RV64-ZCMP-NEXT: addw a0, a0, s0 +; RV64-ZCMP-NEXT: cm.pop {ra, s0-s2}, 32 +; RV64-ZCMP-NEXT: sspopchk ra +; RV64-ZCMP-NEXT: ret +; +; RV32-ZCMP-NOZCMOP-LABEL: f4_hw: +; RV32-ZCMP-NOZCMOP: # %bb.0: +; RV32-ZCMP-NOZCMOP-NEXT: sspush ra +; RV32-ZCMP-NOZCMOP-NEXT: cm.push {ra, s0-s2}, -16 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_def_cfa_offset 16 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_offset ra, -16 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_offset s0, -12 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_offset s1, -8 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_offset s2, -4 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: mv s0, a0 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: mv s1, a0 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: mv s2, a0 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: add s0, s0, s1 +; RV32-ZCMP-NOZCMOP-NEXT: add a0, a0, s2 +; RV32-ZCMP-NOZCMOP-NEXT: add a0, a0, s0 +; RV32-ZCMP-NOZCMOP-NEXT: cm.pop {ra, s0-s2}, 16 +; RV32-ZCMP-NOZCMOP-NEXT: sspopchk ra +; RV32-ZCMP-NOZCMOP-NEXT: ret +; ; RV32-NOZCMOP-LABEL: f4_hw: ; RV32-NOZCMOP: # %bb.0: ; RV32-NOZCMOP-NEXT: sspush ra @@ -894,6 +1104,24 @@ define i32 @f5_hw() "hw-shadow-stack" nounwind { ; RV64-NEXT: addi sp, sp, 16 ; RV64-NEXT: ret ; +; RV64-ZCMP-LABEL: f5_hw: +; RV64-ZCMP: # %bb.0: +; RV64-ZCMP-NEXT: sspush ra +; RV64-ZCMP-NEXT: cm.push {ra}, -16 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: cm.pop {ra}, 16 +; RV64-ZCMP-NEXT: sspopchk ra +; RV64-ZCMP-NEXT: ret +; +; RV32-ZCMP-NOZCMOP-LABEL: f5_hw: +; RV32-ZCMP-NOZCMOP: # %bb.0: +; RV32-ZCMP-NOZCMOP-NEXT: sspush ra +; RV32-ZCMP-NOZCMOP-NEXT: cm.push {ra}, -16 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: cm.pop {ra}, 16 +; RV32-ZCMP-NOZCMOP-NEXT: sspopchk ra +; RV32-ZCMP-NOZCMOP-NEXT: ret +; ; RV32-NOZCMOP-LABEL: f5_hw: ; RV32-NOZCMOP: # %bb.0: ; RV32-NOZCMOP-NEXT: sspush ra @@ -951,6 +1179,14 @@ define void @f1_both() "hw-shadow-stack" shadowcallstack { ; RV64: # %bb.0: ; RV64-NEXT: ret ; +; RV64-ZCMP-LABEL: f1_both: +; RV64-ZCMP: # %bb.0: +; RV64-ZCMP-NEXT: ret +; +; RV32-ZCMP-NOZCMOP-LABEL: f1_both: +; RV32-ZCMP-NOZCMOP: # %bb.0: +; RV32-ZCMP-NOZCMOP-NEXT: ret +; ; RV32-NOZCMOP-LABEL: f1_both: ; RV32-NOZCMOP: # %bb.0: ; RV32-NOZCMOP-NEXT: ret @@ -978,6 +1214,14 @@ define void @f2_both() "hw-shadow-stack" shadowcallstack { ; RV64: # %bb.0: ; RV64-NEXT: tail foo ; +; RV64-ZCMP-LABEL: f2_both: +; RV64-ZCMP: # %bb.0: +; RV64-ZCMP-NEXT: tail foo +; +; RV32-ZCMP-NOZCMOP-LABEL: f2_both: +; RV32-ZCMP-NOZCMOP: # %bb.0: +; RV32-ZCMP-NOZCMOP-NEXT: tail foo +; ; RV32-ZICFISS-LABEL: f2_both: ; RV32-ZICFISS: # %bb.0: ; RV32-ZICFISS-NEXT: tail foo @@ -1028,6 +1272,28 @@ define i32 @f3_both() "hw-shadow-stack" shadowcallstack { ; RV64-NEXT: .cfi_restore gp ; RV64-NEXT: ret ; +; RV64-ZCMP-LABEL: f3_both: +; RV64-ZCMP: # %bb.0: +; RV64-ZCMP-NEXT: sspush ra +; RV64-ZCMP-NEXT: cm.push {ra}, -16 +; RV64-ZCMP-NEXT: .cfi_def_cfa_offset 16 +; RV64-ZCMP-NEXT: .cfi_offset ra, -8 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: cm.pop {ra}, 16 +; RV64-ZCMP-NEXT: sspopchk ra +; RV64-ZCMP-NEXT: ret +; +; RV32-ZCMP-NOZCMOP-LABEL: f3_both: +; RV32-ZCMP-NOZCMOP: # %bb.0: +; RV32-ZCMP-NOZCMOP-NEXT: sspush ra +; RV32-ZCMP-NOZCMOP-NEXT: cm.push {ra}, -16 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_def_cfa_offset 16 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_offset ra, -4 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: cm.pop {ra}, 16 +; RV32-ZCMP-NOZCMOP-NEXT: sspopchk ra +; RV32-ZCMP-NOZCMOP-NEXT: ret +; ; RV32-NOZCMOP-LABEL: f3_both: ; RV32-NOZCMOP: # %bb.0: ; RV32-NOZCMOP-NEXT: sspush ra @@ -1173,6 +1439,52 @@ define i32 @f4_both() "hw-shadow-stack" shadowcallstack { ; RV64-NEXT: .cfi_restore gp ; RV64-NEXT: ret ; +; RV64-ZCMP-LABEL: f4_both: +; RV64-ZCMP: # %bb.0: +; RV64-ZCMP-NEXT: sspush ra +; RV64-ZCMP-NEXT: cm.push {ra, s0-s2}, -32 +; RV64-ZCMP-NEXT: .cfi_def_cfa_offset 32 +; RV64-ZCMP-NEXT: .cfi_offset ra, -32 +; RV64-ZCMP-NEXT: .cfi_offset s0, -24 +; RV64-ZCMP-NEXT: .cfi_offset s1, -16 +; RV64-ZCMP-NEXT: .cfi_offset s2, -8 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: mv s0, a0 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: mv s1, a0 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: mv s2, a0 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: add s0, s0, s1 +; RV64-ZCMP-NEXT: add a0, a0, s2 +; RV64-ZCMP-NEXT: addw a0, a0, s0 +; RV64-ZCMP-NEXT: cm.pop {ra, s0-s2}, 32 +; RV64-ZCMP-NEXT: sspopchk ra +; RV64-ZCMP-NEXT: ret +; +; RV32-ZCMP-NOZCMOP-LABEL: f4_both: +; RV32-ZCMP-NOZCMOP: # %bb.0: +; RV32-ZCMP-NOZCMOP-NEXT: sspush ra +; RV32-ZCMP-NOZCMOP-NEXT: cm.push {ra, s0-s2}, -16 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_def_cfa_offset 16 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_offset ra, -16 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_offset s0, -12 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_offset s1, -8 +; RV32-ZCMP-NOZCMOP-NEXT: .cfi_offset s2, -4 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: mv s0, a0 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: mv s1, a0 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: mv s2, a0 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: add s0, s0, s1 +; RV32-ZCMP-NOZCMOP-NEXT: add a0, a0, s2 +; RV32-ZCMP-NOZCMOP-NEXT: add a0, a0, s0 +; RV32-ZCMP-NOZCMOP-NEXT: cm.pop {ra, s0-s2}, 16 +; RV32-ZCMP-NOZCMOP-NEXT: sspopchk ra +; RV32-ZCMP-NOZCMOP-NEXT: ret +; ; RV32-NOZCMOP-LABEL: f4_both: ; RV32-NOZCMOP: # %bb.0: ; RV32-NOZCMOP-NEXT: sspush ra @@ -1353,6 +1665,24 @@ define i32 @f5_both() "hw-shadow-stack" shadowcallstack nounwind { ; RV64-NEXT: addi gp, gp, -8 ; RV64-NEXT: ret ; +; RV64-ZCMP-LABEL: f5_both: +; RV64-ZCMP: # %bb.0: +; RV64-ZCMP-NEXT: sspush ra +; RV64-ZCMP-NEXT: cm.push {ra}, -16 +; RV64-ZCMP-NEXT: call bar +; RV64-ZCMP-NEXT: cm.pop {ra}, 16 +; RV64-ZCMP-NEXT: sspopchk ra +; RV64-ZCMP-NEXT: ret +; +; RV32-ZCMP-NOZCMOP-LABEL: f5_both: +; RV32-ZCMP-NOZCMOP: # %bb.0: +; RV32-ZCMP-NOZCMOP-NEXT: sspush ra +; RV32-ZCMP-NOZCMOP-NEXT: cm.push {ra}, -16 +; RV32-ZCMP-NOZCMOP-NEXT: call bar +; RV32-ZCMP-NOZCMOP-NEXT: cm.pop {ra}, 16 +; RV32-ZCMP-NOZCMOP-NEXT: sspopchk ra +; RV32-ZCMP-NOZCMOP-NEXT: ret +; ; RV32-NOZCMOP-LABEL: f5_both: ; RV32-NOZCMOP: # %bb.0: ; RV32-NOZCMOP-NEXT: sspush ra >From bd035e0ddc98d2988c951dbc6b517c3c86bbb5ef Mon Sep 17 00:00:00 2001 From: Nemanja Ivanovic <[email protected]> Date: Wed, 29 Jul 2026 17:53:36 +0200 Subject: [PATCH 2/2] [RISC-V] Fix assert after 255162a (#212791) The iterator passed-in may point to the end of the block which causes an assertion failure when attempting to inspect the MI it points to. Guard against this. (cherry picked from commit f24da9d03ba5d25c523e050da2ca3c4060ca23d5) --- llvm/lib/Target/RISCV/RISCVFrameLowering.cpp | 3 +- llvm/test/CodeGen/RISCV/epilog-crash.ll | 37 ++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 llvm/test/CodeGen/RISCV/epilog-crash.ll diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp index 516cb557feaba6..8eb20927fb8a08 100644 --- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp @@ -195,7 +195,8 @@ static void emitSCSEpilogue(MachineFunction &MF, MachineBasicBlock &MBB, return; // The shadow call stack popchk needs to happen after cm.pop that loads ra. - if (MI->getOpcode() == RISCV::CM_POP || MI->getOpcode() == RISCV::QC_CM_POP) + if (MI != MBB.end() && + (MI->getOpcode() == RISCV::CM_POP || MI->getOpcode() == RISCV::QC_CM_POP)) ++MI; const RISCVInstrInfo *TII = STI.getInstrInfo(); if (HasHWShadowStack) { diff --git a/llvm/test/CodeGen/RISCV/epilog-crash.ll b/llvm/test/CodeGen/RISCV/epilog-crash.ll new file mode 100644 index 00000000000000..ad5c8a7068b9f0 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/epilog-crash.ll @@ -0,0 +1,37 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 +; RUN: llc -mtriple=riscv64 < %s | FileCheck %s + +define double @test() #0 { +; CHECK-LABEL: test: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: addi gp, gp, 8 +; CHECK-NEXT: sd ra, -8(gp) +; CHECK-NEXT: .cfi_escape 0x16, 0x03, 0x02, 0x73, 0x78 # +; CHECK-NEXT: addi sp, sp, -16 +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; CHECK-NEXT: .cfi_offset ra, -8 +; CHECK-NEXT: li a0, 0 +; CHECK-NEXT: li a1, 0 +; CHECK-NEXT: jalr a0 +; CHECK-NEXT: ld ra, 8(sp) # 8-byte Folded Reload +; CHECK-NEXT: .cfi_restore ra +; CHECK-NEXT: addi sp, sp, 16 +; CHECK-NEXT: .cfi_def_cfa_offset 0 +; CHECK-NEXT: ld ra, -8(gp) +; CHECK-NEXT: addi gp, gp, -8 +; CHECK-NEXT: .cfi_restore gp +; CHECK-NEXT: li a0, 0 +; CHECK-NEXT: ret +entry: + br label %if.end.i + +if.end.i: ; preds = %entry + %call.i.i = tail call i32 null(i128 0) + br label %exit + +exit: ; preds = %if.end.i + ret double 0.000000e+00 +} + +attributes #0 = { shadowcallstack } _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
