Index: lib/Target/RISCV/RISCVFrameLowering.h =================================================================== --- lib/Target/RISCV/RISCVFrameLowering.h +++ lib/Target/RISCV/RISCVFrameLowering.h @@ -49,6 +49,9 @@ private: void determineFrameLayout(MachineFunction &MF) const; + void adjustReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, + int64_t Val, MachineInstr::MIFlag Flag) const; }; } #endif Index: lib/Target/RISCV/RISCVFrameLowering.cpp =================================================================== --- lib/Target/RISCV/RISCVFrameLowering.cpp +++ lib/Target/RISCV/RISCVFrameLowering.cpp @@ -57,6 +57,49 @@ MFI.setStackSize(FrameSize); } +void RISCVFrameLowering::adjustReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, unsigned DestReg, + unsigned SrcReg, int64_t Val, + MachineInstr::MIFlag Flag) const { + MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); + const RISCVInstrInfo *TII = STI.getInstrInfo(); + + if (DestReg == SrcReg && Val == 0) + return; + + if (isInt<12>(Val)) { + BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), DestReg) + .addReg(SrcReg) + .addImm(Val) + .setMIFlag(Flag); + } else if (isInt<32>(Val)) { + unsigned Opc = RISCV::ADD; + bool isSub = Val < 0; + if (isSub) { + Val = -Val; + Opc = RISCV::SUB; + } + + unsigned ScratchReg = MRI.createVirtualRegister(&RISCV::GPRRegClass); + uint64_t Hi20 = ((Val + 0x800) >> 12) & 0xfffff; + uint64_t Lo12 = SignExtend64<12>(Val); + BuildMI(MBB, MBBI, DL, TII->get(RISCV::LUI), ScratchReg) + .addImm(Hi20) + .setMIFlag(Flag); + BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), ScratchReg) + .addReg(ScratchReg, RegState::Kill) + .addImm(Lo12) + .setMIFlag(Flag); + BuildMI(MBB, MBBI, DL, TII->get(Opc), DestReg) + .addReg(SrcReg) + .addReg(ScratchReg, RegState::Kill) + .setMIFlag(Flag); + } else { + report_fatal_error("adjustReg cannot yet handle adjustments >32 bits"); + } +} + void RISCVFrameLowering::emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const { assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported"); @@ -67,7 +110,6 @@ } MachineFrameInfo &MFI = MF.getFrameInfo(); - const RISCVInstrInfo *TII = STI.getInstrInfo(); auto *RVFI = MF.getInfo(); MachineBasicBlock::iterator MBBI = MBB.begin(); @@ -89,17 +131,8 @@ if (StackSize == 0 && !MFI.adjustsStack()) return; - if (!isInt<12>(StackSize)) { - report_fatal_error("Stack adjustment won't fit in signed 12-bit immediate"); - } - // Allocate space on the stack if necessary. - if (StackSize != 0) { - BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), SPReg) - .addReg(SPReg) - .addImm(-StackSize) - .setMIFlag(MachineInstr::FrameSetup); - } + adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup); // The frame pointer is callee-saved, and code has been generated for us to // save it to the stack. We need to skip over the storing of callee-saved @@ -111,10 +144,8 @@ std::advance(MBBI, CSI.size()); // Generate new FP. - BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), FPReg) - .addReg(SPReg) - .addImm(StackSize - RVFI->getVarArgsSaveSize()) - .setMIFlag(MachineInstr::FrameSetup); + adjustReg(MBB, MBBI, DL, FPReg, SPReg, StackSize - RVFI->getVarArgsSaveSize(), + MachineInstr::FrameSetup); } void RISCVFrameLowering::emitEpilogue(MachineFunction &MF, @@ -125,7 +156,6 @@ } MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); - const RISCVInstrInfo *TII = STI.getInstrInfo(); const RISCVRegisterInfo *RI = STI.getRegisterInfo(); MachineFrameInfo &MFI = MF.getFrameInfo(); auto *RVFI = MF.getInfo(); @@ -145,21 +175,13 @@ // necessary if the stack pointer was modified, meaning the stack size is // unknown. if (RI->needsStackRealignment(MF) || MFI.hasVarSizedObjects()) { - BuildMI(MBB, LastFrameDestroy, DL, TII->get(RISCV::ADDI), SPReg) - .addReg(FPReg) - .addImm(-StackSize + RVFI->getVarArgsSaveSize()) - .setMIFlag(MachineInstr::FrameDestroy); - } - - if (!isInt<12>(StackSize)) { - report_fatal_error("Stack adjustment won't fit in signed 12-bit immediate"); + adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg, + -StackSize + RVFI->getVarArgsSaveSize(), + MachineInstr::FrameDestroy); } // Deallocate stack - BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), SPReg) - .addReg(SPReg) - .addImm(StackSize) - .setMIFlag(MachineInstr::FrameDestroy); + adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy); } int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, Index: lib/Target/RISCV/RISCVRegisterInfo.h =================================================================== --- lib/Target/RISCV/RISCVRegisterInfo.h +++ lib/Target/RISCV/RISCVRegisterInfo.h @@ -39,6 +39,14 @@ RegScavenger *RS = nullptr) const override; unsigned getFrameRegister(const MachineFunction &MF) const override; + + bool requiresRegisterScavenging(const MachineFunction &MF) const override { + return true; + } + + bool requiresFrameIndexScavenging(const MachineFunction &MF) const override { + return true; + } }; } Index: lib/Target/RISCV/RISCVRegisterInfo.cpp =================================================================== --- lib/Target/RISCV/RISCVRegisterInfo.cpp +++ lib/Target/RISCV/RISCVRegisterInfo.cpp @@ -61,6 +61,8 @@ MachineInstr &MI = *II; MachineFunction &MF = *MI.getParent()->getParent(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); DebugLoc DL = MI.getDebugLoc(); int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); @@ -72,13 +74,34 @@ assert(MF.getSubtarget().getFrameLowering()->hasFP(MF) && "eliminateFrameIndex currently requires hasFP"); - // Offsets must be directly encoded in a 12-bit immediate field - if (!isInt<12>(Offset)) { + if (!isInt<32>(Offset)) { report_fatal_error( - "Frame offsets outside of the signed 12-bit range not supported"); + "Frame offsets outside of the signed 32-bit range not supported"); + } + + MachineBasicBlock &MBB = *MI.getParent(); + bool FrameRegIsKill = false; + + if (!isInt<12>(Offset)) { + // The offset won't fit in an immediate, so use a scratch register instead + // Modify Offset and FrameReg appropriately + unsigned ScratchReg = MRI.createVirtualRegister(&RISCV::GPRRegClass); + uint64_t Hi20 = ((Offset + 0x800) >> 12) & 0xfffff; + uint64_t Lo12 = SignExtend64<12>(Offset); + BuildMI(MBB, II, DL, TII->get(RISCV::LUI), ScratchReg).addImm(Hi20); + BuildMI(MBB, II, DL, TII->get(RISCV::ADDI), ScratchReg) + .addReg(ScratchReg, RegState::Kill) + .addImm(Lo12); + BuildMI(MBB, II, DL, TII->get(RISCV::ADD), ScratchReg) + .addReg(FrameReg) + .addReg(ScratchReg, RegState::Kill); + Offset = 0; + FrameReg = ScratchReg; + FrameRegIsKill = true; } - MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false); + MI.getOperand(FIOperandNum) + .ChangeToRegister(FrameReg, false, false, FrameRegIsKill); MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); } Index: test/CodeGen/RISCV/large-stack.ll =================================================================== --- /dev/null +++ test/CodeGen/RISCV/large-stack.ll @@ -0,0 +1,38 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32I %s + +; TODO: the quality of the generated code is poor + +define void @test() nounwind { +; RV32I-LABEL: test: +; RV32I: # BB#0: +; RV32I-NEXT: lui a0, 74565 +; RV32I-NEXT: addi a0, a0, 1664 +; RV32I-NEXT: sub sp, sp, a0 +; RV32I-NEXT: lui a0, 74565 +; RV32I-NEXT: addi a0, a0, 1660 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: sw ra, 0(a0) +; RV32I-NEXT: lui a0, 74565 +; RV32I-NEXT: addi a0, a0, 1656 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: sw s0, 0(a0) +; RV32I-NEXT: lui a0, 74565 +; RV32I-NEXT: addi a0, a0, 1664 +; RV32I-NEXT: add s0, sp, a0 +; RV32I-NEXT: lui a0, 74565 +; RV32I-NEXT: addi a0, a0, 1656 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: lw s0, 0(a0) +; RV32I-NEXT: lui a0, 74565 +; RV32I-NEXT: addi a0, a0, 1660 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: lw ra, 0(a0) +; RV32I-NEXT: lui a0, 74565 +; RV32I-NEXT: addi a0, a0, 1664 +; RV32I-NEXT: add sp, sp, a0 +; RV32I-NEXT: jalr zero, ra, 0 + %tmp = alloca [ 305419896 x i8 ] , align 4 + ret void +}