Skip to content

Commit 0de2b26

Browse files
authored
[RISCV] Register fixed stack slots for callee saved registers for -msave-restore/Zcmp (llvm#81392)
PEI previously used fake frame indices for these callee saved registers. These fake frame indices are not register with MachineFrameInfo. This required them to be deleted form CalleeSavedInfo after PEI to avoid breaking later passes. See llvm#79535 Unfortunately, removing the registers from CalleeSavedInfo pessimizes Interprocedural Register Allocation. The RegUsageInfoCollector pass runs after PEI and uses CalleeSavedInfo. This patch replaces llvm#79535 by properly creating fixed stack objects through MachineFrameInfo. This changes the stack size and offsets returned by MachineFrameInfo which requires changes to how RISCVFrameLowering uses that information. In addition to the individual object for each register, I've also create a single large fixed object that covers the entire stack area covered by cm.push or the libcalls. cm.push must always push a multiple of 16 bytes and the save restore libcall pushes a multiple of stack align. I think this leaves holes in the stack where we could spill other registers, but it matches what we did previously. Maybe we can optimize this in the future. The only test changes are due to stack alignment handling after the callee save registers. Since we now have the fixed objects, on the stack the offset is non-zero when an aligned object is processed so the offset gets rounded up, increasing the stack size. I suspect we might need some more updates for RVV related code. There is very little or maybe even no testing of RVV mixed with Zcmp and save-restore.
1 parent 017675f commit 0de2b26

File tree

5 files changed

+163
-163
lines changed

5 files changed

+163
-163
lines changed

llvm/lib/Target/RISCV/RISCVFrameLowering.cpp

Lines changed: 99 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -291,9 +291,7 @@ static Register getMaxPushPopReg(const MachineFunction &MF,
291291
const std::vector<CalleeSavedInfo> &CSI) {
292292
Register MaxPushPopReg = RISCV::NoRegister;
293293
for (auto &CS : CSI) {
294-
// RISCVRegisterInfo::hasReservedSpillSlot assigns negative frame indices to
295-
// registers which can be saved by Zcmp Push.
296-
if (CS.getFrameIdx() < 0)
294+
if (llvm::is_contained(AllPopRegs, CS.getReg().id()))
297295
MaxPushPopReg = std::max(MaxPushPopReg.id(), CS.getReg().id());
298296
}
299297
// if rlist is {rs, s0-s10}, then s11 will also be included
@@ -532,8 +530,8 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
532530

533531
// FIXME (note copied from Lanai): This appears to be overallocating. Needs
534532
// investigation. Get the number of bytes to allocate from the FrameInfo.
535-
uint64_t StackSize = getStackSizeWithRVVPadding(MF);
536-
uint64_t RealStackSize = StackSize + RVFI->getReservedSpillsSize();
533+
uint64_t RealStackSize = getStackSizeWithRVVPadding(MF);
534+
uint64_t StackSize = RealStackSize - RVFI->getReservedSpillsSize();
537535
uint64_t RVVStackSize = RVFI->getRVVStackSize();
538536

539537
// Early exit if there is no need to allocate on the stack
@@ -590,20 +588,7 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
590588
// directives.
591589
for (const auto &Entry : CSI) {
592590
int FrameIdx = Entry.getFrameIdx();
593-
int64_t Offset;
594-
// Offsets for objects with fixed locations (IE: those saved by libcall) are
595-
// simply calculated from the frame index.
596-
if (FrameIdx < 0) {
597-
if (RVFI->isPushable(MF)) {
598-
// Callee-saved register stored by Zcmp push is in reverse order.
599-
Offset = -(FrameIdx + RVFI->getRVPushRegs() + 1) *
600-
(int64_t)STI.getXLen() / 8;
601-
} else {
602-
Offset = FrameIdx * (int64_t)STI.getXLen() / 8;
603-
}
604-
} else {
605-
Offset = MFI.getObjectOffset(FrameIdx) - RVFI->getReservedSpillsSize();
606-
}
591+
int64_t Offset = MFI.getObjectOffset(FrameIdx);
607592
Register Reg = Entry.getReg();
608593
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
609594
nullptr, RI->getDwarfRegNum(Reg, true), Offset));
@@ -746,8 +731,8 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
746731
if (!CSI.empty())
747732
LastFrameDestroy = std::prev(MBBI, CSI.size());
748733

749-
uint64_t StackSize = getStackSizeWithRVVPadding(MF);
750-
uint64_t RealStackSize = StackSize + RVFI->getReservedSpillsSize();
734+
uint64_t RealStackSize = getStackSizeWithRVVPadding(MF);
735+
uint64_t StackSize = RealStackSize - RVFI->getReservedSpillsSize();
751736
uint64_t FPOffset = RealStackSize - RVFI->getVarArgsSaveSize();
752737
uint64_t RVVStackSize = RVFI->getRVVStackSize();
753738

@@ -897,8 +882,6 @@ RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
897882

898883
if (FrameReg == getFPReg(STI)) {
899884
Offset += StackOffset::getFixed(RVFI->getVarArgsSaveSize());
900-
if (FI >= 0)
901-
Offset -= StackOffset::getFixed(RVFI->getReservedSpillsSize());
902885
// When using FP to access scalable vector objects, we need to minus
903886
// the frame size.
904887
//
@@ -965,8 +948,7 @@ RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
965948
if (MFI.isFixedObjectIndex(FI)) {
966949
assert(!RI->hasStackRealignment(MF) &&
967950
"Can't index across variable sized realign");
968-
Offset += StackOffset::get(getStackSizeWithRVVPadding(MF) +
969-
RVFI->getReservedSpillsSize(),
951+
Offset += StackOffset::get(getStackSizeWithRVVPadding(MF),
970952
RVFI->getRVVStackSize());
971953
} else {
972954
Offset += StackOffset::getFixed(MFI.getStackSize());
@@ -1243,47 +1225,17 @@ void RISCVFrameLowering::processFunctionBeforeFrameFinalized(
12431225
RVFI->setBranchRelaxationScratchFrameIndex(FI);
12441226
}
12451227

1246-
if (MFI.getCalleeSavedInfo().empty() || RVFI->useSaveRestoreLibCalls(MF) ||
1247-
RVFI->isPushable(MF)) {
1248-
RVFI->setCalleeSavedStackSize(0);
1249-
return;
1250-
}
1251-
1252-
unsigned Size = 0;
1228+
unsigned Size = RVFI->getReservedSpillsSize();
12531229
for (const auto &Info : MFI.getCalleeSavedInfo()) {
12541230
int FrameIdx = Info.getFrameIdx();
1255-
if (MFI.getStackID(FrameIdx) != TargetStackID::Default)
1231+
if (FrameIdx < 0 || MFI.getStackID(FrameIdx) != TargetStackID::Default)
12561232
continue;
12571233

12581234
Size += MFI.getObjectSize(FrameIdx);
12591235
}
12601236
RVFI->setCalleeSavedStackSize(Size);
12611237
}
12621238

1263-
void RISCVFrameLowering::processFunctionBeforeFrameIndicesReplaced(
1264-
MachineFunction &MF, RegScavenger *RS) const {
1265-
// Remove CalleeSavedInfo for registers saved by Zcmp or save/restore
1266-
// libcalls.
1267-
MachineFrameInfo &MFI = MF.getFrameInfo();
1268-
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
1269-
const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
1270-
if (!RVFI->isPushable(MF) && !RVFI->useSaveRestoreLibCalls(MF))
1271-
return;
1272-
const std::vector<CalleeSavedInfo> &CSIs = MFI.getCalleeSavedInfo();
1273-
std::vector<CalleeSavedInfo> NewCSIs;
1274-
for (const auto &CSI : CSIs) {
1275-
// Skip CSRs that have fake a frame index.
1276-
int ReservedFI = 0;
1277-
if (TRI->hasReservedSpillSlot(MF, CSI.getReg(), ReservedFI)) {
1278-
assert(CSI.getFrameIdx() == ReservedFI &&
1279-
"Reserved CSR spill slot frame index mismatch in CSI");
1280-
continue;
1281-
}
1282-
NewCSIs.push_back(CSI);
1283-
}
1284-
MFI.setCalleeSavedInfo(std::move(NewCSIs));
1285-
}
1286-
12871239
// Not preserve stack space within prologue for outgoing variables when the
12881240
// function contains variable size objects or there are vector objects accessed
12891241
// by the frame pointer.
@@ -1403,6 +1355,93 @@ RISCVFrameLowering::getFirstSPAdjustAmount(const MachineFunction &MF) const {
14031355
return 0;
14041356
}
14051357

1358+
// Offsets which need to be scale by XLen representing locations of CSRs which
1359+
// are given a fixed location by save/restore libcalls or Zcmp Push/Pop.
1360+
static const std::pair<MCPhysReg, int8_t> FixedCSRFIMap[] = {
1361+
{/*ra*/ RISCV::X1, -1}, {/*s0*/ RISCV::X8, -2},
1362+
{/*s1*/ RISCV::X9, -3}, {/*s2*/ RISCV::X18, -4},
1363+
{/*s3*/ RISCV::X19, -5}, {/*s4*/ RISCV::X20, -6},
1364+
{/*s5*/ RISCV::X21, -7}, {/*s6*/ RISCV::X22, -8},
1365+
{/*s7*/ RISCV::X23, -9}, {/*s8*/ RISCV::X24, -10},
1366+
{/*s9*/ RISCV::X25, -11}, {/*s10*/ RISCV::X26, -12},
1367+
{/*s11*/ RISCV::X27, -13}};
1368+
1369+
bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
1370+
MachineFunction &MF, const TargetRegisterInfo *TRI,
1371+
std::vector<CalleeSavedInfo> &CSI, unsigned &MinCSFrameIndex,
1372+
unsigned &MaxCSFrameIndex) const {
1373+
// Early exit if no callee saved registers are modified!
1374+
if (CSI.empty())
1375+
return true;
1376+
1377+
auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
1378+
1379+
if (RVFI->isPushable(MF)) {
1380+
// Determine how many GPRs we need to push and save it to RVFI.
1381+
Register MaxReg = getMaxPushPopReg(MF, CSI);
1382+
if (MaxReg != RISCV::NoRegister) {
1383+
auto [RegEnc, PushedRegNum] = getPushPopEncodingAndNum(MaxReg);
1384+
RVFI->setRVPushRegs(PushedRegNum);
1385+
RVFI->setRVPushStackSize(alignTo((STI.getXLen() / 8) * PushedRegNum, 16));
1386+
1387+
// Use encoded number to represent registers to spill.
1388+
RVFI->setRVPushRlist(RegEnc);
1389+
}
1390+
}
1391+
1392+
MachineFrameInfo &MFI = MF.getFrameInfo();
1393+
const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
1394+
1395+
for (auto &CS : CSI) {
1396+
unsigned Reg = CS.getReg();
1397+
const TargetRegisterClass *RC = RegInfo->getMinimalPhysRegClass(Reg);
1398+
unsigned Size = RegInfo->getSpillSize(*RC);
1399+
1400+
// This might need a fixed stack slot.
1401+
if (RVFI->useSaveRestoreLibCalls(MF) || RVFI->isPushable(MF)) {
1402+
const auto *FII = llvm::find_if(
1403+
FixedCSRFIMap, [&](auto P) { return P.first == CS.getReg(); });
1404+
if (FII != std::end(FixedCSRFIMap)) {
1405+
int64_t Offset;
1406+
if (RVFI->isPushable(MF))
1407+
Offset = -((FII->second + RVFI->getRVPushRegs() + 1) * (int64_t)Size);
1408+
else
1409+
Offset = FII->second * (int64_t)Size;
1410+
1411+
int FrameIdx = MFI.CreateFixedSpillStackObject(Size, Offset);
1412+
assert(FrameIdx < 0);
1413+
CS.setFrameIdx(FrameIdx);
1414+
continue;
1415+
}
1416+
}
1417+
1418+
// Not a fixed slot.
1419+
Align Alignment = RegInfo->getSpillAlign(*RC);
1420+
// We may not be able to satisfy the desired alignment specification of
1421+
// the TargetRegisterClass if the stack alignment is smaller. Use the
1422+
// min.
1423+
Alignment = std::min(Alignment, getStackAlign());
1424+
int FrameIdx = MFI.CreateStackObject(Size, Alignment, true);
1425+
if ((unsigned)FrameIdx < MinCSFrameIndex)
1426+
MinCSFrameIndex = FrameIdx;
1427+
if ((unsigned)FrameIdx > MaxCSFrameIndex)
1428+
MaxCSFrameIndex = FrameIdx;
1429+
CS.setFrameIdx(FrameIdx);
1430+
}
1431+
1432+
// Allocate a fixed object that covers the full push or libcall size.
1433+
if (RVFI->isPushable(MF)) {
1434+
if (int64_t PushSize = RVFI->getRVPushStackSize())
1435+
MFI.CreateFixedSpillStackObject(PushSize, -PushSize);
1436+
} else if (int LibCallRegs = getLibCallID(MF, CSI) + 1) {
1437+
int64_t LibCallFrameSize =
1438+
alignTo((STI.getXLen() / 8) * LibCallRegs, getStackAlign());
1439+
MFI.CreateFixedSpillStackObject(LibCallFrameSize, -LibCallFrameSize);
1440+
}
1441+
1442+
return true;
1443+
}
1444+
14061445
bool RISCVFrameLowering::spillCalleeSavedRegisters(
14071446
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
14081447
ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
@@ -1418,14 +1457,10 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
14181457
// Emit CM.PUSH with base SPimm & evaluate Push stack
14191458
RISCVMachineFunctionInfo *RVFI = MF->getInfo<RISCVMachineFunctionInfo>();
14201459
if (RVFI->isPushable(*MF)) {
1421-
Register MaxReg = getMaxPushPopReg(*MF, CSI);
1422-
if (MaxReg != RISCV::NoRegister) {
1423-
auto [RegEnc, PushedRegNum] = getPushPopEncodingAndNum(MaxReg);
1424-
RVFI->setRVPushRegs(PushedRegNum);
1425-
RVFI->setRVPushStackSize(alignTo((STI.getXLen() / 8) * PushedRegNum, 16));
1426-
1460+
unsigned PushedRegNum = RVFI->getRVPushRegs();
1461+
if (PushedRegNum > 0) {
14271462
// Use encoded number to represent registers to spill.
1428-
RVFI->setRVPushRlist(RegEnc);
1463+
int RegEnc = RVFI->getRVPushRlist();
14291464
MachineInstrBuilder PushBuilder =
14301465
BuildMI(MBB, MI, DL, TII.get(RISCV::CM_PUSH))
14311466
.setMIFlag(MachineInstr::FrameSetup);

llvm/lib/Target/RISCV/RISCVFrameLowering.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,6 @@ class RISCVFrameLowering : public TargetFrameLowering {
3737
void processFunctionBeforeFrameFinalized(MachineFunction &MF,
3838
RegScavenger *RS) const override;
3939

40-
void
41-
processFunctionBeforeFrameIndicesReplaced(MachineFunction &MF,
42-
RegScavenger *RS) const override;
43-
4440
bool hasFP(const MachineFunction &MF) const override;
4541

4642
bool hasBP(const MachineFunction &MF) const;
@@ -49,6 +45,12 @@ class RISCVFrameLowering : public TargetFrameLowering {
4945
MachineBasicBlock::iterator
5046
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
5147
MachineBasicBlock::iterator MI) const override;
48+
49+
bool assignCalleeSavedSpillSlots(MachineFunction &MF,
50+
const TargetRegisterInfo *TRI,
51+
std::vector<CalleeSavedInfo> &CSI,
52+
unsigned &MinCSFrameIndex,
53+
unsigned &MaxCSFrameIndex) const override;
5254
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
5355
MachineBasicBlock::iterator MI,
5456
ArrayRef<CalleeSavedInfo> CSI,

llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -156,40 +156,6 @@ const uint32_t *RISCVRegisterInfo::getNoPreservedMask() const {
156156
return CSR_NoRegs_RegMask;
157157
}
158158

159-
// Frame indexes representing locations of CSRs which are given a fixed location
160-
// by save/restore libcalls or Zcmp Push/Pop.
161-
static const std::pair<unsigned, int> FixedCSRFIMap[] = {
162-
{/*ra*/ RISCV::X1, -1},
163-
{/*s0*/ RISCV::X8, -2},
164-
{/*s1*/ RISCV::X9, -3},
165-
{/*s2*/ RISCV::X18, -4},
166-
{/*s3*/ RISCV::X19, -5},
167-
{/*s4*/ RISCV::X20, -6},
168-
{/*s5*/ RISCV::X21, -7},
169-
{/*s6*/ RISCV::X22, -8},
170-
{/*s7*/ RISCV::X23, -9},
171-
{/*s8*/ RISCV::X24, -10},
172-
{/*s9*/ RISCV::X25, -11},
173-
{/*s10*/ RISCV::X26, -12},
174-
{/*s11*/ RISCV::X27, -13}
175-
};
176-
177-
bool RISCVRegisterInfo::hasReservedSpillSlot(const MachineFunction &MF,
178-
Register Reg,
179-
int &FrameIdx) const {
180-
const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
181-
if (!RVFI->useSaveRestoreLibCalls(MF) && !RVFI->isPushable(MF))
182-
return false;
183-
184-
const auto *FII =
185-
llvm::find_if(FixedCSRFIMap, [&](auto P) { return P.first == Reg; });
186-
if (FII == std::end(FixedCSRFIMap))
187-
return false;
188-
189-
FrameIdx = FII->second;
190-
return true;
191-
}
192-
193159
void RISCVRegisterInfo::adjustReg(MachineBasicBlock &MBB,
194160
MachineBasicBlock::iterator II,
195161
const DebugLoc &DL, Register DestReg,

llvm/lib/Target/RISCV/RISCVRegisterInfo.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@ struct RISCVRegisterInfo : public RISCVGenRegisterInfo {
3535

3636
const uint32_t *getNoPreservedMask() const override;
3737

38-
bool hasReservedSpillSlot(const MachineFunction &MF, Register Reg,
39-
int &FrameIdx) const override;
40-
4138
// Update DestReg to have the value SrcReg plus an offset. This is
4239
// used during frame layout, and we may need to ensure that if we
4340
// split the offset internally that the DestReg is always aligned,

0 commit comments

Comments
 (0)