@@ -568,6 +568,18 @@ getPushOrLibCallsSavedInfo(const MachineFunction &MF,
568
568
return PushOrLibCallsCSI;
569
569
570
570
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
+
571
583
const auto *FII = llvm::find_if (
572
584
FixedCSRFIMap, [&](MCPhysReg P) { return P == CS.getReg (); });
573
585
if (FII != std::end (FixedCSRFIMap))
@@ -866,12 +878,12 @@ static bool isPop(unsigned Opcode) {
866
878
}
867
879
868
880
static unsigned getPushOpcode (RISCVMachineFunctionInfo::PushPopKind Kind,
869
- bool HasFP ) {
881
+ bool UpdateFP ) {
870
882
switch (Kind) {
871
883
case RISCVMachineFunctionInfo::PushPopKind::StdExtZcmp:
872
884
return RISCV::CM_PUSH;
873
885
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;
875
887
default :
876
888
llvm_unreachable (" Unhandled PushPopKind" );
877
889
}
@@ -914,7 +926,10 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
914
926
// Emit prologue for shadow call stack.
915
927
emitSCSPrologue (MF, MBB, MBBI, DL);
916
928
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;
918
933
919
934
// Skip past all callee-saved register spill instructions.
920
935
while (MBBI != MBB.end () && MBBI->getFlag (MachineInstr::FrameSetup))
@@ -988,19 +1003,29 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
988
1003
}
989
1004
990
1005
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);
992
1015
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 ())) {
997
1022
// Use available stack adjustment in push instruction to allocate additional
998
1023
// stack space. Align the stack size down to a multiple of 16. This is
999
1024
// needed for RVE.
1000
1025
// FIXME: Can we increase the stack size to a multiple of 16 instead?
1001
1026
uint64_t StackAdj =
1002
1027
std::min (alignDown (StackSize, 16 ), static_cast <uint64_t >(48 ));
1003
- FirstFrameSetup ->getOperand (1 ).setImm (StackAdj);
1028
+ PossiblePush ->getOperand (1 ).setImm (StackAdj);
1004
1029
StackSize -= StackAdj;
1005
1030
1006
1031
CFIBuilder.buildDefCFAOffset (RealStackSize - StackSize);
@@ -1305,17 +1330,21 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
1305
1330
for (const CalleeSavedInfo &CS : getPushOrLibCallsSavedInfo (MF, CSI))
1306
1331
CFIBuilder.buildRestore (CS.getReg ());
1307
1332
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 ());
1311
1337
}
1312
1338
}
1313
1339
1314
1340
emitSiFiveCLICPreemptibleRestores (MF, MBB, MBBI, DL);
1315
1341
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.
1317
1345
if (StackSize != 0 )
1318
- deallocateStack (MF, MBB, MBBI, DL, StackSize, RealStackSize - StackSize);
1346
+ deallocateStack (MF, MBB, MBBI, DL, StackSize,
1347
+ RVFI->getQCIInterruptStackSize ());
1319
1348
1320
1349
// Emit epilogue for shadow call stack.
1321
1350
emitSCSEpilogue (MF, MBB, MBBI, DL);
@@ -1894,10 +1923,17 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
1894
1923
1895
1924
if (RVFI->useQCIInterrupt (MF)) {
1896
1925
RVFI->setQCIInterruptStackSize (QCIInterruptPushAmount);
1897
- } else if (RVFI->isPushable (MF)) {
1926
+ }
1927
+
1928
+ if (RVFI->isPushable (MF)) {
1898
1929
// Determine how many GPRs we need to push and save it to RVFI.
1899
1930
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) {
1901
1937
RVFI->setRVPushRegs (PushedRegNum);
1902
1938
RVFI->setRVPushStackSize (alignTo ((STI.getXLen () / 8 ) * PushedRegNum, 16 ));
1903
1939
}
@@ -1923,8 +1959,9 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
1923
1959
CS.setFrameIdx (FrameIdx);
1924
1960
continue ;
1925
1961
}
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)) {
1928
1965
const auto *FII = llvm::find_if (
1929
1966
FixedCSRFIMap, [&](MCPhysReg P) { return P == CS.getReg (); });
1930
1967
unsigned RegNum = std::distance (std::begin (FixedCSRFIMap), FII);
@@ -1937,6 +1974,9 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
1937
1974
else
1938
1975
Offset = -int64_t (RegNum + 1 ) * Size;
1939
1976
1977
+ if (RVFI->useQCIInterrupt (MF))
1978
+ Offset -= QCIInterruptPushAmount;
1979
+
1940
1980
int FrameIdx = MFI.CreateFixedSpillStackObject (Size, Offset);
1941
1981
assert (FrameIdx < 0 );
1942
1982
CS.setFrameIdx (FrameIdx);
@@ -1965,10 +2005,13 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
1965
2005
// because there are gaps which are reserved for future use.
1966
2006
MFI.CreateFixedSpillStackObject (
1967
2007
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 ;
1969
2012
// Allocate a fixed object that covers the full push.
1970
2013
if (int64_t PushSize = RVFI->getRVPushStackSize ())
1971
- MFI.CreateFixedSpillStackObject (PushSize, -PushSize);
2014
+ MFI.CreateFixedSpillStackObject (PushSize, -PushSize - QCIOffset );
1972
2015
} else if (int LibCallRegs = getLibCallID (MF, CSI) + 1 ) {
1973
2016
int64_t LibCallFrameSize =
1974
2017
alignTo ((STI.getXLen () / 8 ) * LibCallRegs, getStackAlign ());
@@ -2003,13 +2046,15 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
2003
2046
2004
2047
for (auto [Reg, _Offset] : FixedCSRFIQCIInterruptMap)
2005
2048
MBB.addLiveIn (Reg);
2006
- // TODO: Handle QCI Interrupt + Push/Pop
2007
- } else if (RVFI->isPushable (*MF)) {
2049
+ }
2050
+
2051
+ if (RVFI->isPushable (*MF)) {
2008
2052
// Emit CM.PUSH with base StackAdj & evaluate Push stack
2009
2053
unsigned PushedRegNum = RVFI->getRVPushRegs ();
2010
2054
if (PushedRegNum > 0 ) {
2011
2055
// 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));
2013
2058
unsigned RegEnc = RISCVZC::encodeRegListNumRegs (PushedRegNum);
2014
2059
MachineInstrBuilder PushBuilder =
2015
2060
BuildMI (MBB, MI, DL, TII.get (Opcode))
@@ -2156,8 +2201,9 @@ bool RISCVFrameLowering::restoreCalleeSavedRegisters(
2156
2201
// QC.C.MILEAVERET which we already inserted to return.
2157
2202
assert (MI->getOpcode () == RISCV::QC_C_MILEAVERET &&
2158
2203
" Unexpected QCI Interrupt Return Instruction" );
2159
- // TODO: Handle QCI + Push/Pop
2160
- } else if (RVFI->isPushable (*MF)) {
2204
+ }
2205
+
2206
+ if (RVFI->isPushable (*MF)) {
2161
2207
unsigned PushedRegNum = RVFI->getRVPushRegs ();
2162
2208
if (PushedRegNum > 0 ) {
2163
2209
unsigned Opcode = getPopOpcode (RVFI->getPushPopKind (*MF));
0 commit comments