diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.h b/llvm/lib/Target/RISCV/RISCVFrameLowering.h --- a/llvm/lib/Target/RISCV/RISCVFrameLowering.h +++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.h @@ -73,6 +73,12 @@ bool isSupportedStackID(TargetStackID::Value ID) const override; TargetStackID::Value getStackIDForScalableVectors() const override; + bool isStackIdSafeForLocalArea(unsigned StackId) const override { + // We don't support putting SVE objects into the pre-allocated local + // frame block at the moment. + return StackId != TargetStackID::ScalableVector; + } + protected: const RISCVSubtarget &STI; 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 @@ -52,6 +52,18 @@ return true; } + bool requiresVirtualBaseRegisters(const MachineFunction &MF) const override { + return true; + } + + 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; + const TargetRegisterClass * getPointerRegClass(const MachineFunction &MF, unsigned Kind = 0) 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 @@ -351,3 +351,126 @@ RISCVRegisterInfo::getRegisterCostTableIndex(const MachineFunction &MF) const { return MF.getSubtarget().hasStdExtC() ? 1 : 0; } + +/// needsFrameBaseReg - Returns true if the instruction's frame index +/// reference would be better served by a base register other than FP +/// or SP. Used by LocalStackFrameAllocation 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!"); + + // It's the load/store FI references that cause issues, as it can be difficult + // to materialize the offset if it won't fit in the literal field. Estimate + // based on the size of the local frame and some conservative assumptions + // about the rest of the stack frame (note, this is pre-regalloc, so + // we don't know everything for certain yet) whether this offset is likely + // to be out of range of the immediate. Return true if so. + + // We only generate virtual base registers for loads and stores, so + // return false for everything else. + if (!MI->mayLoad() && !MI->mayStore()) + return false; + + // Without a virtual base register, if the function has variable sized + // objects, all fixed-size local references will be via the frame pointer, + // Approximate the offset and see if it's legal for the instruction. + // Note that the incoming offset is based on the SP value at function entry, + // so it'll be negative. + MachineFunction &MF = *MI->getParent()->getParent(); + const RISCVFrameLowering *TFI = getFrameLowering(MF); + MachineFrameInfo &MFI = MF.getFrameInfo(); + + // Estimate an offset from the frame pointer. + // Conservatively assume all GPR callee-saved registers get pushed. + // RA, S0-S11. + auto &Subtarget = MF.getSubtarget(); + int64_t FPOffset = Offset - (Subtarget.is64Bit() ? 104 : 52); + // Consider FS0-FS11 if present. + if (Subtarget.hasStdExtD()) + FPOffset -= 96; + else if (Subtarget.hasStdExtF()) + FPOffset -= 48; + + // Estimate an offset from the stack pointer. + // The incoming offset is relating to the SP at the start of the function, + // but when we access the local it'll be relative to the SP after local + // allocation, so adjust our SP-relative offset by that allocation size. + Offset += MFI.getLocalFrameSize(); + // Assume that we'll have at least some spill slots allocated. + // FIXME: This is a total SWAG number. We should run some statistics + // and pick a real one. + Offset += 128; // 128 bytes of spill slots + + // If there is a frame pointer, try using it. + // The FP is only available if there is no dynamic realignment. We + // don't know for sure yet whether we'll need that, so we guess based + // on whether there are any local variables that would trigger it. + if (TFI->hasFP(MF) && isFrameOffsetLegal(MI, RISCV::X8, FPOffset)) + return false; + + // If we can reference via the stack pointer or base pointer, try that. + // FIXME: This (and the code that resolves the references) can be improved + // to only disallow SP relative references in the live range of + // the VLA(s). In practice, it's unclear how much difference that + // would make, but it may be worth doing. + if (isFrameOffsetLegal(MI, RISCV::X2, Offset)) + return false; + + // If even offset 0 is illegal, we don't want a virtual base register. + if (!isFrameOffsetLegal(MI, RISCV::X2, 0)) + return false; + + // The offset likely isn't legal; we want to allocate a virtual base register. + return true; +} + +bool RISCVRegisterInfo::isFrameOffsetLegal(const MachineInstr *MI, + Register BaseReg, + int64_t Offset) const { + unsigned i = 0; + for (; !MI->getOperand(i).isFI(); ++i) + assert(i + 1 < MI->getNumOperands() && + "Instr doesn't have FrameIndex operand!"); + + Offset += MI->getOperand(i + 1).getImm(); + + return isInt<12>(Offset); +} + +/// materializeFrameBaseRegister - Insert defining instruction(s) for BaseReg to +/// be a pointer to FrameIdx at the beginning of the basic block. +Register RISCVRegisterInfo::materializeFrameBaseRegister(MachineBasicBlock *MBB, + int FrameIdx, + int64_t Offset) const { + MachineBasicBlock::iterator Ins = MBB->begin(); + DebugLoc DL; // Defaults to "unknown" + if (Ins != MBB->end()) + DL = Ins->getDebugLoc(); + + const MachineFunction &MF = *MBB->getParent(); + MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo(); + const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); + const MCInstrDesc &MCID = TII.get(RISCV::ADDI); + Register BaseReg = MRI.createVirtualRegister(&RISCV::GPRRegClass); + + BuildMI(*MBB, Ins, DL, MCID, BaseReg).addFrameIndex(FrameIdx).addImm(Offset); + + return BaseReg; +} + +void RISCVRegisterInfo::resolveFrameIndex(MachineInstr &MI, Register BaseReg, + int64_t Offset) const { + unsigned i = 0; + while (!MI.getOperand(i).isFI()) { + ++i; + assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!"); + } + + Offset += MI.getOperand(i + 1).getImm(); + assert(isInt<12>(Offset)); + MI.getOperand(i).ChangeToRegister(BaseReg, false); + MI.getOperand(i + 1).ChangeToImmediate(Offset); +}