Skip to content

Commit 5a31a67

Browse files
committed
[RISCV] Frame handling for RISC-V V extension.
This patch proposes how to deal with RISC-V vector frame objects. The layout of RISC-V vector frame will look like |---------------------------------| | scalar callee-saved registers | |---------------------------------| | scalar local variables | |---------------------------------| | scalar outgoing arguments | |---------------------------------| | RVV local variables && | | RVV outgoing arguments | |---------------------------------| <- end of frame (sp) If there is realignment or variable length array in the stack, we will use frame pointer to access fixed objects and stack pointer to access non-fixed objects. |---------------------------------| <- frame pointer (fp) | scalar callee-saved registers | |---------------------------------| | scalar local variables | |---------------------------------| | ///// realignment ///// | |---------------------------------| | scalar outgoing arguments | |---------------------------------| | RVV local variables && | | RVV outgoing arguments | |---------------------------------| <- end of frame (sp) If there are both realignment and variable length array in the stack, we will use frame pointer to access fixed objects and base pointer to access non-fixed objects. |---------------------------------| <- frame pointer (fp) | scalar callee-saved registers | |---------------------------------| | scalar local variables | |---------------------------------| | ///// realignment ///// | |---------------------------------| <- base pointer (bp) | RVV local variables && | | RVV outgoing arguments | |---------------------------------| | /////////////////////////////// | | variable length array | | /////////////////////////////// | |---------------------------------| <- end of frame (sp) | scalar outgoing arguments | |---------------------------------| In this version, we do not save the addresses of RVV objects in the stack. We access them directly through the polynomial expression (a x VLENB + b). We do not reserve frame pointer when there is any RVV object in the stack. So, we also access the scalar frame objects through the polynomial expression (a x VLENB + b) if the access across RVV stack area. Differential Revision: https://reviews.llvm.org/D94465
1 parent 0e3d7e6 commit 5a31a67

File tree

10 files changed

+1127
-41
lines changed

10 files changed

+1127
-41
lines changed

llvm/lib/Target/RISCV/RISCVFrameLowering.cpp

Lines changed: 174 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -242,10 +242,6 @@ void RISCVFrameLowering::determineFrameLayout(MachineFunction &MF) const {
242242
// Get the alignment.
243243
Align StackAlign = getStackAlign();
244244

245-
// Set Max Call Frame Size
246-
uint64_t MaxCallSize = alignTo(MFI.getMaxCallFrameSize(), StackAlign);
247-
MFI.setMaxCallFrameSize(MaxCallSize);
248-
249245
// Make sure the frame is aligned.
250246
FrameSize = alignTo(FrameSize, StackAlign);
251247

@@ -293,16 +289,43 @@ static Register getFPReg(const RISCVSubtarget &STI) { return RISCV::X8; }
293289
static Register getSPReg(const RISCVSubtarget &STI) { return RISCV::X2; }
294290

295291
static SmallVector<CalleeSavedInfo, 8>
296-
getNonLibcallCSI(const std::vector<CalleeSavedInfo> &CSI) {
292+
getNonLibcallCSI(const MachineFunction &MF,
293+
const std::vector<CalleeSavedInfo> &CSI) {
294+
const MachineFrameInfo &MFI = MF.getFrameInfo();
297295
SmallVector<CalleeSavedInfo, 8> NonLibcallCSI;
298296

299-
for (auto &CS : CSI)
300-
if (CS.getFrameIdx() >= 0)
297+
for (auto &CS : CSI) {
298+
int FI = CS.getFrameIdx();
299+
if (FI >= 0 && MFI.getStackID(FI) == TargetStackID::Default)
301300
NonLibcallCSI.push_back(CS);
301+
}
302302

303303
return NonLibcallCSI;
304304
}
305305

306+
void RISCVFrameLowering::adjustStackForRVV(MachineFunction &MF,
307+
MachineBasicBlock &MBB,
308+
MachineBasicBlock::iterator MBBI,
309+
const DebugLoc &DL,
310+
int64_t Amount) const {
311+
assert(Amount != 0 && "Did not need to adjust stack pointer for RVV.");
312+
313+
const RISCVInstrInfo *TII = STI.getInstrInfo();
314+
Register SPReg = getSPReg(STI);
315+
unsigned Opc = RISCV::ADD;
316+
if (Amount < 0) {
317+
Amount = -Amount;
318+
Opc = RISCV::SUB;
319+
}
320+
321+
// 1. Multiply the number of v-slots to the length of registers
322+
Register FactorRegister = TII->getVLENFactoredAmount(MF, MBB, MBBI, Amount);
323+
// 2. SP = SP - RVV stack size
324+
BuildMI(MBB, MBBI, DL, TII->get(Opc), SPReg)
325+
.addReg(SPReg)
326+
.addReg(FactorRegister);
327+
}
328+
306329
void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
307330
MachineBasicBlock &MBB) const {
308331
MachineFrameInfo &MFI = MF.getFrameInfo();
@@ -364,9 +387,10 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
364387
// investigation. Get the number of bytes to allocate from the FrameInfo.
365388
uint64_t StackSize = MFI.getStackSize();
366389
uint64_t RealStackSize = StackSize + RVFI->getLibCallStackSize();
390+
uint64_t RVVStackSize = RVFI->getRVVStackSize();
367391

368392
// Early exit if there is no need to allocate on the stack
369-
if (RealStackSize == 0 && !MFI.adjustsStack())
393+
if (RealStackSize == 0 && !MFI.adjustsStack() && RVVStackSize == 0)
370394
return;
371395

372396
// If the stack pointer has been marked as reserved, then produce an error if
@@ -399,7 +423,7 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
399423
// to the stack, not before.
400424
// FIXME: assumes exactly one instruction is used to save each callee-saved
401425
// register.
402-
std::advance(MBBI, getNonLibcallCSI(CSI).size());
426+
std::advance(MBBI, getNonLibcallCSI(MF, CSI).size());
403427

404428
// Iterate over list of callee-saved registers and emit .cfi_offset
405429
// directives.
@@ -489,6 +513,9 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
489513
}
490514
}
491515
}
516+
517+
if (RVVStackSize)
518+
adjustStackForRVV(MF, MBB, MBBI, DL, -RVVStackSize);
492519
}
493520

494521
void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
@@ -526,7 +553,7 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
526553
--MBBI;
527554
}
528555

529-
const auto &CSI = getNonLibcallCSI(MFI.getCalleeSavedInfo());
556+
const auto &CSI = getNonLibcallCSI(MF, MFI.getCalleeSavedInfo());
530557

531558
// Skip to before the restores of callee-saved registers
532559
// FIXME: assumes exactly one instruction is used to restore each
@@ -538,6 +565,7 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
538565
uint64_t StackSize = MFI.getStackSize();
539566
uint64_t RealStackSize = StackSize + RVFI->getLibCallStackSize();
540567
uint64_t FPOffset = RealStackSize - RVFI->getVarArgsSaveSize();
568+
uint64_t RVVStackSize = RVFI->getRVVStackSize();
541569

542570
// Restore the stack pointer using the value of the frame pointer. Only
543571
// necessary if the stack pointer was modified, meaning the stack size is
@@ -546,6 +574,9 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
546574
assert(hasFP(MF) && "frame pointer should not have been eliminated");
547575
adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg, -FPOffset,
548576
MachineInstr::FrameDestroy);
577+
} else {
578+
if (RVVStackSize)
579+
adjustStackForRVV(MF, MBB, LastFrameDestroy, DL, RVVStackSize);
549580
}
550581

551582
uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);
@@ -578,12 +609,22 @@ RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
578609
// Callee-saved registers should be referenced relative to the stack
579610
// pointer (positive offset), otherwise use the frame pointer (negative
580611
// offset).
581-
const auto &CSI = getNonLibcallCSI(MFI.getCalleeSavedInfo());
612+
const auto &CSI = getNonLibcallCSI(MF, MFI.getCalleeSavedInfo());
582613
int MinCSFI = 0;
583614
int MaxCSFI = -1;
584-
585-
int Offset = MFI.getObjectOffset(FI) - getOffsetOfLocalArea() +
586-
MFI.getOffsetAdjustment();
615+
StackOffset Offset;
616+
auto StackID = MFI.getStackID(FI);
617+
618+
assert((StackID == TargetStackID::Default ||
619+
StackID == TargetStackID::ScalableVector) &&
620+
"Unexpected stack ID for the frame object.");
621+
if (StackID == TargetStackID::Default) {
622+
Offset =
623+
StackOffset::getFixed(MFI.getObjectOffset(FI) - getOffsetOfLocalArea() +
624+
MFI.getOffsetAdjustment());
625+
} else if (StackID == TargetStackID::ScalableVector) {
626+
Offset = StackOffset::getScalable(MFI.getObjectOffset(FI));
627+
}
587628

588629
uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);
589630

@@ -596,33 +637,86 @@ RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
596637
FrameReg = RISCV::X2;
597638

598639
if (FirstSPAdjustAmount)
599-
Offset += FirstSPAdjustAmount;
640+
Offset += StackOffset::getFixed(FirstSPAdjustAmount);
600641
else
601-
Offset += MFI.getStackSize();
642+
Offset += StackOffset::getFixed(MFI.getStackSize());
602643
} else if (RI->needsStackRealignment(MF) && !MFI.isFixedObjectIndex(FI)) {
603644
// If the stack was realigned, the frame pointer is set in order to allow
604645
// SP to be restored, so we need another base register to record the stack
605646
// after realignment.
606-
if (hasBP(MF))
647+
if (hasBP(MF)) {
607648
FrameReg = RISCVABI::getBPReg();
608-
else
649+
// |--------------------------| -- <-- FP
650+
// | callee-saved registers | |
651+
// |--------------------------| | MFI.getStackSize()
652+
// | scalar local variables | |
653+
// |--------------------------| --
654+
// | Realignment | |
655+
// |--------------------------| -- <-- BP
656+
// | RVV objects | | RVFI->getRVVStackSize()
657+
// |--------------------------| --
658+
// | VarSize objects | |
659+
// |--------------------------| -- <-- SP
660+
} else {
609661
FrameReg = RISCV::X2;
610-
Offset += MFI.getStackSize();
611-
if (FI < 0)
612-
Offset += RVFI->getLibCallStackSize();
662+
// When using SP to access frame objects, we need to add RVV stack size.
663+
//
664+
// |--------------------------| -- <-- FP
665+
// | callee-saved registers | |
666+
// |--------------------------| | MFI.getStackSize()
667+
// | scalar local variables | |
668+
// |--------------------------| --
669+
// | Realignment | |
670+
// |--------------------------| --
671+
// | RVV objects | | RVFI->getRVVStackSize()
672+
// |--------------------------| -- <-- SP
673+
Offset += StackOffset::getScalable(RVFI->getRVVStackSize());
674+
}
675+
if (MFI.getStackID(FI) == TargetStackID::Default) {
676+
Offset += StackOffset::getFixed(MFI.getStackSize());
677+
if (FI < 0)
678+
Offset += StackOffset::getFixed(RVFI->getLibCallStackSize());
679+
}
613680
} else {
614681
FrameReg = RI->getFrameRegister(MF);
615682
if (hasFP(MF)) {
616-
Offset += RVFI->getVarArgsSaveSize();
683+
Offset += StackOffset::getFixed(RVFI->getVarArgsSaveSize());
617684
if (FI >= 0)
618-
Offset -= RVFI->getLibCallStackSize();
685+
Offset -= StackOffset::getFixed(RVFI->getLibCallStackSize());
686+
// When using FP to access scalable vector objects, we need to minus
687+
// the frame size.
688+
//
689+
// |--------------------------| -- <-- FP
690+
// | callee-saved registers | |
691+
// |--------------------------| | MFI.getStackSize()
692+
// | scalar local variables | |
693+
// |--------------------------| -- (Offset of RVV objects is from here.)
694+
// | RVV objects |
695+
// |--------------------------|
696+
// | VarSize objects |
697+
// |--------------------------| <-- SP
698+
if (MFI.getStackID(FI) == TargetStackID::ScalableVector)
699+
Offset -= StackOffset::getFixed(MFI.getStackSize());
619700
} else {
620-
Offset += MFI.getStackSize();
621-
if (FI < 0)
622-
Offset += RVFI->getLibCallStackSize();
701+
// When using SP to access frame objects, we need to add RVV stack size.
702+
//
703+
// |--------------------------| -- <-- FP
704+
// | callee-saved registers | |
705+
// |--------------------------| | MFI.getStackSize()
706+
// | scalar local variables | |
707+
// |--------------------------| --
708+
// | RVV objects | | RVFI->getRVVStackSize()
709+
// |--------------------------| -- <-- SP
710+
Offset += StackOffset::getScalable(RVFI->getRVVStackSize());
711+
if (MFI.getStackID(FI) == TargetStackID::Default) {
712+
Offset += StackOffset::getFixed(MFI.getStackSize());
713+
if (FI < 0)
714+
Offset += StackOffset::getFixed(RVFI->getLibCallStackSize());
715+
}
623716
}
624717
}
625-
return StackOffset::getFixed(Offset);
718+
719+
return Offset;
626720
}
627721

628722
void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF,
@@ -670,6 +764,37 @@ void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF,
670764
}
671765
}
672766

767+
int64_t
768+
RISCVFrameLowering::assignRVVStackObjectOffsets(MachineFrameInfo &MFI) const {
769+
int64_t Offset = 0;
770+
// Create a buffer of RVV objects to allocate.
771+
SmallVector<int, 8> ObjectsToAllocate;
772+
for (int I = 0, E = MFI.getObjectIndexEnd(); I != E; ++I) {
773+
unsigned StackID = MFI.getStackID(I);
774+
if (StackID != TargetStackID::ScalableVector)
775+
continue;
776+
if (MFI.isDeadObjectIndex(I))
777+
continue;
778+
779+
ObjectsToAllocate.push_back(I);
780+
}
781+
782+
// Allocate all RVV locals and spills
783+
for (int FI : ObjectsToAllocate) {
784+
// ObjectSize in bytes.
785+
int64_t ObjectSize = MFI.getObjectSize(FI);
786+
// If the data type is the fractional vector type, reserve one vector
787+
// register for it.
788+
if (ObjectSize < 8)
789+
ObjectSize = 8;
790+
// Currently, all scalable vector types are aligned to 8 bytes.
791+
Offset = alignTo(Offset + ObjectSize, 8);
792+
MFI.setObjectOffset(FI, -Offset);
793+
}
794+
795+
return Offset;
796+
}
797+
673798
void RISCVFrameLowering::processFunctionBeforeFrameFinalized(
674799
MachineFunction &MF, RegScavenger *RS) const {
675800
const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
@@ -686,6 +811,10 @@ void RISCVFrameLowering::processFunctionBeforeFrameFinalized(
686811
RegInfo->getSpillAlign(*RC), false);
687812
RS->addScavengingFrameIndex(RegScavFI);
688813
}
814+
815+
auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
816+
int64_t RVVStackSize = assignRVVStackObjectOffsets(MFI);
817+
RVFI->setRVVStackSize(RVVStackSize);
689818
}
690819

691820
// Not preserve stack space within prologue for outgoing variables when the
@@ -786,7 +915,7 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
786915
}
787916

788917
// Manually spill values not spilled by libcall.
789-
const auto &NonLibcallCSI = getNonLibcallCSI(CSI);
918+
const auto &NonLibcallCSI = getNonLibcallCSI(*MF, CSI);
790919
for (auto &CS : NonLibcallCSI) {
791920
// Insert the spill to the stack frame.
792921
Register Reg = CS.getReg();
@@ -811,7 +940,7 @@ bool RISCVFrameLowering::restoreCalleeSavedRegisters(
811940

812941
// Manually restore values not restored by libcall. Insert in reverse order.
813942
// loadRegFromStackSlot can insert multiple instructions.
814-
const auto &NonLibcallCSI = getNonLibcallCSI(CSI);
943+
const auto &NonLibcallCSI = getNonLibcallCSI(*MF, CSI);
815944
for (auto &CS : reverse(NonLibcallCSI)) {
816945
Register Reg = CS.getReg();
817946
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
@@ -883,3 +1012,19 @@ bool RISCVFrameLowering::canUseAsEpilogue(const MachineBasicBlock &MBB) const {
8831012
// replacing the successor with our own tail return at the end of our block.
8841013
return SuccMBB->isReturnBlock() && SuccMBB->size() == 1;
8851014
}
1015+
1016+
bool RISCVFrameLowering::isSupportedStackID(TargetStackID::Value ID) const {
1017+
switch (ID) {
1018+
case TargetStackID::Default:
1019+
case TargetStackID::ScalableVector:
1020+
return true;
1021+
case TargetStackID::NoAlloc:
1022+
case TargetStackID::SGPRSpill:
1023+
return false;
1024+
}
1025+
llvm_unreachable("Invalid TargetStackID::Value");
1026+
}
1027+
1028+
TargetStackID::Value RISCVFrameLowering::getStackIDForScalableVectors() const {
1029+
return TargetStackID::ScalableVector;
1030+
}

llvm/lib/Target/RISCV/RISCVFrameLowering.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ class RISCVFrameLowering : public TargetFrameLowering {
6565
bool canUseAsPrologue(const MachineBasicBlock &MBB) const override;
6666
bool canUseAsEpilogue(const MachineBasicBlock &MBB) const override;
6767

68+
bool isSupportedStackID(TargetStackID::Value ID) const override;
69+
TargetStackID::Value getStackIDForScalableVectors() const override;
70+
6871
protected:
6972
const RISCVSubtarget &STI;
7073

@@ -73,6 +76,10 @@ class RISCVFrameLowering : public TargetFrameLowering {
7376
void adjustReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
7477
const DebugLoc &DL, Register DestReg, Register SrcReg,
7578
int64_t Val, MachineInstr::MIFlag Flag) const;
79+
void adjustStackForRVV(MachineFunction &MF, MachineBasicBlock &MBB,
80+
MachineBasicBlock::iterator MBBI, const DebugLoc &DL,
81+
int64_t Amount) const;
82+
int64_t assignRVVStackObjectOffsets(MachineFrameInfo &MFI) const;
7683
};
7784
}
7885
#endif

llvm/lib/Target/RISCV/RISCVInstrInfo.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,3 +1112,43 @@ MachineInstr *RISCVInstrInfo::commuteInstructionImpl(MachineInstr &MI,
11121112
#undef CASE_VFMA_SPLATS
11131113
#undef CASE_VFMA_OPCODE_LMULS
11141114
#undef CASE_VFMA_OPCODE_COMMON
1115+
1116+
Register RISCVInstrInfo::getVLENFactoredAmount(MachineFunction &MF,
1117+
MachineBasicBlock &MBB,
1118+
MachineBasicBlock::iterator II,
1119+
int64_t Amount) const {
1120+
assert(Amount > 0 && "There is no need to get VLEN scaled value.");
1121+
assert(Amount % 8 == 0 &&
1122+
"Reserve the stack by the multiple of one vector size.");
1123+
1124+
MachineRegisterInfo &MRI = MF.getRegInfo();
1125+
const RISCVInstrInfo *TII = MF.getSubtarget<RISCVSubtarget>().getInstrInfo();
1126+
DebugLoc DL = II->getDebugLoc();
1127+
int64_t NumOfVReg = Amount / 8;
1128+
1129+
Register SizeOfVector = MRI.createVirtualRegister(&RISCV::GPRRegClass);
1130+
BuildMI(MBB, II, DL, TII->get(RISCV::PseudoReadVLENB), SizeOfVector);
1131+
Register FactorRegister = MRI.createVirtualRegister(&RISCV::GPRRegClass);
1132+
assert(isInt<12>(NumOfVReg) &&
1133+
"Expect the number of vector registers within 12-bits.");
1134+
if (isPowerOf2_32(NumOfVReg)) {
1135+
uint32_t ShiftAmount = Log2_32(NumOfVReg);
1136+
if (ShiftAmount == 0)
1137+
return SizeOfVector;
1138+
BuildMI(MBB, II, DL, TII->get(RISCV::SLLI), FactorRegister)
1139+
.addReg(SizeOfVector, RegState::Kill)
1140+
.addImm(ShiftAmount);
1141+
} else {
1142+
Register VN = MRI.createVirtualRegister(&RISCV::GPRRegClass);
1143+
BuildMI(MBB, II, DL, TII->get(RISCV::ADDI), VN)
1144+
.addReg(RISCV::X0)
1145+
.addImm(NumOfVReg);
1146+
assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtM() &&
1147+
"M-extension must be enabled to calculate the vscaled size/offset.");
1148+
BuildMI(MBB, II, DL, TII->get(RISCV::MUL), FactorRegister)
1149+
.addReg(SizeOfVector, RegState::Kill)
1150+
.addReg(VN, RegState::Kill);
1151+
}
1152+
1153+
return FactorRegister;
1154+
}

0 commit comments

Comments
 (0)