Skip to content

Commit 82c820b

Browse files
author
luxufan
committed
[RISCV] Enable the LocalStackSlotAllocation pass support
For RISC-V, load/store(exclude vector load/store) instructions only has a 12 bit immediate operand. If the offset is out-of-range, it must make use of a temp register to make up this offset. If between these offsets, they have a small(IsInt<12>) relative offset, LocalStackSlotAllocation pass can find a value as frame base register's value, and replace the origin offset with this register's value plus the relative offset. Reviewed By: craig.topper Differential Revision: https://reviews.llvm.org/D98101
1 parent 2ca5fcb commit 82c820b

File tree

4 files changed

+131
-9
lines changed

4 files changed

+131
-9
lines changed

llvm/lib/Target/RISCV/RISCVFrameLowering.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ class RISCVFrameLowering : public TargetFrameLowering {
7373
bool isSupportedStackID(TargetStackID::Value ID) const override;
7474
TargetStackID::Value getStackIDForScalableVectors() const override;
7575

76+
bool isStackIdSafeForLocalArea(unsigned StackId) const override {
77+
// We don't support putting RISCV Vector objects into the pre-allocated
78+
// local frame block at the moment.
79+
return StackId != TargetStackID::ScalableVector;
80+
}
81+
7682
protected:
7783
const RISCVSubtarget &STI;
7884

llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,113 @@ void RISCVRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
295295
}
296296
}
297297

298+
bool RISCVRegisterInfo::requiresVirtualBaseRegisters(
299+
const MachineFunction &MF) const {
300+
return true;
301+
}
302+
303+
// Returns true if the instruction's frame index reference would be better
304+
// served by a base register other than FP or SP.
305+
// Used by LocalStackSlotAllocation pass to determine which frame index
306+
// references it should create new base registers for.
307+
bool RISCVRegisterInfo::needsFrameBaseReg(MachineInstr *MI,
308+
int64_t Offset) const {
309+
unsigned FIOperandNum = 0;
310+
for (; !MI->getOperand(FIOperandNum).isFI(); FIOperandNum++)
311+
assert(FIOperandNum < MI->getNumOperands() &&
312+
"Instr doesn't have FrameIndex operand");
313+
314+
// For RISC-V, The machine instructions that include a FrameIndex operand
315+
// are load/store, ADDI instructions.
316+
unsigned MIFrm = RISCVII::getFormat(MI->getDesc().TSFlags);
317+
if (MIFrm != RISCVII::InstFormatI && MIFrm != RISCVII::InstFormatS)
318+
return false;
319+
320+
const MachineFunction &MF = *MI->getMF();
321+
const MachineFrameInfo &MFI = MF.getFrameInfo();
322+
const RISCVFrameLowering *TFI = getFrameLowering(MF);
323+
const MachineRegisterInfo &MRI = MF.getRegInfo();
324+
unsigned CalleeSavedSize = 0;
325+
Offset += getFrameIndexInstrOffset(MI, FIOperandNum);
326+
327+
// Estimate the stack size used to store callee saved registers(
328+
// excludes reserved registers).
329+
BitVector ReservedRegs = getReservedRegs(MF);
330+
for (const MCPhysReg *R = MRI.getCalleeSavedRegs(); MCPhysReg Reg = *R; ++R) {
331+
if (!ReservedRegs.test(Reg))
332+
CalleeSavedSize += getSpillSize(*getMinimalPhysRegClass(Reg));
333+
}
334+
335+
int64_t MaxFPOffset = Offset - CalleeSavedSize;
336+
if (TFI->hasFP(MF) && !shouldRealignStack(MF))
337+
return !isFrameOffsetLegal(MI, RISCV::X8, MaxFPOffset);
338+
339+
// Assume 128 bytes spill slots size to estimate the maximum possible
340+
// offset relative to the stack pointer.
341+
// FIXME: The 128 is copied from ARM. We should run some statistics and pick a
342+
// real one for RISC-V.
343+
int64_t MaxSPOffset = Offset + 128;
344+
MaxSPOffset += MFI.getLocalFrameSize();
345+
return !isFrameOffsetLegal(MI, RISCV::X2, MaxSPOffset);
346+
}
347+
348+
// Determine whether a given base register plus offset immediate is
349+
// encodable to resolve a frame index.
350+
bool RISCVRegisterInfo::isFrameOffsetLegal(const MachineInstr *MI,
351+
Register BaseReg,
352+
int64_t Offset) const {
353+
return isInt<12>(Offset);
354+
}
355+
356+
// Insert defining instruction(s) for a pointer to FrameIdx before
357+
// insertion point I.
358+
// Return materialized frame pointer.
359+
Register RISCVRegisterInfo::materializeFrameBaseRegister(MachineBasicBlock *MBB,
360+
int FrameIdx,
361+
int64_t Offset) const {
362+
MachineBasicBlock::iterator MBBI = MBB->begin();
363+
DebugLoc DL;
364+
if (MBBI != MBB->end())
365+
DL = MBBI->getDebugLoc();
366+
MachineFunction *MF = MBB->getParent();
367+
MachineRegisterInfo &MFI = MF->getRegInfo();
368+
const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
369+
370+
Register BaseReg = MFI.createVirtualRegister(&RISCV::GPRRegClass);
371+
BuildMI(*MBB, MBBI, DL, TII->get(RISCV::ADDI), BaseReg)
372+
.addFrameIndex(FrameIdx)
373+
.addImm(Offset);
374+
return BaseReg;
375+
}
376+
377+
// Resolve a frame index operand of an instruction to reference the
378+
// indicated base register plus offset instead.
379+
void RISCVRegisterInfo::resolveFrameIndex(MachineInstr &MI, Register BaseReg,
380+
int64_t Offset) const {
381+
unsigned FIOperandNum = 0;
382+
while (!MI.getOperand(FIOperandNum).isFI())
383+
FIOperandNum++;
384+
assert(FIOperandNum < MI.getNumOperands() &&
385+
"Instr does not have a FrameIndex operand!");
386+
Offset += getFrameIndexInstrOffset(&MI, FIOperandNum);
387+
// FrameIndex Operands are always represented as a
388+
// register followed by an immediate.
389+
MI.getOperand(FIOperandNum).ChangeToRegister(BaseReg, false);
390+
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
391+
}
392+
393+
// Get the offset from the referenced frame index in the instruction,
394+
// if there is one.
395+
int64_t RISCVRegisterInfo::getFrameIndexInstrOffset(const MachineInstr *MI,
396+
int Idx) const {
397+
assert((RISCVII::getFormat(MI->getDesc().TSFlags) == RISCVII::InstFormatI ||
398+
RISCVII::getFormat(MI->getDesc().TSFlags) == RISCVII::InstFormatS) &&
399+
"The MI must be I or S format.");
400+
assert(MI->getOperand(Idx).isFI() && "The Idx'th operand of MI is not a "
401+
"FrameIndex operand");
402+
return MI->getOperand(Idx + 1).getImm();
403+
}
404+
298405
Register RISCVRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
299406
const TargetFrameLowering *TFI = getFrameLowering(MF);
300407
return TFI->hasFP(MF) ? RISCV::X8 : RISCV::X2;

llvm/lib/Target/RISCV/RISCVRegisterInfo.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@ struct RISCVRegisterInfo : public RISCVGenRegisterInfo {
3838
bool hasReservedSpillSlot(const MachineFunction &MF, Register Reg,
3939
int &FrameIdx) const override;
4040

41+
bool requiresVirtualBaseRegisters(const MachineFunction &MF) const override;
42+
43+
bool needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const override;
44+
45+
bool isFrameOffsetLegal(const MachineInstr *MI, Register BaseReg,
46+
int64_t Offset) const override;
47+
48+
Register materializeFrameBaseRegister(MachineBasicBlock *MBB, int FrameIdx,
49+
int64_t Offset) const override;
50+
51+
void resolveFrameIndex(MachineInstr &MI, Register BaseReg,
52+
int64_t Offset) const override;
53+
54+
int64_t getFrameIndexInstrOffset(const MachineInstr *MI,
55+
int Idx) const override;
56+
4157
void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj,
4258
unsigned FIOperandNum,
4359
RegScavenger *RS = nullptr) const override;

llvm/test/CodeGen/RISCV/local-stack-slot-allocation.ll

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
; This test case test the LocalStackSlotAllocation pass that use a base register
66
; for the frame index that its offset is out-of-range (for RISC-V. the immediate
77
; is 12 bits for the load store instruction (excludes vector load / store))
8-
; TODO: Enable LocalStackSlotAllocation pass.
98
define void @use_frame_base_reg() {
109
; RV32I-LABEL: use_frame_base_reg:
1110
; RV32I: # %bb.0:
@@ -14,12 +13,9 @@ define void @use_frame_base_reg() {
1413
; RV32I-NEXT: sub sp, sp, a0
1514
; RV32I-NEXT: .cfi_def_cfa_offset 100016
1615
; RV32I-NEXT: lui a0, 24
17-
; RV32I-NEXT: addi a0, a0, 1708
18-
; RV32I-NEXT: add a0, sp, a0
19-
; RV32I-NEXT: lb a0, 0(a0)
20-
; RV32I-NEXT: lui a0, 24
2116
; RV32I-NEXT: addi a0, a0, 1704
2217
; RV32I-NEXT: add a0, sp, a0
18+
; RV32I-NEXT: lb a1, 4(a0)
2319
; RV32I-NEXT: lb a0, 0(a0)
2420
; RV32I-NEXT: lui a0, 24
2521
; RV32I-NEXT: addi a0, a0, 1712
@@ -33,12 +29,9 @@ define void @use_frame_base_reg() {
3329
; RV64I-NEXT: sub sp, sp, a0
3430
; RV64I-NEXT: .cfi_def_cfa_offset 100016
3531
; RV64I-NEXT: lui a0, 24
36-
; RV64I-NEXT: addiw a0, a0, 1708
37-
; RV64I-NEXT: add a0, sp, a0
38-
; RV64I-NEXT: lb a0, 0(a0)
39-
; RV64I-NEXT: lui a0, 24
4032
; RV64I-NEXT: addiw a0, a0, 1704
4133
; RV64I-NEXT: add a0, sp, a0
34+
; RV64I-NEXT: lb a1, 4(a0)
4235
; RV64I-NEXT: lb a0, 0(a0)
4336
; RV64I-NEXT: lui a0, 24
4437
; RV64I-NEXT: addiw a0, a0, 1712

0 commit comments

Comments
 (0)