@@ -568,6 +568,18 @@ getPushOrLibCallsSavedInfo(const MachineFunction &MF,
568568 return PushOrLibCallsCSI;
569569
570570 for (const auto &CS : CSI) {
571+ if (RVFI->useQCIInterrupt (MF)) {
572+ // Some registers are saved by both `QC.C.MIENTER(.NEST)` and
573+ // `QC.CM.PUSH(FP)`. In these cases, prioritise the CFI info that points
574+ // to the versions saved by `QC.C.MIENTER(.NEST)` which is what FP
575+ // unwinding would use.
576+ const auto *FII = llvm::find_if (FixedCSRFIQCIInterruptMap, [&](auto P) {
577+ return P.first == CS.getReg ();
578+ });
579+ if (FII != std::end (FixedCSRFIQCIInterruptMap))
580+ continue ;
581+ }
582+
571583 const auto *FII = llvm::find_if (
572584 FixedCSRFIMap, [&](MCPhysReg P) { return P == CS.getReg (); });
573585 if (FII != std::end (FixedCSRFIMap))
@@ -866,12 +878,12 @@ static bool isPop(unsigned Opcode) {
866878}
867879
868880static unsigned getPushOpcode (RISCVMachineFunctionInfo::PushPopKind Kind,
869- bool HasFP ) {
881+ bool UpdateFP ) {
870882 switch (Kind) {
871883 case RISCVMachineFunctionInfo::PushPopKind::StdExtZcmp:
872884 return RISCV::CM_PUSH;
873885 case RISCVMachineFunctionInfo::PushPopKind::VendorXqccmp:
874- return HasFP ? RISCV::QC_CM_PUSHFP : RISCV::QC_CM_PUSH;
886+ return UpdateFP ? RISCV::QC_CM_PUSHFP : RISCV::QC_CM_PUSH;
875887 default :
876888 llvm_unreachable (" Unhandled PushPopKind" );
877889 }
@@ -914,7 +926,10 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
914926 // Emit prologue for shadow call stack.
915927 emitSCSPrologue (MF, MBB, MBBI, DL);
916928
917- auto FirstFrameSetup = MBBI;
929+ // We keep track of the first instruction because it might be a
930+ // `(QC.)CM.PUSH(FP)`, and we may need to adjust the immediate rather than
931+ // inserting an `addi sp, sp, -N*16`
932+ auto PossiblePush = MBBI;
918933
919934 // Skip past all callee-saved register spill instructions.
920935 while (MBBI != MBB.end () && MBBI->getFlag (MachineInstr::FrameSetup))
@@ -988,19 +1003,29 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
9881003 }
9891004
9901005 if (RVFI->useQCIInterrupt (MF)) {
991- CFIBuilder.buildDefCFAOffset (QCIInterruptPushAmount);
1006+ // The function starts with `QC.C.MIENTER(.NEST)`, so the `(QC.)CM.PUSH(FP)`
1007+ // could only be the next instruction.
1008+ ++PossiblePush;
1009+
1010+ // Insert the CFI metadata before where we think the `(QC.)CM.PUSH(FP)`
1011+ // could be. The PUSH will also get its own CFI metadata for its own
1012+ // modifications, which should come after the PUSH.
1013+ CFIInstBuilder PushCFIBuilder (MBB, PossiblePush, MachineInstr::FrameSetup);
1014+ PushCFIBuilder.buildDefCFAOffset (QCIInterruptPushAmount);
9921015 for (const CalleeSavedInfo &CS : getQCISavedInfo (MF, CSI))
993- CFIBuilder.buildOffset (CS.getReg (),
994- MFI.getObjectOffset (CS.getFrameIdx ()));
995- } else if (RVFI->isPushable (MF) && FirstFrameSetup != MBB.end () &&
996- isPush (FirstFrameSetup->getOpcode ())) {
1016+ PushCFIBuilder.buildOffset (CS.getReg (),
1017+ MFI.getObjectOffset (CS.getFrameIdx ()));
1018+ }
1019+
1020+ if (RVFI->isPushable (MF) && PossiblePush != MBB.end () &&
1021+ isPush (PossiblePush->getOpcode ())) {
9971022 // Use available stack adjustment in push instruction to allocate additional
9981023 // stack space. Align the stack size down to a multiple of 16. This is
9991024 // needed for RVE.
10001025 // FIXME: Can we increase the stack size to a multiple of 16 instead?
10011026 uint64_t StackAdj =
10021027 std::min (alignDown (StackSize, 16 ), static_cast <uint64_t >(48 ));
1003- FirstFrameSetup ->getOperand (1 ).setImm (StackAdj);
1028+ PossiblePush ->getOperand (1 ).setImm (StackAdj);
10041029 StackSize -= StackAdj;
10051030
10061031 CFIBuilder.buildDefCFAOffset (RealStackSize - StackSize);
@@ -1305,17 +1330,21 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
13051330 for (const CalleeSavedInfo &CS : getPushOrLibCallsSavedInfo (MF, CSI))
13061331 CFIBuilder.buildRestore (CS.getReg ());
13071332
1308- // Update CFA offset. After CM_POP SP should be equal to CFA, so CFA
1309- // offset should be a zero.
1310- CFIBuilder.buildDefCFAOffset (0 );
1333+ // Update CFA Offset. If this is a QCI interrupt function, there will be a
1334+ // leftover offset which is deallocated by `QC.C.MILEAVERET`, otherwise
1335+ // getQCIInterruptStackSize() will be 0.
1336+ CFIBuilder.buildDefCFAOffset (RVFI->getQCIInterruptStackSize ());
13111337 }
13121338 }
13131339
13141340 emitSiFiveCLICPreemptibleRestores (MF, MBB, MBBI, DL);
13151341
1316- // Deallocate stack if StackSize isn't a zero yet
1342+ // Deallocate stack if StackSize isn't a zero yet. If this is a QCI interrupt
1343+ // function, there will be a leftover offset which is deallocated by
1344+ // `QC.C.MILEAVERET`, otherwise getQCIInterruptStackSize() will be 0.
13171345 if (StackSize != 0 )
1318- deallocateStack (MF, MBB, MBBI, DL, StackSize, RealStackSize - StackSize);
1346+ deallocateStack (MF, MBB, MBBI, DL, StackSize,
1347+ RVFI->getQCIInterruptStackSize ());
13191348
13201349 // Emit epilogue for shadow call stack.
13211350 emitSCSEpilogue (MF, MBB, MBBI, DL);
@@ -1894,10 +1923,17 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
18941923
18951924 if (RVFI->useQCIInterrupt (MF)) {
18961925 RVFI->setQCIInterruptStackSize (QCIInterruptPushAmount);
1897- } else if (RVFI->isPushable (MF)) {
1926+ }
1927+
1928+ if (RVFI->isPushable (MF)) {
18981929 // Determine how many GPRs we need to push and save it to RVFI.
18991930 unsigned PushedRegNum = getNumPushPopRegs (CSI);
1900- if (PushedRegNum) {
1931+
1932+ // `QC.C.MIENTER(.NEST)` will save `ra` and `s0`, so we should only push if
1933+ // we want to push more than 2 registers. Otherwise, we should push if we
1934+ // want to push more than 0 registers.
1935+ unsigned OnlyPushIfMoreThan = RVFI->useQCIInterrupt (MF) ? 2 : 0 ;
1936+ if (PushedRegNum > OnlyPushIfMoreThan) {
19011937 RVFI->setRVPushRegs (PushedRegNum);
19021938 RVFI->setRVPushStackSize (alignTo ((STI.getXLen () / 8 ) * PushedRegNum, 16 ));
19031939 }
@@ -1923,8 +1959,9 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
19231959 CS.setFrameIdx (FrameIdx);
19241960 continue ;
19251961 }
1926- // TODO: QCI Interrupt + Push/Pop
1927- } else if (RVFI->useSaveRestoreLibCalls (MF) || RVFI->isPushable (MF)) {
1962+ }
1963+
1964+ if (RVFI->useSaveRestoreLibCalls (MF) || RVFI->isPushable (MF)) {
19281965 const auto *FII = llvm::find_if (
19291966 FixedCSRFIMap, [&](MCPhysReg P) { return P == CS.getReg (); });
19301967 unsigned RegNum = std::distance (std::begin (FixedCSRFIMap), FII);
@@ -1937,6 +1974,9 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
19371974 else
19381975 Offset = -int64_t (RegNum + 1 ) * Size;
19391976
1977+ if (RVFI->useQCIInterrupt (MF))
1978+ Offset -= QCIInterruptPushAmount;
1979+
19401980 int FrameIdx = MFI.CreateFixedSpillStackObject (Size, Offset);
19411981 assert (FrameIdx < 0 );
19421982 CS.setFrameIdx (FrameIdx);
@@ -1965,10 +2005,13 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
19652005 // because there are gaps which are reserved for future use.
19662006 MFI.CreateFixedSpillStackObject (
19672007 QCIInterruptPushAmount, -static_cast <int64_t >(QCIInterruptPushAmount));
1968- } else if (RVFI->isPushable (MF)) {
2008+ }
2009+
2010+ if (RVFI->isPushable (MF)) {
2011+ int64_t QCIOffset = RVFI->useQCIInterrupt (MF) ? QCIInterruptPushAmount : 0 ;
19692012 // Allocate a fixed object that covers the full push.
19702013 if (int64_t PushSize = RVFI->getRVPushStackSize ())
1971- MFI.CreateFixedSpillStackObject (PushSize, -PushSize);
2014+ MFI.CreateFixedSpillStackObject (PushSize, -PushSize - QCIOffset );
19722015 } else if (int LibCallRegs = getLibCallID (MF, CSI) + 1 ) {
19732016 int64_t LibCallFrameSize =
19742017 alignTo ((STI.getXLen () / 8 ) * LibCallRegs, getStackAlign ());
@@ -2003,13 +2046,15 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
20032046
20042047 for (auto [Reg, _Offset] : FixedCSRFIQCIInterruptMap)
20052048 MBB.addLiveIn (Reg);
2006- // TODO: Handle QCI Interrupt + Push/Pop
2007- } else if (RVFI->isPushable (*MF)) {
2049+ }
2050+
2051+ if (RVFI->isPushable (*MF)) {
20082052 // Emit CM.PUSH with base StackAdj & evaluate Push stack
20092053 unsigned PushedRegNum = RVFI->getRVPushRegs ();
20102054 if (PushedRegNum > 0 ) {
20112055 // Use encoded number to represent registers to spill.
2012- unsigned Opcode = getPushOpcode (RVFI->getPushPopKind (*MF), hasFP (*MF));
2056+ unsigned Opcode = getPushOpcode (
2057+ RVFI->getPushPopKind (*MF), hasFP (*MF) && !RVFI->useQCIInterrupt (*MF));
20132058 unsigned RegEnc = RISCVZC::encodeRegListNumRegs (PushedRegNum);
20142059 MachineInstrBuilder PushBuilder =
20152060 BuildMI (MBB, MI, DL, TII.get (Opcode))
@@ -2156,8 +2201,9 @@ bool RISCVFrameLowering::restoreCalleeSavedRegisters(
21562201 // QC.C.MILEAVERET which we already inserted to return.
21572202 assert (MI->getOpcode () == RISCV::QC_C_MILEAVERET &&
21582203 " Unexpected QCI Interrupt Return Instruction" );
2159- // TODO: Handle QCI + Push/Pop
2160- } else if (RVFI->isPushable (*MF)) {
2204+ }
2205+
2206+ if (RVFI->isPushable (*MF)) {
21612207 unsigned PushedRegNum = RVFI->getRVPushRegs ();
21622208 if (PushedRegNum > 0 ) {
21632209 unsigned Opcode = getPopOpcode (RVFI->getPushPopKind (*MF));
0 commit comments