diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.h b/llvm/lib/Target/RISCV/RISCVRegisterInfo.h --- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.h +++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.h @@ -40,6 +40,22 @@ bool hasReservedSpillSlot(const MachineFunction &MF, Register Reg, int &FrameIdx) const override; + bool requiresVirtualBaseRegisters(const MachineFunction &MF) const override; + + bool needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const override; + + bool isFrameOffsetLegal(const MachineInstr *MI, Register BaseReg, + int64_t Offset) const override; + + Register materializeFrameBaseRegister(MachineBasicBlock *MBB, int FrameIdx, + int64_t Offset) const override; + + void resolveFrameIndex(MachineInstr &MI, Register BaseReg, + int64_t Offset) const override; + + int64_t getFrameIndexInstrOffset(const MachineInstr *MI, + int Idx) const override; + void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj, unsigned FIOperandNum, RegScavenger *RS = nullptr) const override; diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp --- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp @@ -270,6 +270,100 @@ } } +// Returns true if the target wants the LocalStackSlotAllocation pass to be run +// and virtual base regsiters used for more efficient stack access. +bool RISCVRegisterInfo::requiresVirtualBaseRegisters( + const MachineFunction &MF) const { + return true; +} + +// returns true if the instruction's frame index reference would be better +// served by a base register other than FP or SP. +// Used by LocalStackSlotAllocation to determine which frame index references it +// should create new base registers for. +bool RISCVRegisterInfo::needsFrameBaseReg(MachineInstr *MI, + int64_t Offset) const { + for (unsigned i = 0; !MI->getOperand(i).isFI(); ++i) + assert(i < MI->getNumOperands() && + "Instr doesn't have FrameIndex Operand!"); + + // For RISC-V, The machine instructions that include a FrameIndex operand + // are load/store, ADDI instructions. + if (!MI->mayLoad() && !MI->mayStore() && !(MI->getOpcode() == RISCV::ADDI)) + return false; + + const MachineFunction &MF = *MI->getMF(); + const MachineFrameInfo &MFI = MF.getFrameInfo(); + const RISCVFrameLowering *TFI = getFrameLowering(MF); + unsigned int SizeOfGPRInBytes = getRegSizeInBits(RISCV::GPRRegClass) / 8; + // Assume all the callee saved registers are modified to estimate the max + // possible offset that relative to frame pointer + // Callee saved registers: X1, X3, X4, X8-9, X18-27. + int64_t MaxFPOffset = Offset - SizeOfGPRInBytes * 15; + if (TFI->hasFP(MF) && !needsStackRealignment(MF)) + return !isFrameOffsetLegal(MI, RISCV::X8, MaxFPOffset); + + // Assume 128 bytes spill slots size to estimate the max possible offset that + // relative to the stack pointer + int64_t MaxSPOffset = Offset + 128; + MaxSPOffset += MFI.getLocalFrameSize(); + return !isFrameOffsetLegal(MI, RISCV::X2, MaxSPOffset); +} + +// Determine whether a given base register plus offset immediate is +// encodable to resolve a frame index. +bool RISCVRegisterInfo::isFrameOffsetLegal(const MachineInstr *MI, + Register BaseReg, + int64_t Offset) const { + return isInt<12>(Offset); +} + +// Insert defining instruction(s) for a pointer to FrameIdx before +// insertion point I. Return materialized frame pointer +Register RISCVRegisterInfo::materializeFrameBaseRegister(MachineBasicBlock *MBB, + int FrameIdx, + int64_t Offset) const { + MachineBasicBlock::iterator MBBI = MBB->begin(); + DebugLoc DL; + if (MBBI != MBB->end()) + DL = MBBI->getDebugLoc(); + MachineFunction *MF = MBB->getParent(); + MachineRegisterInfo &MFI = MF->getRegInfo(); + const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo(); + + Register BaseReg = MFI.createVirtualRegister(&RISCV::GPRRegClass); + BuildMI(*MBB, MBBI, DL, TII->get(RISCV::ADDI), BaseReg) + .addFrameIndex(FrameIdx) + .addImm(Offset); + return BaseReg; +} + +// Resolve a frame index operand of an instruction +// to reference the indicated base register plus offset instead +void RISCVRegisterInfo::resolveFrameIndex(MachineInstr &MI, Register BaseReg, + int64_t Offset) const { + unsigned FIIndex = 0; + while (!MI.getOperand(FIIndex).isFI()) + FIIndex++; + + // For RISC-V, only load/store, ADDI machine instruction + // has a FrameIndex operand. These instructions' immediate operand + // follow the FrameIndex operand + unsigned ImmIndex = FIIndex + 1; + + MI.getOperand(FIIndex).ChangeToRegister(BaseReg, false); + MI.getOperand(ImmIndex).ChangeToImmediate(Offset); +} + +// Get the offset from the referenced frame index in the instruction, +// if there is one +int64_t RISCVRegisterInfo::getFrameIndexInstrOffset(const MachineInstr *MI, + int Idx) const { + assert(MI->getOperand(Idx).isFI() && "The Idx'th operand of MI is not a " + "FrameIndex operand"); + return MI->getOperand(Idx + 1).getImm(); +} + Register RISCVRegisterInfo::getFrameRegister(const MachineFunction &MF) const { const TargetFrameLowering *TFI = getFrameLowering(MF); return TFI->hasFP(MF) ? RISCV::X8 : RISCV::X2; diff --git a/llvm/test/CodeGen/RISCV/local-stack-allocation.ll b/llvm/test/CodeGen/RISCV/local-stack-allocation.ll --- a/llvm/test/CodeGen/RISCV/local-stack-allocation.ll +++ b/llvm/test/CodeGen/RISCV/local-stack-allocation.ll @@ -12,12 +12,10 @@ ; CHECK-NEXT: sub sp, sp, a0 ; CHECK-NEXT: .cfi_def_cfa_offset 100016 ; CHECK-NEXT: lui a0, 24 -; CHECK-NEXT: addiw a0, a0, 1708 -; CHECK-NEXT: add a0, sp, a0 -; CHECK-NEXT: lb a0, 0(a0) -; CHECK-NEXT: lui a0, 24 ; CHECK-NEXT: addiw a0, a0, 1704 ; CHECK-NEXT: add a0, sp, a0 +; CHECK-NEXT: mv a0, a0 +; CHECK-NEXT: lb a1, 4(a0) ; CHECK-NEXT: lb a0, 0(a0) ; CHECK-NEXT: lui a0, 24 ; CHECK-NEXT: addiw a0, a0, 1712