@@ -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.
126154static 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+
466518void 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