[llvm] [RISCV] Disable shrink wrapping for SiFive CLIC preemptible handlers (PR #218347)
Zeyi Xu via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 26 23:01:46 PDT 2026
https://github.com/zeyi2 updated https://github.com/llvm/llvm-project/pull/218347
>From 58b33cc8d6bd1187e521acd361efa34ace451f1d Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Thu, 27 Aug 2026 01:09:47 +0800
Subject: [PATCH 1/2] Add testcase first
---
.../CodeGen/RISCV/interrupt-shrink-wrap.ll | 175 ++++++++++++++++++
1 file changed, 175 insertions(+)
create mode 100644 llvm/test/CodeGen/RISCV/interrupt-shrink-wrap.ll
diff --git a/llvm/test/CodeGen/RISCV/interrupt-shrink-wrap.ll b/llvm/test/CodeGen/RISCV/interrupt-shrink-wrap.ll
new file mode 100644
index 0000000000000..ab4a775966ea2
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/interrupt-shrink-wrap.ll
@@ -0,0 +1,175 @@
+; RUN: split-file %s %t
+; RUN: llc -mtriple=riscv32 -mattr=+smrnmi -verify-machineinstrs \
+; RUN: < %t/standard.ll | FileCheck %t/standard.ll
+; RUN: llc -mtriple=riscv64 -mattr=+smrnmi -verify-machineinstrs \
+; RUN: < %t/standard.ll | FileCheck %t/standard.ll
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-xsfmclic \
+; RUN: -verify-machineinstrs < %t/sifive.ll | FileCheck %t/sifive.ll
+; RUN: llc -mtriple=riscv64 -mattr=+experimental-xsfmclic \
+; RUN: -verify-machineinstrs < %t/sifive.ll | FileCheck %t/sifive.ll
+; RUN: llc -mtriple=riscv32 -mattr=+xqciint -verify-machineinstrs \
+; RUN: < %t/qci.ll | FileCheck %t/qci.ll
+
+;--- standard.ll
+
+declare ptr @llvm.thread.pointer()
+declare void @callee()
+
+define void @machine() "interrupt"="machine" {
+; CHECK-LABEL: machine:
+; CHECK: # %bb.0:
+; CHECK: beqz tp,
+; CHECK: addi sp, sp,
+entry:
+ %tp = call ptr @llvm.thread.pointer()
+ %isnull = icmp eq ptr %tp, null
+ br i1 %isnull, label %cold, label %return
+
+return:
+ ret void
+
+cold:
+ call void @callee()
+ ret void
+}
+
+define void @supervisor() "interrupt"="supervisor" {
+; CHECK-LABEL: supervisor:
+; CHECK: # %bb.0:
+; CHECK: beqz tp,
+; CHECK: addi sp, sp,
+entry:
+ %tp = call ptr @llvm.thread.pointer()
+ %isnull = icmp eq ptr %tp, null
+ br i1 %isnull, label %cold, label %return
+
+return:
+ ret void
+
+cold:
+ call void @callee()
+ ret void
+}
+
+define void @rnmi() "interrupt"="rnmi" {
+; CHECK-LABEL: rnmi:
+; CHECK: # %bb.0:
+; CHECK: beqz tp,
+; CHECK: addi sp, sp,
+entry:
+ %tp = call ptr @llvm.thread.pointer()
+ %isnull = icmp eq ptr %tp, null
+ br i1 %isnull, label %cold, label %return
+
+return:
+ ret void
+
+cold:
+ call void @callee()
+ ret void
+}
+
+;--- sifive.ll
+
+declare ptr @llvm.thread.pointer()
+declare void @callee()
+
+define void @sifive_stack_swap() "interrupt"="SiFive-CLIC-stack-swap" {
+; CHECK-LABEL: sifive_stack_swap:
+; CHECK: # %bb.0:
+; CHECK: beqz tp,
+; CHECK: csrrw sp, sf.mscratchcsw, sp
+; CHECK-NEXT: addi sp, sp,
+entry:
+ %tp = call ptr @llvm.thread.pointer()
+ %isnull = icmp eq ptr %tp, null
+ br i1 %isnull, label %cold, label %return
+
+return:
+ ret void
+
+cold:
+ call void @callee()
+ ret void
+}
+
+define void @sifive_preemptible() "interrupt"="SiFive-CLIC-preemptible" {
+; CHECK-LABEL: sifive_preemptible:
+; CHECK: # %bb.0:
+; CHECK: beqz tp,
+; CHECK: csrsi mstatus, 8
+entry:
+ %tp = call ptr @llvm.thread.pointer()
+ %isnull = icmp eq ptr %tp, null
+ br i1 %isnull, label %cold, label %return
+
+return:
+ ret void
+
+cold:
+ call void @callee()
+ ret void
+}
+
+define void @sifive_preemptible_stack_swap() "interrupt"="SiFive-CLIC-preemptible-stack-swap" {
+; CHECK-LABEL: sifive_preemptible_stack_swap:
+; CHECK: # %bb.0:
+; CHECK: beqz tp,
+; CHECK: csrrw sp, sf.mscratchcsw, sp
+; CHECK: csrsi mstatus, 8
+entry:
+ %tp = call ptr @llvm.thread.pointer()
+ %isnull = icmp eq ptr %tp, null
+ br i1 %isnull, label %cold, label %return
+
+return:
+ ret void
+
+cold:
+ call void @callee()
+ ret void
+}
+
+;--- qci.ll
+
+declare ptr @llvm.thread.pointer()
+declare void @panic() noreturn
+declare void @llvm.trap() cold noreturn nounwind
+
+define void @qci_nest() noreturn "interrupt"="qci-nest" {
+; CHECK-LABEL: qci_nest:
+; CHECK: # %bb.0:
+; CHECK: bnez tp,
+; CHECK: qc.c.mienter.nest
+entry:
+ %tp = call ptr @llvm.thread.pointer()
+ %isnull = icmp eq ptr %tp, null
+ br i1 %isnull, label %panic, label %trap
+
+trap:
+ call void @llvm.trap()
+ unreachable
+
+panic:
+ call void @panic()
+ unreachable
+}
+
+define void @qci_nonest() noreturn "interrupt"="qci-nonest" {
+; CHECK-LABEL: qci_nonest:
+; CHECK: # %bb.0:
+; CHECK: bnez tp,
+; CHECK: qc.c.mienter
+entry:
+ %tp = call ptr @llvm.thread.pointer()
+ %isnull = icmp eq ptr %tp, null
+ br i1 %isnull, label %panic, label %trap
+
+trap:
+ call void @llvm.trap()
+ unreachable
+
+panic:
+ call void @panic()
+ unreachable
+}
>From 536edece7d43aab39faed0a2b976cb34a7fb9592 Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Thu, 27 Aug 2026 01:22:08 +0800
Subject: [PATCH 2/2] apply fix and update previous test file
---
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp | 11 ++++++-----
llvm/test/CodeGen/RISCV/interrupt-shrink-wrap.ll | 14 +++++++-------
2 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 35a36497d4f65..cd2220d6c8baa 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -2651,6 +2651,12 @@ bool RISCVFrameLowering::enableShrinkWrapping(const MachineFunction &MF) const {
if (MF.getFunction().hasOptNone())
return false;
+ // QCI and SiFive CLIC interrupt entry sequences must precede all handler
+ // code.
+ const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
+ if (RVFI->useQCIInterrupt(MF) || RVFI->useSiFiveInterrupt(MF))
+ return false;
+
return true;
}
@@ -2687,11 +2693,6 @@ bool RISCVFrameLowering::canUseAsEpilogue(const MachineBasicBlock &MBB) const {
MachineBasicBlock *TmpMBB = const_cast<MachineBasicBlock *>(&MBB);
const auto *RVFI = MF->getInfo<RISCVMachineFunctionInfo>();
- // We do not want QC.C.MILEAVERET to be subject to shrink-wrapping - it must
- // come in the final block of its function as it both pops and returns.
- if (RVFI->useQCIInterrupt(*MF))
- return MBB.succ_empty();
-
if (!RVFI->useSaveRestoreLibCalls(*MF))
return true;
diff --git a/llvm/test/CodeGen/RISCV/interrupt-shrink-wrap.ll b/llvm/test/CodeGen/RISCV/interrupt-shrink-wrap.ll
index ab4a775966ea2..90b849b0efbeb 100644
--- a/llvm/test/CodeGen/RISCV/interrupt-shrink-wrap.ll
+++ b/llvm/test/CodeGen/RISCV/interrupt-shrink-wrap.ll
@@ -77,9 +77,9 @@ declare void @callee()
define void @sifive_stack_swap() "interrupt"="SiFive-CLIC-stack-swap" {
; CHECK-LABEL: sifive_stack_swap:
; CHECK: # %bb.0:
-; CHECK: beqz tp,
-; CHECK: csrrw sp, sf.mscratchcsw, sp
+; CHECK-NEXT: csrrw sp, sf.mscratchcsw, sp
; CHECK-NEXT: addi sp, sp,
+; CHECK: bnez tp,
entry:
%tp = call ptr @llvm.thread.pointer()
%isnull = icmp eq ptr %tp, null
@@ -96,8 +96,8 @@ cold:
define void @sifive_preemptible() "interrupt"="SiFive-CLIC-preemptible" {
; CHECK-LABEL: sifive_preemptible:
; CHECK: # %bb.0:
-; CHECK: beqz tp,
; CHECK: csrsi mstatus, 8
+; CHECK: bnez tp,
entry:
%tp = call ptr @llvm.thread.pointer()
%isnull = icmp eq ptr %tp, null
@@ -114,9 +114,9 @@ cold:
define void @sifive_preemptible_stack_swap() "interrupt"="SiFive-CLIC-preemptible-stack-swap" {
; CHECK-LABEL: sifive_preemptible_stack_swap:
; CHECK: # %bb.0:
-; CHECK: beqz tp,
-; CHECK: csrrw sp, sf.mscratchcsw, sp
+; CHECK-NEXT: csrrw sp, sf.mscratchcsw, sp
; CHECK: csrsi mstatus, 8
+; CHECK: bnez tp,
entry:
%tp = call ptr @llvm.thread.pointer()
%isnull = icmp eq ptr %tp, null
@@ -139,8 +139,8 @@ declare void @llvm.trap() cold noreturn nounwind
define void @qci_nest() noreturn "interrupt"="qci-nest" {
; CHECK-LABEL: qci_nest:
; CHECK: # %bb.0:
+; CHECK-NEXT: qc.c.mienter.nest
; CHECK: bnez tp,
-; CHECK: qc.c.mienter.nest
entry:
%tp = call ptr @llvm.thread.pointer()
%isnull = icmp eq ptr %tp, null
@@ -158,8 +158,8 @@ panic:
define void @qci_nonest() noreturn "interrupt"="qci-nonest" {
; CHECK-LABEL: qci_nonest:
; CHECK: # %bb.0:
+; CHECK-NEXT: qc.c.mienter
; CHECK: bnez tp,
-; CHECK: qc.c.mienter
entry:
%tp = call ptr @llvm.thread.pointer()
%isnull = icmp eq ptr %tp, null
More information about the llvm-commits
mailing list