@@ -121,6 +121,34 @@ static const MCPhysReg FixedCSRFIMap[] = {
121
121
/* s8*/ RISCV::X24, /* s9*/ RISCV::X25, /* s10*/ RISCV::X26,
122
122
/* s11*/ RISCV::X27};
123
123
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
+
124
152
// For now we use x3, a.k.a gp, as pointer to shadow call stack.
125
153
// User should not use x3 in their asm.
126
154
static void emitSCSPrologue (MachineFunction &MF, MachineBasicBlock &MBB,
@@ -382,6 +410,10 @@ void RISCVFrameLowering::determineFrameLayout(MachineFunction &MF) const {
382
410
// Get the number of bytes to allocate from the FrameInfo.
383
411
uint64_t FrameSize = MFI.getStackSize ();
384
412
413
+ // QCI Interrupts use at least 96 bytes of stack space
414
+ if (RVFI->useQCIInterrupt (MF))
415
+ FrameSize = std::max (FrameSize, QCIInterruptPushAmount);
416
+
385
417
// Get the alignment.
386
418
Align StackAlign = getStackAlign ();
387
419
@@ -463,6 +495,26 @@ getPushOrLibCallsSavedInfo(const MachineFunction &MF,
463
495
return PushOrLibCallsCSI;
464
496
}
465
497
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
+
466
518
void RISCVFrameLowering::allocateAndProbeStackForRVV (
467
519
MachineFunction &MF, MachineBasicBlock &MBB,
468
520
MachineBasicBlock::iterator MBBI, const DebugLoc &DL, int64_t Amount,
@@ -896,8 +948,16 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
896
948
RealStackSize = FirstSPAdjustAmount;
897
949
}
898
950
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 ())) {
901
961
// Use available stack adjustment in push instruction to allocate additional
902
962
// stack space. Align the stack size down to a multiple of 16. This is
903
963
// needed for RVE.
@@ -1247,7 +1307,7 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
1247
1307
1248
1308
// Deallocate stack if StackSize isn't a zero yet
1249
1309
if (StackSize != 0 )
1250
- deallocateStack (MF, MBB, MBBI, DL, StackSize, 0 );
1310
+ deallocateStack (MF, MBB, MBBI, DL, StackSize, RealStackSize - StackSize );
1251
1311
1252
1312
// Emit epilogue for shadow call stack.
1253
1313
emitSCSEpilogue (MF, MBB, MBBI, DL);
@@ -1737,9 +1797,9 @@ RISCVFrameLowering::getFirstSPAdjustAmount(const MachineFunction &MF) const {
1737
1797
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo ();
1738
1798
uint64_t StackSize = getStackSizeWithRVVPadding (MF);
1739
1799
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.
1743
1803
if (RVFI->getReservedSpillsSize ())
1744
1804
return 0 ;
1745
1805
@@ -1807,8 +1867,9 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
1807
1867
return true ;
1808
1868
1809
1869
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)) {
1812
1873
// Determine how many GPRs we need to push and save it to RVFI.
1813
1874
unsigned PushedRegNum = getNumPushPopRegs (CSI);
1814
1875
if (PushedRegNum) {
@@ -1825,8 +1886,20 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
1825
1886
const TargetRegisterClass *RC = RegInfo->getMinimalPhysRegClass (Reg);
1826
1887
unsigned Size = RegInfo->getSpillSize (*RC);
1827
1888
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)) {
1830
1903
const auto *FII = llvm::find_if (
1831
1904
FixedCSRFIMap, [&](MCPhysReg P) { return P == CS.getReg (); });
1832
1905
unsigned RegNum = std::distance (std::begin (FixedCSRFIMap), FII);
@@ -1862,7 +1935,12 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
1862
1935
MFI.setStackID (FrameIdx, TargetStackID::ScalableVector);
1863
1936
}
1864
1937
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)) {
1866
1944
// Allocate a fixed object that covers all the registers that are pushed.
1867
1945
if (unsigned PushedRegs = RVFI->getRVPushRegs ()) {
1868
1946
int64_t PushedRegsBytes =
@@ -1892,9 +1970,22 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
1892
1970
if (MI != MBB.end () && !MI->isDebugInstr ())
1893
1971
DL = MI->getDebugLoc ();
1894
1972
1895
- // Emit CM.PUSH with base SPimm & evaluate Push stack
1896
1973
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
1898
1989
unsigned PushedRegNum = RVFI->getRVPushRegs ();
1899
1990
if (PushedRegNum > 0 ) {
1900
1991
// Use encoded number to represent registers to spill.
@@ -2051,7 +2142,13 @@ bool RISCVFrameLowering::restoreCalleeSavedRegisters(
2051
2142
loadRegFromStackSlot (UnmanagedCSI);
2052
2143
2053
2144
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)) {
2055
2152
unsigned PushedRegNum = RVFI->getRVPushRegs ();
2056
2153
if (PushedRegNum > 0 ) {
2057
2154
unsigned Opcode = getPopOpcode (RVFI->getPushPopKind (*MF));
@@ -2116,6 +2213,11 @@ bool RISCVFrameLowering::canUseAsEpilogue(const MachineBasicBlock &MBB) const {
2116
2213
MachineBasicBlock *TmpMBB = const_cast <MachineBasicBlock *>(&MBB);
2117
2214
const auto *RVFI = MF->getInfo <RISCVMachineFunctionInfo>();
2118
2215
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
+
2119
2221
if (!RVFI->useSaveRestoreLibCalls (*MF))
2120
2222
return true ;
2121
2223
0 commit comments