diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2022-01-27 22:06:42 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2022-01-27 22:06:42 +0000 |
commit | 6f8fc217eaa12bf657be1c6468ed9938d10168b3 (patch) | |
tree | a1fd89b864d9b93e2ad68fe1dcf7afee2e3c8d76 /llvm/lib/Target/CSKY/CSKYFrameLowering.cpp | |
parent | 77fc4c146f0870ffb09c1afb823ccbe742c5e6ff (diff) |
Diffstat (limited to 'llvm/lib/Target/CSKY/CSKYFrameLowering.cpp')
-rw-r--r-- | llvm/lib/Target/CSKY/CSKYFrameLowering.cpp | 548 |
1 files changed, 546 insertions, 2 deletions
diff --git a/llvm/lib/Target/CSKY/CSKYFrameLowering.cpp b/llvm/lib/Target/CSKY/CSKYFrameLowering.cpp index 3a8ee5713584..3bf001c2cee7 100644 --- a/llvm/lib/Target/CSKY/CSKYFrameLowering.cpp +++ b/llvm/lib/Target/CSKY/CSKYFrameLowering.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "CSKYFrameLowering.h" +#include "CSKYMachineFunctionInfo.h" #include "CSKYSubtarget.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" @@ -46,12 +47,555 @@ bool CSKYFrameLowering::hasBP(const MachineFunction &MF) const { return MFI.hasVarSizedObjects(); } +// Determines the size of the frame and maximum call frame size. +void CSKYFrameLowering::determineFrameLayout(MachineFunction &MF) const { + MachineFrameInfo &MFI = MF.getFrameInfo(); + const CSKYRegisterInfo *RI = STI.getRegisterInfo(); + + // Get the number of bytes to allocate from the FrameInfo. + uint64_t FrameSize = MFI.getStackSize(); + + // Get the alignment. + Align StackAlign = getStackAlign(); + if (RI->hasStackRealignment(MF)) { + Align MaxStackAlign = std::max(StackAlign, MFI.getMaxAlign()); + FrameSize += (MaxStackAlign.value() - StackAlign.value()); + StackAlign = MaxStackAlign; + } + + // Set Max Call Frame Size + uint64_t MaxCallSize = alignTo(MFI.getMaxCallFrameSize(), StackAlign); + MFI.setMaxCallFrameSize(MaxCallSize); + + // Make sure the frame is aligned. + FrameSize = alignTo(FrameSize, StackAlign); + + // Update frame info. + MFI.setStackSize(FrameSize); +} + void CSKYFrameLowering::emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const { - // FIXME: Implement this when we have function calls + CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + const CSKYRegisterInfo *RI = STI.getRegisterInfo(); + const CSKYInstrInfo *TII = STI.getInstrInfo(); + MachineBasicBlock::iterator MBBI = MBB.begin(); + const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); + const MachineRegisterInfo &MRI = MF.getRegInfo(); + + Register FPReg = getFPReg(STI); + Register SPReg = CSKY::R14; + Register BPReg = getBPReg(STI); + + // Debug location must be unknown since the first debug location is used + // to determine the end of the prologue. + DebugLoc DL; + + if (MF.getFunction().hasFnAttribute("interrupt")) + BuildMI(MBB, MBBI, DL, TII->get(CSKY::NIE)); + + // Determine the correct frame layout + determineFrameLayout(MF); + + // FIXME (note copied from Lanai): This appears to be overallocating. Needs + // investigation. Get the number of bytes to allocate from the FrameInfo. + uint64_t StackSize = MFI.getStackSize(); + + // Early exit if there is no need to allocate on the stack + if (StackSize == 0 && !MFI.adjustsStack()) + return; + + const auto &CSI = MFI.getCalleeSavedInfo(); + + unsigned spillAreaSize = CFI->getCalleeSaveAreaSize(); + + uint64_t ActualSize = spillAreaSize + CFI->getVarArgsSaveSize(); + + // First part stack allocation. + adjustReg(MBB, MBBI, DL, SPReg, SPReg, -(static_cast<int64_t>(ActualSize)), + MachineInstr::NoFlags); + + // Emit ".cfi_def_cfa_offset FirstSPAdjustAmount" + unsigned CFIIndex = + MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, ActualSize)); + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + + // 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 + // registers as the frame pointer must be modified after it has been saved + // to the stack, not before. + // FIXME: assumes exactly one instruction is used to save each callee-saved + // register. + std::advance(MBBI, CSI.size()); + + // Iterate over list of callee-saved registers and emit .cfi_offset + // directives. + for (const auto &Entry : CSI) { + int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx()); + Register Reg = Entry.getReg(); + + unsigned Num = TRI->getRegSizeInBits(Reg, MRI) / 32; + for (unsigned i = 0; i < Num; i++) { + unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( + nullptr, RI->getDwarfRegNum(Reg, true) + i, Offset + i * 4)); + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } + } + + // Generate new FP. + if (hasFP(MF)) { + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::COPY), FPReg) + .addReg(SPReg) + .setMIFlag(MachineInstr::FrameSetup); + + // Emit ".cfi_def_cfa_register $fp" + unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfaRegister( + nullptr, RI->getDwarfRegNum(FPReg, true))); + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + + // Second part stack allocation. + adjustReg(MBB, MBBI, DL, SPReg, SPReg, + -(static_cast<int64_t>(StackSize - ActualSize)), + MachineInstr::NoFlags); + + // Realign Stack + const CSKYRegisterInfo *RI = STI.getRegisterInfo(); + if (RI->hasStackRealignment(MF)) { + Align MaxAlignment = MFI.getMaxAlign(); + + const CSKYInstrInfo *TII = STI.getInstrInfo(); + if (STI.hasE2() && isUInt<12>(~(-(int)MaxAlignment.value()))) { + BuildMI(MBB, MBBI, DL, TII->get(CSKY::ANDNI32), SPReg) + .addReg(SPReg) + .addImm(~(-(int)MaxAlignment.value())); + } else { + unsigned ShiftAmount = Log2(MaxAlignment); + + if (STI.hasE2()) { + Register VR = + MF.getRegInfo().createVirtualRegister(&CSKY::GPRRegClass); + BuildMI(MBB, MBBI, DL, TII->get(CSKY::LSRI32), VR) + .addReg(SPReg) + .addImm(ShiftAmount); + BuildMI(MBB, MBBI, DL, TII->get(CSKY::LSLI32), SPReg) + .addReg(VR) + .addImm(ShiftAmount); + } else { + Register VR = + MF.getRegInfo().createVirtualRegister(&CSKY::mGPRRegClass); + BuildMI(MBB, MBBI, DL, TII->get(CSKY::MOV16), VR).addReg(SPReg); + BuildMI(MBB, MBBI, DL, TII->get(CSKY::LSRI16), VR) + .addReg(VR) + .addImm(ShiftAmount); + BuildMI(MBB, MBBI, DL, TII->get(CSKY::LSLI16), VR) + .addReg(VR) + .addImm(ShiftAmount); + BuildMI(MBB, MBBI, DL, TII->get(CSKY::MOV16), SPReg).addReg(VR); + } + } + } + + // FP will be used to restore the frame in the epilogue, so we need + // another base register BP to record SP after re-alignment. SP will + // track the current stack after allocating variable sized objects. + if (hasBP(MF)) { + // move BP, SP + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::COPY), BPReg).addReg(SPReg); + } + + } else { + adjustReg(MBB, MBBI, DL, SPReg, SPReg, + -(static_cast<int64_t>(StackSize - ActualSize)), + MachineInstr::NoFlags); + // Emit ".cfi_def_cfa_offset StackSize" + unsigned CFIIndex = MF.addFrameInst( + MCCFIInstruction::cfiDefCfaOffset(nullptr, MFI.getStackSize())); + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } } void CSKYFrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { - // FIXME: Implement this when we have function calls + CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>(); + + MachineFrameInfo &MFI = MF.getFrameInfo(); + Register FPReg = getFPReg(STI); + Register SPReg = CSKY::R14; + + // Get the insert location for the epilogue. If there were no terminators in + // the block, get the last instruction. + MachineBasicBlock::iterator MBBI = MBB.end(); + DebugLoc DL; + if (!MBB.empty()) { + MBBI = MBB.getFirstTerminator(); + if (MBBI == MBB.end()) + MBBI = MBB.getLastNonDebugInstr(); + DL = MBBI->getDebugLoc(); + + // If this is not a terminator, the actual insert location should be after + // the last instruction. + if (!MBBI->isTerminator()) + MBBI = std::next(MBBI); + } + + const auto &CSI = MFI.getCalleeSavedInfo(); + uint64_t StackSize = MFI.getStackSize(); + + uint64_t ActualSize = + CFI->getCalleeSaveAreaSize() + CFI->getVarArgsSaveSize(); + + // Skip to before the restores of callee-saved registers + // FIXME: assumes exactly one instruction is used to restore each + // callee-saved register. + auto LastFrameDestroy = MBBI; + if (!CSI.empty()) + LastFrameDestroy = std::prev(MBBI, CSI.size()); + + if (hasFP(MF)) { + const CSKYInstrInfo *TII = STI.getInstrInfo(); + BuildMI(MBB, LastFrameDestroy, DL, TII->get(TargetOpcode::COPY), SPReg) + .addReg(FPReg) + .setMIFlag(MachineInstr::NoFlags); + } else { + adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, (StackSize - ActualSize), + MachineInstr::FrameDestroy); + } + + adjustReg(MBB, MBBI, DL, SPReg, SPReg, ActualSize, + MachineInstr::FrameDestroy); +} + +static unsigned estimateRSStackSizeLimit(MachineFunction &MF, + const CSKYSubtarget &STI) { + unsigned Limit = (1 << 12) - 1; + + for (auto &MBB : MF) { + for (auto &MI : MBB) { + if (MI.isDebugInstr()) + continue; + + for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { + if (!MI.getOperand(i).isFI()) + continue; + + if (MI.getOpcode() == CSKY::SPILL_CARRY || + MI.getOpcode() == CSKY::RESTORE_CARRY || + MI.getOpcode() == CSKY::STORE_PAIR || + MI.getOpcode() == CSKY::LOAD_PAIR) { + Limit = std::min(Limit, ((1U << 12) - 1) * 4); + break; + } + + if (MI.getOpcode() == CSKY::ADDI32) { + Limit = std::min(Limit, (1U << 12)); + break; + } + + if (MI.getOpcode() == CSKY::ADDI16XZ) { + Limit = std::min(Limit, (1U << 3)); + break; + } + + // ADDI16 will not require an extra register, + // it can reuse the destination. + if (MI.getOpcode() == CSKY::ADDI16) + break; + + // Otherwise check the addressing mode. + switch (MI.getDesc().TSFlags & CSKYII::AddrModeMask) { + default: + LLVM_DEBUG(MI.dump()); + llvm_unreachable( + "Unhandled addressing mode in stack size limit calculation"); + case CSKYII::AddrMode32B: + Limit = std::min(Limit, (1U << 12) - 1); + break; + case CSKYII::AddrMode32H: + Limit = std::min(Limit, ((1U << 12) - 1) * 2); + break; + case CSKYII::AddrMode32WD: + Limit = std::min(Limit, ((1U << 12) - 1) * 4); + break; + case CSKYII::AddrMode16B: + Limit = std::min(Limit, (1U << 5) - 1); + break; + case CSKYII::AddrMode16H: + Limit = std::min(Limit, ((1U << 5) - 1) * 2); + break; + case CSKYII::AddrMode16W: + Limit = std::min(Limit, ((1U << 5) - 1) * 4); + break; + case CSKYII::AddrMode32SDF: + Limit = std::min(Limit, ((1U << 8) - 1) * 4); + break; + } + break; // At most one FI per instruction + } + } + } + + return Limit; +} + +void CSKYFrameLowering::determineCalleeSaves(MachineFunction &MF, + BitVector &SavedRegs, + RegScavenger *RS) const { + TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); + + CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>(); + const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); + const MachineRegisterInfo &MRI = MF.getRegInfo(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + + if (hasFP(MF)) + SavedRegs.set(CSKY::R8); + + // Mark BP as used if function has dedicated base pointer. + if (hasBP(MF)) + SavedRegs.set(CSKY::R7); + + // If interrupt is enabled and there are calls in the handler, + // unconditionally save all Caller-saved registers and + // all FP registers, regardless whether they are used. + if (MF.getFunction().hasFnAttribute("interrupt") && MFI.hasCalls()) { + + static const MCPhysReg CSRegs[] = {CSKY::R0, CSKY::R1, CSKY::R2, CSKY::R3, + CSKY::R12, CSKY::R13, 0}; + + for (unsigned i = 0; CSRegs[i]; ++i) + SavedRegs.set(CSRegs[i]); + + if (STI.hasHighRegisters()) { + + static const MCPhysReg CSHRegs[] = {CSKY::R18, CSKY::R19, CSKY::R20, + CSKY::R21, CSKY::R22, CSKY::R23, + CSKY::R24, CSKY::R25, 0}; + + for (unsigned i = 0; CSHRegs[i]; ++i) + SavedRegs.set(CSHRegs[i]); + } + + static const MCPhysReg CSF32Regs[] = { + CSKY::F8_32, CSKY::F9_32, CSKY::F10_32, + CSKY::F11_32, CSKY::F12_32, CSKY::F13_32, + CSKY::F14_32, CSKY::F15_32, 0}; + static const MCPhysReg CSF64Regs[] = { + CSKY::F8_64, CSKY::F9_64, CSKY::F10_64, + CSKY::F11_64, CSKY::F12_64, CSKY::F13_64, + CSKY::F14_64, CSKY::F15_64, 0}; + + const MCPhysReg *FRegs = NULL; + if (STI.hasFPUv2DoubleFloat() || STI.hasFPUv3DoubleFloat()) + FRegs = CSF64Regs; + else if (STI.hasFPUv2SingleFloat() || STI.hasFPUv3SingleFloat()) + FRegs = CSF32Regs; + + if (FRegs != NULL) { + const MCPhysReg *Regs = MF.getRegInfo().getCalleeSavedRegs(); + + for (unsigned i = 0; Regs[i]; ++i) + if (CSKY::FPR32RegClass.contains(Regs[i]) || + CSKY::FPR64RegClass.contains(Regs[i])) { + unsigned x = 0; + for (; FRegs[x]; ++x) + if (FRegs[x] == Regs[i]) + break; + if (FRegs[x] == 0) + SavedRegs.set(Regs[i]); + } + } + } + + CFI->setLRIsSpilled(SavedRegs.test(CSKY::R15)); + + unsigned CSStackSize = 0; + for (unsigned Reg : SavedRegs.set_bits()) { + auto RegSize = TRI->getRegSizeInBits(Reg, MRI) / 8; + CSStackSize += RegSize; + } + + CFI->setCalleeSaveAreaSize(CSStackSize); + + uint64_t Limit = estimateRSStackSizeLimit(MF, STI); + + bool BigFrame = (MFI.estimateStackSize(MF) + CSStackSize >= Limit); + + if (BigFrame || CFI->isCRSpilled() || !STI.hasE2()) { + const TargetRegisterClass *RC = &CSKY::GPRRegClass; + unsigned size = TRI->getSpillSize(*RC); + Align align = TRI->getSpillAlign(*RC); + + RS->addScavengingFrameIndex(MFI.CreateStackObject(size, align, false)); + } +} + +// Not preserve stack space within prologue for outgoing variables when the +// function contains variable size objects and let eliminateCallFramePseudoInstr +// preserve stack space for it. +bool CSKYFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { + return !MF.getFrameInfo().hasVarSizedObjects(); +} + +bool CSKYFrameLowering::spillCalleeSavedRegisters( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, + ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { + if (CSI.empty()) + return true; + + MachineFunction *MF = MBB.getParent(); + const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); + DebugLoc DL; + if (MI != MBB.end() && !MI->isDebugInstr()) + DL = MI->getDebugLoc(); + + for (auto &CS : CSI) { + // Insert the spill to the stack frame. + Register Reg = CS.getReg(); + const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); + TII.storeRegToStackSlot(MBB, MI, Reg, true, CS.getFrameIdx(), RC, TRI); + } + + return true; +} + +bool CSKYFrameLowering::restoreCalleeSavedRegisters( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, + MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { + if (CSI.empty()) + return true; + + MachineFunction *MF = MBB.getParent(); + const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); + DebugLoc DL; + if (MI != MBB.end() && !MI->isDebugInstr()) + DL = MI->getDebugLoc(); + + for (auto &CS : reverse(CSI)) { + Register Reg = CS.getReg(); + const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); + TII.loadRegFromStackSlot(MBB, MI, Reg, CS.getFrameIdx(), RC, TRI); + assert(MI != MBB.begin() && "loadRegFromStackSlot didn't insert any code!"); + } + + return true; +} + +// Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions. +MachineBasicBlock::iterator CSKYFrameLowering::eliminateCallFramePseudoInstr( + MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const { + Register SPReg = CSKY::R14; + DebugLoc DL = MI->getDebugLoc(); + + if (!hasReservedCallFrame(MF)) { + // If space has not been reserved for a call frame, ADJCALLSTACKDOWN and + // ADJCALLSTACKUP must be converted to instructions manipulating the stack + // pointer. This is necessary when there is a variable length stack + // allocation (e.g. alloca), which means it's not possible to allocate + // space for outgoing arguments from within the function prologue. + int64_t Amount = MI->getOperand(0).getImm(); + + if (Amount != 0) { + // Ensure the stack remains aligned after adjustment. + Amount = alignSPAdjust(Amount); + + if (MI->getOpcode() == CSKY::ADJCALLSTACKDOWN) + Amount = -Amount; + + adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags); + } + } + + return MBB.erase(MI); +} + +void CSKYFrameLowering::adjustReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, Register DestReg, + Register SrcReg, int64_t Val, + MachineInstr::MIFlag Flag) const { + const CSKYInstrInfo *TII = STI.getInstrInfo(); + + if (DestReg == SrcReg && Val == 0) + return; + + // TODO: Add 16-bit instruction support with immediate num + if (STI.hasE2() && isUInt<12>(std::abs(Val) - 1)) { + BuildMI(MBB, MBBI, DL, TII->get(Val < 0 ? CSKY::SUBI32 : CSKY::ADDI32), + DestReg) + .addReg(SrcReg) + .addImm(std::abs(Val)) + .setMIFlag(Flag); + } else if (!STI.hasE2() && isShiftedUInt<7, 2>(std::abs(Val))) { + BuildMI(MBB, MBBI, DL, + TII->get(Val < 0 ? CSKY::SUBI16SPSP : CSKY::ADDI16SPSP), CSKY::R14) + .addReg(CSKY::R14, RegState::Kill) + .addImm(std::abs(Val)) + .setMIFlag(Flag); + } else { + + unsigned Op = 0; + + if (STI.hasE2()) { + Op = Val < 0 ? CSKY::SUBU32 : CSKY::ADDU32; + } else { + assert(SrcReg == DestReg); + Op = Val < 0 ? CSKY::SUBU16XZ : CSKY::ADDU16XZ; + } + + Register ScratchReg = TII->movImm(MBB, MBBI, DL, std::abs(Val), Flag); + + BuildMI(MBB, MBBI, DL, TII->get(Op), DestReg) + .addReg(SrcReg) + .addReg(ScratchReg, RegState::Kill) + .setMIFlag(Flag); + } +} + +StackOffset +CSKYFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, + Register &FrameReg) const { + const CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>(); + const MachineFrameInfo &MFI = MF.getFrameInfo(); + const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo(); + const auto &CSI = MFI.getCalleeSavedInfo(); + + int MinCSFI = 0; + int MaxCSFI = -1; + + int Offset = MFI.getObjectOffset(FI) + MFI.getOffsetAdjustment(); + + if (CSI.size()) { + MinCSFI = CSI[0].getFrameIdx(); + MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); + } + + if (FI >= MinCSFI && FI <= MaxCSFI) { + FrameReg = CSKY::R14; + Offset += CFI->getVarArgsSaveSize() + CFI->getCalleeSaveAreaSize(); + } else if (RI->hasStackRealignment(MF)) { + assert(hasFP(MF)); + if (!MFI.isFixedObjectIndex(FI)) { + FrameReg = hasBP(MF) ? getBPReg(STI) : CSKY::R14; + Offset += MFI.getStackSize(); + } else { + FrameReg = getFPReg(STI); + Offset += CFI->getVarArgsSaveSize() + CFI->getCalleeSaveAreaSize(); + } + } else { + if (MFI.isFixedObjectIndex(FI) && hasFP(MF)) { + FrameReg = getFPReg(STI); + Offset += CFI->getVarArgsSaveSize() + CFI->getCalleeSaveAreaSize(); + } else { + FrameReg = hasBP(MF) ? getBPReg(STI) : CSKY::R14; + Offset += MFI.getStackSize(); + } + } + + return StackOffset::getFixed(Offset); } |