//===-- CSKYFrameLowering.cpp - CSKY Frame Information ------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains the CSKY implementation of TargetFrameLowering class. // //===----------------------------------------------------------------------===// #include "CSKYFrameLowering.h" #include "CSKYMachineFunctionInfo.h" #include "CSKYSubtarget.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/RegisterScavenging.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/MC/MCDwarf.h" using namespace llvm; #define DEBUG_TYPE "csky-frame-lowering" // Returns the register used to hold the frame pointer. static Register getFPReg(const CSKYSubtarget &STI) { return CSKY::R8; } // To avoid the BP value clobbered by a function call, we need to choose a // callee saved register to save the value. static Register getBPReg(const CSKYSubtarget &STI) { return CSKY::R7; } bool CSKYFrameLowering::hasFP(const MachineFunction &MF) const { const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); const MachineFrameInfo &MFI = MF.getFrameInfo(); return MF.getTarget().Options.DisableFramePointerElim(MF) || RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() || MFI.isFrameAddressTaken(); } bool CSKYFrameLowering::hasBP(const MachineFunction &MF) const { const MachineFrameInfo &MFI = MF.getFrameInfo(); 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 { CSKYMachineFunctionInfo *CFI = MF.getInfo(); 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(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(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(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 { CSKYMachineFunctionInfo *CFI = MF.getInfo(); 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 EstimateFunctionSizeInBytes(const MachineFunction &MF, const CSKYInstrInfo &TII) { unsigned FnSize = 0; for (auto &MBB : MF) { for (auto &MI : MBB) FnSize += TII.getInstSizeInBytes(MI); } FnSize += MF.getConstantPool()->getConstants().size() * 4; return FnSize; } 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(); const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); const CSKYInstrInfo *TII = STI.getInstrInfo(); 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]); } } } 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)); } unsigned FnSize = EstimateFunctionSizeInBytes(MF, *TII); // Force R15 to be spilled if the function size is > 65534. This enables // use of BSR to implement far jump. if (FnSize >= ((1 << (16 - 1)) * 2)) SavedRegs.set(CSKY::R15); CFI->setLRIsSpilled(SavedRegs.test(CSKY::R15)); } // 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 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 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(); 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); }