Skip to content

Commit 3492245

Browse files
lenarypgodeq
andauthored
[RISCV] QCI Interrupt Support (#129957)
This change adds support for `qci-nest` and `qci-nonest` interrupt attribute values. Both of these are machine-mode interrupts, which use instructions in Xqciint to push and pop A- and T-registers (and a few others) from the stack. In particular: - `qci-nonest` uses `qc.c.mienter` to save registers at the start of the function, and uses `qc.c.mileaveret` to restore those registers and return from the interrupt. - `qci-nest` uses `qc.c.mienter.nest` to save registers at the start of the function, and uses `qc.c.mileaveret` to restore those registers and return from the interrupt. - `qc.c.mienter` and `qc.c.mienter.nest` both push registers ra, s0 (fp), t0-t6, and a0-a10 onto the stack (as well as some CSRs for the interrupt context). The difference between these is that `qc.c.mienter.nest` re-enables M-mode interrupts. - `qc.c.mileaveret` will restore the registers that were saved by `qc.c.mienter(.nest)`, and return from the interrupt. These work for both standard M-mode interrupts and the non-maskable interrupt CSRs added by Xqciint. The `qc.c.mienter`, `qc.c.mienter.nest` and `qc.c.mileaveret` instructions are compatible with push and pop instructions, in as much as they (mostly) only spill the A- and T-registers, so we can use the `Zcmp` or `Xqccmp` instructions to spill the S-registers. This combination (`qci-(no)nest` and `Xqccmp`/`Zcmp`) is not implemented in this change. The `qc.c.mienter(.nest)` instructions have a specific register storage order so they preserve the frame pointer convention linked list past the current interrupt handler and into the interrupted code and frames if frame pointers are enabled. Co-authored-by: Pankaj Gode <[email protected]>
1 parent f3effc2 commit 3492245

15 files changed

+6035
-31
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2232,8 +2232,8 @@ def RISCVInterrupt : InheritableAttr, TargetSpecificAttr<TargetRISCV> {
22322232
let Spellings = [GCC<"interrupt">];
22332233
let Subjects = SubjectList<[Function]>;
22342234
let Args = [EnumArgument<"Interrupt", "InterruptType", /*is_string=*/true,
2235-
["supervisor", "machine"],
2236-
["supervisor", "machine"],
2235+
["supervisor", "machine", "qci-nest", "qci-nonest"],
2236+
["supervisor", "machine", "qcinest", "qcinonest"],
22372237
1>];
22382238
let ParseKind = "Interrupt";
22392239
let Documentation = [RISCVInterruptDocs];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2828,8 +2828,17 @@ targets. This attribute may be attached to a function definition and instructs
28282828
the backend to generate appropriate function entry/exit code so that it can be
28292829
used directly as an interrupt service routine.
28302830

2831-
Permissible values for this parameter are ``supervisor`` and ``machine``. If
2832-
there is no parameter, then it defaults to ``machine``.
2831+
Permissible values for this parameter are ``supervisor``, ``machine``,
2832+
``qci-nest`` and ``qci-nonest``. If there is no parameter, then it defaults to
2833+
``machine``.
2834+
2835+
The ``qci-nest`` and ``qci-nonest`` values require Qualcomm's Xqciint extension
2836+
and are used for Machine-mode Interrupts and Machine-mode Non-maskable
2837+
interrupts. These use the following instructions from Xqciint to save and
2838+
restore interrupt state to the stack -- the ``qci-nest`` value will use
2839+
``qc.c.mienter.nest`` and the ``qci-nonest`` value will use ``qc.c.mienter`` to
2840+
begin the interrupt handler. Both of these will use ``qc.c.mileaveret`` to
2841+
restore the state and return to the previous context.
28332842

28342843
Repeated interrupt attribute on the same declaration will cause a warning
28352844
to be emitted. In case of repeated declarations, the last one prevails.
@@ -2839,6 +2848,7 @@ https://gcc.gnu.org/onlinedocs/gcc/RISC-V-Function-Attributes.html
28392848
https://riscv.org/specifications/privileged-isa/
28402849
The RISC-V Instruction Set Manual Volume II: Privileged Architecture
28412850
Version 1.10.
2851+
https://github.com/quic/riscv-unified-db/releases/tag/Xqci-0.6
28422852
}];
28432853
}
28442854

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12637,8 +12637,9 @@ def err_riscv_builtin_requires_extension : Error<
1263712637
def err_riscv_builtin_invalid_lmul : Error<
1263812638
"LMUL argument must be in the range [0,3] or [5,7]">;
1263912639
def err_riscv_type_requires_extension : Error<
12640-
"RISC-V type %0 requires the '%1' extension"
12641-
>;
12640+
"RISC-V type %0 requires the '%1' extension">;
12641+
def err_riscv_attribute_interrupt_requires_extension : Error<
12642+
"RISC-V interrupt attribute '%0' requires extension '%1'">;
1264212643

1264312644
def err_std_source_location_impl_not_found : Error<
1264412645
"'std::source_location::__impl' was not found; it must be defined before '__builtin_source_location' is called">;

clang/lib/CodeGen/Targets/RISCV.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,12 @@ class RISCVTargetCodeGenInfo : public TargetCodeGenInfo {
833833
switch (Attr->getInterrupt()) {
834834
case RISCVInterruptAttr::supervisor: Kind = "supervisor"; break;
835835
case RISCVInterruptAttr::machine: Kind = "machine"; break;
836+
case RISCVInterruptAttr::qcinest:
837+
Kind = "qci-nest";
838+
break;
839+
case RISCVInterruptAttr::qcinonest:
840+
Kind = "qci-nonest";
841+
break;
836842
}
837843

838844
Fn->addFnAttr("interrupt", Kind);

clang/lib/Sema/SemaRISCV.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "clang/Sema/SemaRISCV.h"
1414
#include "clang/AST/ASTContext.h"
15+
#include "clang/AST/Attr.h"
1516
#include "clang/AST/Decl.h"
1617
#include "clang/Basic/Builtins.h"
1718
#include "clang/Basic/TargetBuiltins.h"
@@ -1475,6 +1476,26 @@ void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
14751476
return;
14761477
}
14771478

1479+
switch (Kind) {
1480+
default:
1481+
break;
1482+
case RISCVInterruptAttr::InterruptType::qcinest:
1483+
case RISCVInterruptAttr::InterruptType::qcinonest: {
1484+
const TargetInfo &TI = getASTContext().getTargetInfo();
1485+
llvm::StringMap<bool> FunctionFeatureMap;
1486+
getASTContext().getFunctionFeatureMap(FunctionFeatureMap,
1487+
dyn_cast<FunctionDecl>(D));
1488+
1489+
if (!TI.hasFeature("experimental-xqciint") &&
1490+
!FunctionFeatureMap.lookup("experimental-xqciint")) {
1491+
Diag(AL.getLoc(), diag::err_riscv_attribute_interrupt_requires_extension)
1492+
<< Str << "Xqciint";
1493+
return;
1494+
}
1495+
break;
1496+
}
1497+
};
1498+
14781499
D->addAttr(::new (getASTContext())
14791500
RISCVInterruptAttr(getASTContext(), AL, Kind));
14801501
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// RUN: %clang_cc1 -triple riscv32-unknown-elf -target-feature +experimental-xqciint -emit-llvm -DCHECK_IR < %s| FileCheck %s
2+
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -target-feature +experimental-xqciint -verify=enabled,both -fsyntax-only
3+
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -verify=disabled,both -fsyntax-only
4+
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -target-feature -experimental-xqciint -verify=disabled,both -fsyntax-only
5+
// RUN: %clang_cc1 %s -triple riscv64-unknown-elf -verify=disabled,both -fsyntax-only -DRV64
6+
7+
#if defined(CHECK_IR)
8+
// Test for QCI extension's interrupt attribute support
9+
// CHECK-LABEL: @foo_nest_interrupt() #0
10+
// CHECK: ret void
11+
__attribute__((interrupt("qci-nest")))
12+
void foo_nest_interrupt(void) {}
13+
14+
// CHECK-LABEL: @foo_nonnest_interrupt() #1
15+
// CHECK: ret void
16+
__attribute__((interrupt("qci-nonest")))
17+
void foo_nonnest_interrupt(void) {}
18+
19+
// CHECK: attributes #0
20+
// CHECK: "interrupt"="qci-nest"
21+
// CHECK: attributes #1
22+
// CHECK: "interrupt"="qci-nonest"
23+
#else
24+
// Test for QCI extension's interrupt attribute support
25+
__attribute__((interrupt("qci-est"))) void foo_nest1(void) {} // both-warning {{'interrupt' attribute argument not supported: qci-est}}
26+
__attribute__((interrupt("qci-noest"))) void foo_nonest1(void) {} // both-warning {{'interrupt' attribute argument not supported: qci-noest}}
27+
__attribute__((interrupt(1))) void foo_nest2(void) {} // both-error {{expected string literal as argument of 'interrupt' attribute}}
28+
__attribute__((interrupt("qci-nest", "qci-nonest"))) void foo1(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
29+
__attribute__((interrupt("qci-nonest", "qci-nest"))) void foo2(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
30+
__attribute__((interrupt("", "qci-nonest"))) void foo3(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
31+
__attribute__((interrupt("", "qci-nest"))) void foo4(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
32+
__attribute__((interrupt("qci-nonest", 1))) void foo5(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
33+
__attribute__((interrupt("qci-nest", 1))) void foo6(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
34+
35+
__attribute__((interrupt("qci-nest"))) void foo_nest(void) {} // disabled-error {{RISC-V interrupt attribute 'qci-nest' requires extension 'Xqciint'}}
36+
__attribute__((interrupt("qci-nonest"))) void foo_nonest(void) {} // disabled-error {{RISC-V interrupt attribute 'qci-nonest' requires extension 'Xqciint'}}
37+
38+
// This tests the errors for the qci interrupts when using
39+
// `__attribute__((target(...)))` - but they fail on RV64, because you cannot
40+
// enable xqciint on rv64.
41+
#if __riscv_xlen == 32
42+
__attribute__((target("arch=+xqciint"))) __attribute__((interrupt("qci-nest"))) void foo_nest_xqciint(void) {}
43+
__attribute__((target("arch=+xqciint"))) __attribute__((interrupt("qci-nonest"))) void foo_nonest_xqciint(void) {}
44+
45+
// The attribute order is important, the interrupt attribute must come after the
46+
// target attribute
47+
__attribute__((interrupt("qci-nest"))) __attribute__((target("arch=+xqciint"))) void foo_nest_xqciint2(void) {} // disabled-error {{RISC-V interrupt attribute 'qci-nest' requires extension 'Xqciint'}}
48+
__attribute__((interrupt("qci-nonest"))) __attribute__((target("arch=+xqciint"))) void foo_nonest_xqciint2(void) {} // disabled-error {{RISC-V interrupt attribute 'qci-nonest' requires extension 'Xqciint'}}
49+
#endif
50+
51+
#endif

llvm/lib/Target/RISCV/RISCVFrameLowering.cpp

Lines changed: 116 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,34 @@ static const MCPhysReg FixedCSRFIMap[] = {
121121
/*s8*/ RISCV::X24, /*s9*/ RISCV::X25, /*s10*/ RISCV::X26,
122122
/*s11*/ RISCV::X27};
123123

124+
// The number of stack bytes allocated by `QC.C.MIENTER(.NEST)` and popped by
125+
// `QC.C.MILEAVERET`.
126+
static constexpr uint64_t QCIInterruptPushAmount = 96;
127+
128+
static const std::pair<MCPhysReg, int8_t> FixedCSRFIQCIInterruptMap[] = {
129+
/* -1 is a gap for mepc/qc.mnepc */
130+
{/*fp*/ FPReg, -2},
131+
/* -3 is a gap for mcause */
132+
{/*ra*/ RAReg, -4},
133+
/* -5 is reserved */
134+
{/*t0*/ RISCV::X5, -6},
135+
{/*t1*/ RISCV::X6, -7},
136+
{/*t2*/ RISCV::X7, -8},
137+
{/*a0*/ RISCV::X10, -9},
138+
{/*a1*/ RISCV::X11, -10},
139+
{/*a2*/ RISCV::X12, -11},
140+
{/*a3*/ RISCV::X13, -12},
141+
{/*a4*/ RISCV::X14, -13},
142+
{/*a5*/ RISCV::X15, -14},
143+
{/*a6*/ RISCV::X16, -15},
144+
{/*a7*/ RISCV::X17, -16},
145+
{/*t3*/ RISCV::X28, -17},
146+
{/*t4*/ RISCV::X29, -18},
147+
{/*t5*/ RISCV::X30, -19},
148+
{/*t6*/ RISCV::X31, -20},
149+
/* -21, -22, -23, -24 are reserved */
150+
};
151+
124152
// For now we use x3, a.k.a gp, as pointer to shadow call stack.
125153
// User should not use x3 in their asm.
126154
static void emitSCSPrologue(MachineFunction &MF, MachineBasicBlock &MBB,
@@ -382,6 +410,10 @@ void RISCVFrameLowering::determineFrameLayout(MachineFunction &MF) const {
382410
// Get the number of bytes to allocate from the FrameInfo.
383411
uint64_t FrameSize = MFI.getStackSize();
384412

413+
// QCI Interrupts use at least 96 bytes of stack space
414+
if (RVFI->useQCIInterrupt(MF))
415+
FrameSize = std::max(FrameSize, QCIInterruptPushAmount);
416+
385417
// Get the alignment.
386418
Align StackAlign = getStackAlign();
387419

@@ -463,6 +495,26 @@ getPushOrLibCallsSavedInfo(const MachineFunction &MF,
463495
return PushOrLibCallsCSI;
464496
}
465497

498+
static SmallVector<CalleeSavedInfo, 8>
499+
getQCISavedInfo(const MachineFunction &MF,
500+
const std::vector<CalleeSavedInfo> &CSI) {
501+
auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
502+
503+
SmallVector<CalleeSavedInfo, 8> QCIInterruptCSI;
504+
if (!RVFI->useQCIInterrupt(MF))
505+
return QCIInterruptCSI;
506+
507+
for (const auto &CS : CSI) {
508+
const auto *FII = llvm::find_if(FixedCSRFIQCIInterruptMap, [&](auto P) {
509+
return P.first == CS.getReg();
510+
});
511+
if (FII != std::end(FixedCSRFIQCIInterruptMap))
512+
QCIInterruptCSI.push_back(CS);
513+
}
514+
515+
return QCIInterruptCSI;
516+
}
517+
466518
void RISCVFrameLowering::allocateAndProbeStackForRVV(
467519
MachineFunction &MF, MachineBasicBlock &MBB,
468520
MachineBasicBlock::iterator MBBI, const DebugLoc &DL, int64_t Amount,
@@ -896,8 +948,16 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
896948
RealStackSize = FirstSPAdjustAmount;
897949
}
898950

899-
if (RVFI->isPushable(MF) && FirstFrameSetup != MBB.end() &&
900-
isPush(FirstFrameSetup->getOpcode())) {
951+
if (RVFI->useQCIInterrupt(MF)) {
952+
unsigned CFIIndex = MF.addFrameInst(
953+
MCCFIInstruction::cfiDefCfaOffset(nullptr, QCIInterruptPushAmount));
954+
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
955+
.addCFIIndex(CFIIndex)
956+
.setMIFlag(MachineInstr::FrameSetup);
957+
958+
emitCFIForCSI<CFISaveRegisterEmitter>(MBB, MBBI, getQCISavedInfo(MF, CSI));
959+
} else if (RVFI->isPushable(MF) && FirstFrameSetup != MBB.end() &&
960+
isPush(FirstFrameSetup->getOpcode())) {
901961
// Use available stack adjustment in push instruction to allocate additional
902962
// stack space. Align the stack size down to a multiple of 16. This is
903963
// needed for RVE.
@@ -1247,7 +1307,7 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
12471307

12481308
// Deallocate stack if StackSize isn't a zero yet
12491309
if (StackSize != 0)
1250-
deallocateStack(MF, MBB, MBBI, DL, StackSize, 0);
1310+
deallocateStack(MF, MBB, MBBI, DL, StackSize, RealStackSize - StackSize);
12511311

12521312
// Emit epilogue for shadow call stack.
12531313
emitSCSEpilogue(MF, MBB, MBBI, DL);
@@ -1737,9 +1797,9 @@ RISCVFrameLowering::getFirstSPAdjustAmount(const MachineFunction &MF) const {
17371797
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
17381798
uint64_t StackSize = getStackSizeWithRVVPadding(MF);
17391799

1740-
// Disable SplitSPAdjust if save-restore libcall is used. The callee-saved
1741-
// registers will be pushed by the save-restore libcalls, so we don't have to
1742-
// split the SP adjustment in this case.
1800+
// Disable SplitSPAdjust if save-restore libcall, push/pop or QCI interrupts
1801+
// are used. The callee-saved registers will be pushed by the save-restore
1802+
// libcalls, so we don't have to split the SP adjustment in this case.
17431803
if (RVFI->getReservedSpillsSize())
17441804
return 0;
17451805

@@ -1807,8 +1867,9 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
18071867
return true;
18081868

18091869
auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
1810-
1811-
if (RVFI->isPushable(MF)) {
1870+
if (RVFI->useQCIInterrupt(MF)) {
1871+
RVFI->setQCIInterruptStackSize(QCIInterruptPushAmount);
1872+
} else if (RVFI->isPushable(MF)) {
18121873
// Determine how many GPRs we need to push and save it to RVFI.
18131874
unsigned PushedRegNum = getNumPushPopRegs(CSI);
18141875
if (PushedRegNum) {
@@ -1825,8 +1886,20 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
18251886
const TargetRegisterClass *RC = RegInfo->getMinimalPhysRegClass(Reg);
18261887
unsigned Size = RegInfo->getSpillSize(*RC);
18271888

1828-
// This might need a fixed stack slot.
1829-
if (RVFI->useSaveRestoreLibCalls(MF) || RVFI->isPushable(MF)) {
1889+
if (RVFI->useQCIInterrupt(MF)) {
1890+
const auto *FFI = llvm::find_if(FixedCSRFIQCIInterruptMap, [&](auto P) {
1891+
return P.first == CS.getReg();
1892+
});
1893+
if (FFI != std::end(FixedCSRFIQCIInterruptMap)) {
1894+
int64_t Offset = FFI->second * (int64_t)Size;
1895+
1896+
int FrameIdx = MFI.CreateFixedSpillStackObject(Size, Offset);
1897+
assert(FrameIdx < 0);
1898+
CS.setFrameIdx(FrameIdx);
1899+
continue;
1900+
}
1901+
// TODO: QCI Interrupt + Push/Pop
1902+
} else if (RVFI->useSaveRestoreLibCalls(MF) || RVFI->isPushable(MF)) {
18301903
const auto *FII = llvm::find_if(
18311904
FixedCSRFIMap, [&](MCPhysReg P) { return P == CS.getReg(); });
18321905
unsigned RegNum = std::distance(std::begin(FixedCSRFIMap), FII);
@@ -1862,7 +1935,12 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
18621935
MFI.setStackID(FrameIdx, TargetStackID::ScalableVector);
18631936
}
18641937

1865-
if (RVFI->isPushable(MF)) {
1938+
if (RVFI->useQCIInterrupt(MF)) {
1939+
// Allocate a fixed object that covers the entire QCI stack allocation,
1940+
// because there are gaps which are reserved for future use.
1941+
MFI.CreateFixedSpillStackObject(
1942+
QCIInterruptPushAmount, -static_cast<int64_t>(QCIInterruptPushAmount));
1943+
} else if (RVFI->isPushable(MF)) {
18661944
// Allocate a fixed object that covers all the registers that are pushed.
18671945
if (unsigned PushedRegs = RVFI->getRVPushRegs()) {
18681946
int64_t PushedRegsBytes =
@@ -1892,9 +1970,22 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
18921970
if (MI != MBB.end() && !MI->isDebugInstr())
18931971
DL = MI->getDebugLoc();
18941972

1895-
// Emit CM.PUSH with base SPimm & evaluate Push stack
18961973
RISCVMachineFunctionInfo *RVFI = MF->getInfo<RISCVMachineFunctionInfo>();
1897-
if (RVFI->isPushable(*MF)) {
1974+
if (RVFI->useQCIInterrupt(*MF)) {
1975+
// Emit QC.C.MIENTER(.NEST)
1976+
BuildMI(
1977+
MBB, MI, DL,
1978+
TII.get(RVFI->getInterruptStackKind(*MF) ==
1979+
RISCVMachineFunctionInfo::InterruptStackKind::QCINest
1980+
? RISCV::QC_C_MIENTER_NEST
1981+
: RISCV::QC_C_MIENTER))
1982+
.setMIFlag(MachineInstr::FrameSetup);
1983+
1984+
for (auto [Reg, _Offset] : FixedCSRFIQCIInterruptMap)
1985+
MBB.addLiveIn(Reg);
1986+
// TODO: Handle QCI Interrupt + Push/Pop
1987+
} else if (RVFI->isPushable(*MF)) {
1988+
// Emit CM.PUSH with base SPimm & evaluate Push stack
18981989
unsigned PushedRegNum = RVFI->getRVPushRegs();
18991990
if (PushedRegNum > 0) {
19001991
// Use encoded number to represent registers to spill.
@@ -2051,7 +2142,13 @@ bool RISCVFrameLowering::restoreCalleeSavedRegisters(
20512142
loadRegFromStackSlot(UnmanagedCSI);
20522143

20532144
RISCVMachineFunctionInfo *RVFI = MF->getInfo<RISCVMachineFunctionInfo>();
2054-
if (RVFI->isPushable(*MF)) {
2145+
if (RVFI->useQCIInterrupt(*MF)) {
2146+
// Don't emit anything here because restoration is handled by
2147+
// QC.C.MILEAVERET which we already inserted to return.
2148+
assert(MI->getOpcode() == RISCV::QC_C_MILEAVERET &&
2149+
"Unexpected QCI Interrupt Return Instruction");
2150+
// TODO: Handle QCI + Push/Pop
2151+
} else if (RVFI->isPushable(*MF)) {
20552152
unsigned PushedRegNum = RVFI->getRVPushRegs();
20562153
if (PushedRegNum > 0) {
20572154
unsigned Opcode = getPopOpcode(RVFI->getPushPopKind(*MF));
@@ -2116,6 +2213,11 @@ bool RISCVFrameLowering::canUseAsEpilogue(const MachineBasicBlock &MBB) const {
21162213
MachineBasicBlock *TmpMBB = const_cast<MachineBasicBlock *>(&MBB);
21172214
const auto *RVFI = MF->getInfo<RISCVMachineFunctionInfo>();
21182215

2216+
// We do not want QC.C.MILEAVERET to be subject to shrink-wrapping - it must
2217+
// come in the final block of its function as it both pops and returns.
2218+
if (RVFI->useQCIInterrupt(*MF))
2219+
return MBB.succ_empty();
2220+
21192221
if (!RVFI->useSaveRestoreLibCalls(*MF))
21202222
return true;
21212223

0 commit comments

Comments
 (0)