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 @@ -288,6 +288,109 @@ } } +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 pass to determine which frame index references it +// should create new base registers for. +bool RISCVRegisterInfo::needsFrameBaseReg(MachineInstr *MI, + int64_t Offset) const { + unsigned FIIndex = 0; + for (; !MI->getOperand(FIIndex).isFI(); FIIndex++) + assert(FIIndex < MI->getNumOperands() && + "Instr doesn't have FrameIndex operand"); + + // For RISC-V, The machine instructions that include a FrameIndex operand + // are load/store, ADDI instructions. + switch (MI->getOpcode()) { + case RISCV::LB: case RISCV::LH: case RISCV::LW: case RISCV::LD: + case RISCV::SB: case RISCV::SH: case RISCV::SW: case RISCV::SD: + case RISCV::FLH: case RISCV::FLW: case RISCV::FLD: + case RISCV::FSH: case RISCV::FSW: case RISCV::FSD: + case RISCV::ADDI: + break; + default: + return false; + } + + const MachineFunction &MF = *MI->getMF(); + const MachineFrameInfo &MFI = MF.getFrameInfo(); + const RISCVFrameLowering *TFI = getFrameLowering(MF); + unsigned int SizeOfGPRInByte = getRegSizeInBits(RISCV::GPRRegClass) / 8; + Offset += getFrameIndexInstrOffset(MI, FIIndex); + // Assume all the callee saved registers are modified to estimate the + // maximum possible offset that relative to the frame pointer + // Callee saved registers: X1, X3, X4, X8-9, X18-27. + int64_t MaxFPOffset = Offset - SizeOfGPRInByte * 15; + if (TFI->hasFP(MF) && !shouldRealignStack(MF)) + return !isFrameOffsetLegal(MI, RISCV::X8, MaxFPOffset); + + // Assume 128 bytes spill slots size to estimate the maximum 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++; + Offset += getFrameIndexInstrOffset(&MI, 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,9 @@ ; 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: lb a1, 4(a0) ; CHECK-NEXT: lb a0, 0(a0) ; CHECK-NEXT: lui a0, 24 ; CHECK-NEXT: addiw a0, a0, 1712