[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