1349cc55cSDimitry Andric //===-- CSKYFrameLowering.cpp - CSKY Frame Information ------------------===// 2349cc55cSDimitry Andric // 3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6349cc55cSDimitry Andric // 7349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 8349cc55cSDimitry Andric // 9349cc55cSDimitry Andric // This file contains the CSKY implementation of TargetFrameLowering class. 10349cc55cSDimitry Andric // 11349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 12349cc55cSDimitry Andric 13349cc55cSDimitry Andric #include "CSKYFrameLowering.h" 1404eeddc0SDimitry Andric #include "CSKYMachineFunctionInfo.h" 15349cc55cSDimitry Andric #include "CSKYSubtarget.h" 16*81ad6265SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h" 17349cc55cSDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 18349cc55cSDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 19349cc55cSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 20349cc55cSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 21349cc55cSDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h" 22349cc55cSDimitry Andric #include "llvm/IR/DiagnosticInfo.h" 23349cc55cSDimitry Andric #include "llvm/MC/MCDwarf.h" 24349cc55cSDimitry Andric 25349cc55cSDimitry Andric using namespace llvm; 26349cc55cSDimitry Andric 27349cc55cSDimitry Andric #define DEBUG_TYPE "csky-frame-lowering" 28349cc55cSDimitry Andric 29349cc55cSDimitry Andric // Returns the register used to hold the frame pointer. 30349cc55cSDimitry Andric static Register getFPReg(const CSKYSubtarget &STI) { return CSKY::R8; } 31349cc55cSDimitry Andric 32349cc55cSDimitry Andric // To avoid the BP value clobbered by a function call, we need to choose a 33349cc55cSDimitry Andric // callee saved register to save the value. 34349cc55cSDimitry Andric static Register getBPReg(const CSKYSubtarget &STI) { return CSKY::R7; } 35349cc55cSDimitry Andric 36349cc55cSDimitry Andric bool CSKYFrameLowering::hasFP(const MachineFunction &MF) const { 37349cc55cSDimitry Andric const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); 38349cc55cSDimitry Andric 39349cc55cSDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 40349cc55cSDimitry Andric return MF.getTarget().Options.DisableFramePointerElim(MF) || 41349cc55cSDimitry Andric RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() || 42349cc55cSDimitry Andric MFI.isFrameAddressTaken(); 43349cc55cSDimitry Andric } 44349cc55cSDimitry Andric 45349cc55cSDimitry Andric bool CSKYFrameLowering::hasBP(const MachineFunction &MF) const { 46349cc55cSDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 47349cc55cSDimitry Andric 48349cc55cSDimitry Andric return MFI.hasVarSizedObjects(); 49349cc55cSDimitry Andric } 50349cc55cSDimitry Andric 5104eeddc0SDimitry Andric // Determines the size of the frame and maximum call frame size. 5204eeddc0SDimitry Andric void CSKYFrameLowering::determineFrameLayout(MachineFunction &MF) const { 5304eeddc0SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 5404eeddc0SDimitry Andric const CSKYRegisterInfo *RI = STI.getRegisterInfo(); 5504eeddc0SDimitry Andric 5604eeddc0SDimitry Andric // Get the number of bytes to allocate from the FrameInfo. 5704eeddc0SDimitry Andric uint64_t FrameSize = MFI.getStackSize(); 5804eeddc0SDimitry Andric 5904eeddc0SDimitry Andric // Get the alignment. 6004eeddc0SDimitry Andric Align StackAlign = getStackAlign(); 6104eeddc0SDimitry Andric if (RI->hasStackRealignment(MF)) { 6204eeddc0SDimitry Andric Align MaxStackAlign = std::max(StackAlign, MFI.getMaxAlign()); 6304eeddc0SDimitry Andric FrameSize += (MaxStackAlign.value() - StackAlign.value()); 6404eeddc0SDimitry Andric StackAlign = MaxStackAlign; 6504eeddc0SDimitry Andric } 6604eeddc0SDimitry Andric 6704eeddc0SDimitry Andric // Set Max Call Frame Size 6804eeddc0SDimitry Andric uint64_t MaxCallSize = alignTo(MFI.getMaxCallFrameSize(), StackAlign); 6904eeddc0SDimitry Andric MFI.setMaxCallFrameSize(MaxCallSize); 7004eeddc0SDimitry Andric 7104eeddc0SDimitry Andric // Make sure the frame is aligned. 7204eeddc0SDimitry Andric FrameSize = alignTo(FrameSize, StackAlign); 7304eeddc0SDimitry Andric 7404eeddc0SDimitry Andric // Update frame info. 7504eeddc0SDimitry Andric MFI.setStackSize(FrameSize); 7604eeddc0SDimitry Andric } 7704eeddc0SDimitry Andric 78349cc55cSDimitry Andric void CSKYFrameLowering::emitPrologue(MachineFunction &MF, 79349cc55cSDimitry Andric MachineBasicBlock &MBB) const { 8004eeddc0SDimitry Andric CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>(); 8104eeddc0SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 8204eeddc0SDimitry Andric const CSKYRegisterInfo *RI = STI.getRegisterInfo(); 8304eeddc0SDimitry Andric const CSKYInstrInfo *TII = STI.getInstrInfo(); 8404eeddc0SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin(); 8504eeddc0SDimitry Andric const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); 8604eeddc0SDimitry Andric const MachineRegisterInfo &MRI = MF.getRegInfo(); 8704eeddc0SDimitry Andric 8804eeddc0SDimitry Andric Register FPReg = getFPReg(STI); 8904eeddc0SDimitry Andric Register SPReg = CSKY::R14; 9004eeddc0SDimitry Andric Register BPReg = getBPReg(STI); 9104eeddc0SDimitry Andric 9204eeddc0SDimitry Andric // Debug location must be unknown since the first debug location is used 9304eeddc0SDimitry Andric // to determine the end of the prologue. 9404eeddc0SDimitry Andric DebugLoc DL; 9504eeddc0SDimitry Andric 9604eeddc0SDimitry Andric if (MF.getFunction().hasFnAttribute("interrupt")) 9704eeddc0SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(CSKY::NIE)); 9804eeddc0SDimitry Andric 9904eeddc0SDimitry Andric // Determine the correct frame layout 10004eeddc0SDimitry Andric determineFrameLayout(MF); 10104eeddc0SDimitry Andric 10204eeddc0SDimitry Andric // FIXME (note copied from Lanai): This appears to be overallocating. Needs 10304eeddc0SDimitry Andric // investigation. Get the number of bytes to allocate from the FrameInfo. 10404eeddc0SDimitry Andric uint64_t StackSize = MFI.getStackSize(); 10504eeddc0SDimitry Andric 10604eeddc0SDimitry Andric // Early exit if there is no need to allocate on the stack 10704eeddc0SDimitry Andric if (StackSize == 0 && !MFI.adjustsStack()) 10804eeddc0SDimitry Andric return; 10904eeddc0SDimitry Andric 11004eeddc0SDimitry Andric const auto &CSI = MFI.getCalleeSavedInfo(); 11104eeddc0SDimitry Andric 11204eeddc0SDimitry Andric unsigned spillAreaSize = CFI->getCalleeSaveAreaSize(); 11304eeddc0SDimitry Andric 11404eeddc0SDimitry Andric uint64_t ActualSize = spillAreaSize + CFI->getVarArgsSaveSize(); 11504eeddc0SDimitry Andric 11604eeddc0SDimitry Andric // First part stack allocation. 11704eeddc0SDimitry Andric adjustReg(MBB, MBBI, DL, SPReg, SPReg, -(static_cast<int64_t>(ActualSize)), 11804eeddc0SDimitry Andric MachineInstr::NoFlags); 11904eeddc0SDimitry Andric 12004eeddc0SDimitry Andric // Emit ".cfi_def_cfa_offset FirstSPAdjustAmount" 12104eeddc0SDimitry Andric unsigned CFIIndex = 12204eeddc0SDimitry Andric MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, ActualSize)); 12304eeddc0SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 12404eeddc0SDimitry Andric .addCFIIndex(CFIIndex); 12504eeddc0SDimitry Andric 12604eeddc0SDimitry Andric // The frame pointer is callee-saved, and code has been generated for us to 12704eeddc0SDimitry Andric // save it to the stack. We need to skip over the storing of callee-saved 12804eeddc0SDimitry Andric // registers as the frame pointer must be modified after it has been saved 12904eeddc0SDimitry Andric // to the stack, not before. 13004eeddc0SDimitry Andric // FIXME: assumes exactly one instruction is used to save each callee-saved 13104eeddc0SDimitry Andric // register. 13204eeddc0SDimitry Andric std::advance(MBBI, CSI.size()); 13304eeddc0SDimitry Andric 13404eeddc0SDimitry Andric // Iterate over list of callee-saved registers and emit .cfi_offset 13504eeddc0SDimitry Andric // directives. 13604eeddc0SDimitry Andric for (const auto &Entry : CSI) { 13704eeddc0SDimitry Andric int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx()); 13804eeddc0SDimitry Andric Register Reg = Entry.getReg(); 13904eeddc0SDimitry Andric 14004eeddc0SDimitry Andric unsigned Num = TRI->getRegSizeInBits(Reg, MRI) / 32; 14104eeddc0SDimitry Andric for (unsigned i = 0; i < Num; i++) { 14204eeddc0SDimitry Andric unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( 14304eeddc0SDimitry Andric nullptr, RI->getDwarfRegNum(Reg, true) + i, Offset + i * 4)); 14404eeddc0SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 14504eeddc0SDimitry Andric .addCFIIndex(CFIIndex); 14604eeddc0SDimitry Andric } 14704eeddc0SDimitry Andric } 14804eeddc0SDimitry Andric 14904eeddc0SDimitry Andric // Generate new FP. 15004eeddc0SDimitry Andric if (hasFP(MF)) { 15104eeddc0SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::COPY), FPReg) 15204eeddc0SDimitry Andric .addReg(SPReg) 15304eeddc0SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 15404eeddc0SDimitry Andric 15504eeddc0SDimitry Andric // Emit ".cfi_def_cfa_register $fp" 15604eeddc0SDimitry Andric unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfaRegister( 15704eeddc0SDimitry Andric nullptr, RI->getDwarfRegNum(FPReg, true))); 15804eeddc0SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 15904eeddc0SDimitry Andric .addCFIIndex(CFIIndex); 16004eeddc0SDimitry Andric 16104eeddc0SDimitry Andric // Second part stack allocation. 16204eeddc0SDimitry Andric adjustReg(MBB, MBBI, DL, SPReg, SPReg, 16304eeddc0SDimitry Andric -(static_cast<int64_t>(StackSize - ActualSize)), 16404eeddc0SDimitry Andric MachineInstr::NoFlags); 16504eeddc0SDimitry Andric 16604eeddc0SDimitry Andric // Realign Stack 16704eeddc0SDimitry Andric const CSKYRegisterInfo *RI = STI.getRegisterInfo(); 16804eeddc0SDimitry Andric if (RI->hasStackRealignment(MF)) { 16904eeddc0SDimitry Andric Align MaxAlignment = MFI.getMaxAlign(); 17004eeddc0SDimitry Andric 17104eeddc0SDimitry Andric const CSKYInstrInfo *TII = STI.getInstrInfo(); 17204eeddc0SDimitry Andric if (STI.hasE2() && isUInt<12>(~(-(int)MaxAlignment.value()))) { 17304eeddc0SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(CSKY::ANDNI32), SPReg) 17404eeddc0SDimitry Andric .addReg(SPReg) 17504eeddc0SDimitry Andric .addImm(~(-(int)MaxAlignment.value())); 17604eeddc0SDimitry Andric } else { 17704eeddc0SDimitry Andric unsigned ShiftAmount = Log2(MaxAlignment); 17804eeddc0SDimitry Andric 17904eeddc0SDimitry Andric if (STI.hasE2()) { 18004eeddc0SDimitry Andric Register VR = 18104eeddc0SDimitry Andric MF.getRegInfo().createVirtualRegister(&CSKY::GPRRegClass); 18204eeddc0SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(CSKY::LSRI32), VR) 18304eeddc0SDimitry Andric .addReg(SPReg) 18404eeddc0SDimitry Andric .addImm(ShiftAmount); 18504eeddc0SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(CSKY::LSLI32), SPReg) 18604eeddc0SDimitry Andric .addReg(VR) 18704eeddc0SDimitry Andric .addImm(ShiftAmount); 18804eeddc0SDimitry Andric } else { 18904eeddc0SDimitry Andric Register VR = 19004eeddc0SDimitry Andric MF.getRegInfo().createVirtualRegister(&CSKY::mGPRRegClass); 19104eeddc0SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(CSKY::MOV16), VR).addReg(SPReg); 19204eeddc0SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(CSKY::LSRI16), VR) 19304eeddc0SDimitry Andric .addReg(VR) 19404eeddc0SDimitry Andric .addImm(ShiftAmount); 19504eeddc0SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(CSKY::LSLI16), VR) 19604eeddc0SDimitry Andric .addReg(VR) 19704eeddc0SDimitry Andric .addImm(ShiftAmount); 19804eeddc0SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(CSKY::MOV16), SPReg).addReg(VR); 19904eeddc0SDimitry Andric } 20004eeddc0SDimitry Andric } 20104eeddc0SDimitry Andric } 20204eeddc0SDimitry Andric 20304eeddc0SDimitry Andric // FP will be used to restore the frame in the epilogue, so we need 20404eeddc0SDimitry Andric // another base register BP to record SP after re-alignment. SP will 20504eeddc0SDimitry Andric // track the current stack after allocating variable sized objects. 20604eeddc0SDimitry Andric if (hasBP(MF)) { 20704eeddc0SDimitry Andric // move BP, SP 20804eeddc0SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::COPY), BPReg).addReg(SPReg); 20904eeddc0SDimitry Andric } 21004eeddc0SDimitry Andric 21104eeddc0SDimitry Andric } else { 21204eeddc0SDimitry Andric adjustReg(MBB, MBBI, DL, SPReg, SPReg, 21304eeddc0SDimitry Andric -(static_cast<int64_t>(StackSize - ActualSize)), 21404eeddc0SDimitry Andric MachineInstr::NoFlags); 21504eeddc0SDimitry Andric // Emit ".cfi_def_cfa_offset StackSize" 21604eeddc0SDimitry Andric unsigned CFIIndex = MF.addFrameInst( 21704eeddc0SDimitry Andric MCCFIInstruction::cfiDefCfaOffset(nullptr, MFI.getStackSize())); 21804eeddc0SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 21904eeddc0SDimitry Andric .addCFIIndex(CFIIndex); 22004eeddc0SDimitry Andric } 221349cc55cSDimitry Andric } 222349cc55cSDimitry Andric 223349cc55cSDimitry Andric void CSKYFrameLowering::emitEpilogue(MachineFunction &MF, 224349cc55cSDimitry Andric MachineBasicBlock &MBB) const { 22504eeddc0SDimitry Andric CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>(); 22604eeddc0SDimitry Andric 22704eeddc0SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 22804eeddc0SDimitry Andric Register FPReg = getFPReg(STI); 22904eeddc0SDimitry Andric Register SPReg = CSKY::R14; 23004eeddc0SDimitry Andric 23104eeddc0SDimitry Andric // Get the insert location for the epilogue. If there were no terminators in 23204eeddc0SDimitry Andric // the block, get the last instruction. 23304eeddc0SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.end(); 23404eeddc0SDimitry Andric DebugLoc DL; 23504eeddc0SDimitry Andric if (!MBB.empty()) { 23604eeddc0SDimitry Andric MBBI = MBB.getFirstTerminator(); 23704eeddc0SDimitry Andric if (MBBI == MBB.end()) 23804eeddc0SDimitry Andric MBBI = MBB.getLastNonDebugInstr(); 23904eeddc0SDimitry Andric DL = MBBI->getDebugLoc(); 24004eeddc0SDimitry Andric 24104eeddc0SDimitry Andric // If this is not a terminator, the actual insert location should be after 24204eeddc0SDimitry Andric // the last instruction. 24304eeddc0SDimitry Andric if (!MBBI->isTerminator()) 24404eeddc0SDimitry Andric MBBI = std::next(MBBI); 24504eeddc0SDimitry Andric } 24604eeddc0SDimitry Andric 24704eeddc0SDimitry Andric const auto &CSI = MFI.getCalleeSavedInfo(); 24804eeddc0SDimitry Andric uint64_t StackSize = MFI.getStackSize(); 24904eeddc0SDimitry Andric 25004eeddc0SDimitry Andric uint64_t ActualSize = 25104eeddc0SDimitry Andric CFI->getCalleeSaveAreaSize() + CFI->getVarArgsSaveSize(); 25204eeddc0SDimitry Andric 25304eeddc0SDimitry Andric // Skip to before the restores of callee-saved registers 25404eeddc0SDimitry Andric // FIXME: assumes exactly one instruction is used to restore each 25504eeddc0SDimitry Andric // callee-saved register. 25604eeddc0SDimitry Andric auto LastFrameDestroy = MBBI; 25704eeddc0SDimitry Andric if (!CSI.empty()) 25804eeddc0SDimitry Andric LastFrameDestroy = std::prev(MBBI, CSI.size()); 25904eeddc0SDimitry Andric 26004eeddc0SDimitry Andric if (hasFP(MF)) { 26104eeddc0SDimitry Andric const CSKYInstrInfo *TII = STI.getInstrInfo(); 26204eeddc0SDimitry Andric BuildMI(MBB, LastFrameDestroy, DL, TII->get(TargetOpcode::COPY), SPReg) 26304eeddc0SDimitry Andric .addReg(FPReg) 26404eeddc0SDimitry Andric .setMIFlag(MachineInstr::NoFlags); 26504eeddc0SDimitry Andric } else { 26604eeddc0SDimitry Andric adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, (StackSize - ActualSize), 26704eeddc0SDimitry Andric MachineInstr::FrameDestroy); 26804eeddc0SDimitry Andric } 26904eeddc0SDimitry Andric 27004eeddc0SDimitry Andric adjustReg(MBB, MBBI, DL, SPReg, SPReg, ActualSize, 27104eeddc0SDimitry Andric MachineInstr::FrameDestroy); 27204eeddc0SDimitry Andric } 27304eeddc0SDimitry Andric 274*81ad6265SDimitry Andric static unsigned EstimateFunctionSizeInBytes(const MachineFunction &MF, 275*81ad6265SDimitry Andric const CSKYInstrInfo &TII) { 276*81ad6265SDimitry Andric unsigned FnSize = 0; 277*81ad6265SDimitry Andric for (auto &MBB : MF) { 278*81ad6265SDimitry Andric for (auto &MI : MBB) 279*81ad6265SDimitry Andric FnSize += TII.getInstSizeInBytes(MI); 280*81ad6265SDimitry Andric } 281*81ad6265SDimitry Andric FnSize += MF.getConstantPool()->getConstants().size() * 4; 282*81ad6265SDimitry Andric return FnSize; 283*81ad6265SDimitry Andric } 284*81ad6265SDimitry Andric 28504eeddc0SDimitry Andric static unsigned estimateRSStackSizeLimit(MachineFunction &MF, 28604eeddc0SDimitry Andric const CSKYSubtarget &STI) { 28704eeddc0SDimitry Andric unsigned Limit = (1 << 12) - 1; 28804eeddc0SDimitry Andric 28904eeddc0SDimitry Andric for (auto &MBB : MF) { 29004eeddc0SDimitry Andric for (auto &MI : MBB) { 29104eeddc0SDimitry Andric if (MI.isDebugInstr()) 29204eeddc0SDimitry Andric continue; 29304eeddc0SDimitry Andric 29404eeddc0SDimitry Andric for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { 29504eeddc0SDimitry Andric if (!MI.getOperand(i).isFI()) 29604eeddc0SDimitry Andric continue; 29704eeddc0SDimitry Andric 29804eeddc0SDimitry Andric if (MI.getOpcode() == CSKY::SPILL_CARRY || 29904eeddc0SDimitry Andric MI.getOpcode() == CSKY::RESTORE_CARRY || 30004eeddc0SDimitry Andric MI.getOpcode() == CSKY::STORE_PAIR || 30104eeddc0SDimitry Andric MI.getOpcode() == CSKY::LOAD_PAIR) { 30204eeddc0SDimitry Andric Limit = std::min(Limit, ((1U << 12) - 1) * 4); 30304eeddc0SDimitry Andric break; 30404eeddc0SDimitry Andric } 30504eeddc0SDimitry Andric 30604eeddc0SDimitry Andric if (MI.getOpcode() == CSKY::ADDI32) { 30704eeddc0SDimitry Andric Limit = std::min(Limit, (1U << 12)); 30804eeddc0SDimitry Andric break; 30904eeddc0SDimitry Andric } 31004eeddc0SDimitry Andric 31104eeddc0SDimitry Andric if (MI.getOpcode() == CSKY::ADDI16XZ) { 31204eeddc0SDimitry Andric Limit = std::min(Limit, (1U << 3)); 31304eeddc0SDimitry Andric break; 31404eeddc0SDimitry Andric } 31504eeddc0SDimitry Andric 31604eeddc0SDimitry Andric // ADDI16 will not require an extra register, 31704eeddc0SDimitry Andric // it can reuse the destination. 31804eeddc0SDimitry Andric if (MI.getOpcode() == CSKY::ADDI16) 31904eeddc0SDimitry Andric break; 32004eeddc0SDimitry Andric 32104eeddc0SDimitry Andric // Otherwise check the addressing mode. 32204eeddc0SDimitry Andric switch (MI.getDesc().TSFlags & CSKYII::AddrModeMask) { 32304eeddc0SDimitry Andric default: 32404eeddc0SDimitry Andric LLVM_DEBUG(MI.dump()); 32504eeddc0SDimitry Andric llvm_unreachable( 32604eeddc0SDimitry Andric "Unhandled addressing mode in stack size limit calculation"); 32704eeddc0SDimitry Andric case CSKYII::AddrMode32B: 32804eeddc0SDimitry Andric Limit = std::min(Limit, (1U << 12) - 1); 32904eeddc0SDimitry Andric break; 33004eeddc0SDimitry Andric case CSKYII::AddrMode32H: 33104eeddc0SDimitry Andric Limit = std::min(Limit, ((1U << 12) - 1) * 2); 33204eeddc0SDimitry Andric break; 33304eeddc0SDimitry Andric case CSKYII::AddrMode32WD: 33404eeddc0SDimitry Andric Limit = std::min(Limit, ((1U << 12) - 1) * 4); 33504eeddc0SDimitry Andric break; 33604eeddc0SDimitry Andric case CSKYII::AddrMode16B: 33704eeddc0SDimitry Andric Limit = std::min(Limit, (1U << 5) - 1); 33804eeddc0SDimitry Andric break; 33904eeddc0SDimitry Andric case CSKYII::AddrMode16H: 34004eeddc0SDimitry Andric Limit = std::min(Limit, ((1U << 5) - 1) * 2); 34104eeddc0SDimitry Andric break; 34204eeddc0SDimitry Andric case CSKYII::AddrMode16W: 34304eeddc0SDimitry Andric Limit = std::min(Limit, ((1U << 5) - 1) * 4); 34404eeddc0SDimitry Andric break; 34504eeddc0SDimitry Andric case CSKYII::AddrMode32SDF: 34604eeddc0SDimitry Andric Limit = std::min(Limit, ((1U << 8) - 1) * 4); 34704eeddc0SDimitry Andric break; 34804eeddc0SDimitry Andric } 34904eeddc0SDimitry Andric break; // At most one FI per instruction 35004eeddc0SDimitry Andric } 35104eeddc0SDimitry Andric } 35204eeddc0SDimitry Andric } 35304eeddc0SDimitry Andric 35404eeddc0SDimitry Andric return Limit; 35504eeddc0SDimitry Andric } 35604eeddc0SDimitry Andric 35704eeddc0SDimitry Andric void CSKYFrameLowering::determineCalleeSaves(MachineFunction &MF, 35804eeddc0SDimitry Andric BitVector &SavedRegs, 35904eeddc0SDimitry Andric RegScavenger *RS) const { 36004eeddc0SDimitry Andric TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); 36104eeddc0SDimitry Andric 36204eeddc0SDimitry Andric CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>(); 36304eeddc0SDimitry Andric const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); 364*81ad6265SDimitry Andric const CSKYInstrInfo *TII = STI.getInstrInfo(); 36504eeddc0SDimitry Andric const MachineRegisterInfo &MRI = MF.getRegInfo(); 36604eeddc0SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 36704eeddc0SDimitry Andric 36804eeddc0SDimitry Andric if (hasFP(MF)) 36904eeddc0SDimitry Andric SavedRegs.set(CSKY::R8); 37004eeddc0SDimitry Andric 37104eeddc0SDimitry Andric // Mark BP as used if function has dedicated base pointer. 37204eeddc0SDimitry Andric if (hasBP(MF)) 37304eeddc0SDimitry Andric SavedRegs.set(CSKY::R7); 37404eeddc0SDimitry Andric 37504eeddc0SDimitry Andric // If interrupt is enabled and there are calls in the handler, 37604eeddc0SDimitry Andric // unconditionally save all Caller-saved registers and 37704eeddc0SDimitry Andric // all FP registers, regardless whether they are used. 37804eeddc0SDimitry Andric if (MF.getFunction().hasFnAttribute("interrupt") && MFI.hasCalls()) { 37904eeddc0SDimitry Andric 38004eeddc0SDimitry Andric static const MCPhysReg CSRegs[] = {CSKY::R0, CSKY::R1, CSKY::R2, CSKY::R3, 38104eeddc0SDimitry Andric CSKY::R12, CSKY::R13, 0}; 38204eeddc0SDimitry Andric 38304eeddc0SDimitry Andric for (unsigned i = 0; CSRegs[i]; ++i) 38404eeddc0SDimitry Andric SavedRegs.set(CSRegs[i]); 38504eeddc0SDimitry Andric 38604eeddc0SDimitry Andric if (STI.hasHighRegisters()) { 38704eeddc0SDimitry Andric 38804eeddc0SDimitry Andric static const MCPhysReg CSHRegs[] = {CSKY::R18, CSKY::R19, CSKY::R20, 38904eeddc0SDimitry Andric CSKY::R21, CSKY::R22, CSKY::R23, 39004eeddc0SDimitry Andric CSKY::R24, CSKY::R25, 0}; 39104eeddc0SDimitry Andric 39204eeddc0SDimitry Andric for (unsigned i = 0; CSHRegs[i]; ++i) 39304eeddc0SDimitry Andric SavedRegs.set(CSHRegs[i]); 39404eeddc0SDimitry Andric } 39504eeddc0SDimitry Andric 39604eeddc0SDimitry Andric static const MCPhysReg CSF32Regs[] = { 39704eeddc0SDimitry Andric CSKY::F8_32, CSKY::F9_32, CSKY::F10_32, 39804eeddc0SDimitry Andric CSKY::F11_32, CSKY::F12_32, CSKY::F13_32, 39904eeddc0SDimitry Andric CSKY::F14_32, CSKY::F15_32, 0}; 40004eeddc0SDimitry Andric static const MCPhysReg CSF64Regs[] = { 40104eeddc0SDimitry Andric CSKY::F8_64, CSKY::F9_64, CSKY::F10_64, 40204eeddc0SDimitry Andric CSKY::F11_64, CSKY::F12_64, CSKY::F13_64, 40304eeddc0SDimitry Andric CSKY::F14_64, CSKY::F15_64, 0}; 40404eeddc0SDimitry Andric 40504eeddc0SDimitry Andric const MCPhysReg *FRegs = NULL; 40604eeddc0SDimitry Andric if (STI.hasFPUv2DoubleFloat() || STI.hasFPUv3DoubleFloat()) 40704eeddc0SDimitry Andric FRegs = CSF64Regs; 40804eeddc0SDimitry Andric else if (STI.hasFPUv2SingleFloat() || STI.hasFPUv3SingleFloat()) 40904eeddc0SDimitry Andric FRegs = CSF32Regs; 41004eeddc0SDimitry Andric 41104eeddc0SDimitry Andric if (FRegs != NULL) { 41204eeddc0SDimitry Andric const MCPhysReg *Regs = MF.getRegInfo().getCalleeSavedRegs(); 41304eeddc0SDimitry Andric 41404eeddc0SDimitry Andric for (unsigned i = 0; Regs[i]; ++i) 41504eeddc0SDimitry Andric if (CSKY::FPR32RegClass.contains(Regs[i]) || 41604eeddc0SDimitry Andric CSKY::FPR64RegClass.contains(Regs[i])) { 41704eeddc0SDimitry Andric unsigned x = 0; 41804eeddc0SDimitry Andric for (; FRegs[x]; ++x) 41904eeddc0SDimitry Andric if (FRegs[x] == Regs[i]) 42004eeddc0SDimitry Andric break; 42104eeddc0SDimitry Andric if (FRegs[x] == 0) 42204eeddc0SDimitry Andric SavedRegs.set(Regs[i]); 42304eeddc0SDimitry Andric } 42404eeddc0SDimitry Andric } 42504eeddc0SDimitry Andric } 42604eeddc0SDimitry Andric 42704eeddc0SDimitry Andric unsigned CSStackSize = 0; 42804eeddc0SDimitry Andric for (unsigned Reg : SavedRegs.set_bits()) { 42904eeddc0SDimitry Andric auto RegSize = TRI->getRegSizeInBits(Reg, MRI) / 8; 43004eeddc0SDimitry Andric CSStackSize += RegSize; 43104eeddc0SDimitry Andric } 43204eeddc0SDimitry Andric 43304eeddc0SDimitry Andric CFI->setCalleeSaveAreaSize(CSStackSize); 43404eeddc0SDimitry Andric 43504eeddc0SDimitry Andric uint64_t Limit = estimateRSStackSizeLimit(MF, STI); 43604eeddc0SDimitry Andric 43704eeddc0SDimitry Andric bool BigFrame = (MFI.estimateStackSize(MF) + CSStackSize >= Limit); 43804eeddc0SDimitry Andric 43904eeddc0SDimitry Andric if (BigFrame || CFI->isCRSpilled() || !STI.hasE2()) { 44004eeddc0SDimitry Andric const TargetRegisterClass *RC = &CSKY::GPRRegClass; 44104eeddc0SDimitry Andric unsigned size = TRI->getSpillSize(*RC); 44204eeddc0SDimitry Andric Align align = TRI->getSpillAlign(*RC); 44304eeddc0SDimitry Andric 44404eeddc0SDimitry Andric RS->addScavengingFrameIndex(MFI.CreateStackObject(size, align, false)); 44504eeddc0SDimitry Andric } 446*81ad6265SDimitry Andric 447*81ad6265SDimitry Andric unsigned FnSize = EstimateFunctionSizeInBytes(MF, *TII); 448*81ad6265SDimitry Andric // Force R15 to be spilled if the function size is > 65534. This enables 449*81ad6265SDimitry Andric // use of BSR to implement far jump. 450*81ad6265SDimitry Andric if (FnSize >= ((1 << (16 - 1)) * 2)) 451*81ad6265SDimitry Andric SavedRegs.set(CSKY::R15); 452*81ad6265SDimitry Andric 453*81ad6265SDimitry Andric CFI->setLRIsSpilled(SavedRegs.test(CSKY::R15)); 45404eeddc0SDimitry Andric } 45504eeddc0SDimitry Andric 45604eeddc0SDimitry Andric // Not preserve stack space within prologue for outgoing variables when the 45704eeddc0SDimitry Andric // function contains variable size objects and let eliminateCallFramePseudoInstr 45804eeddc0SDimitry Andric // preserve stack space for it. 45904eeddc0SDimitry Andric bool CSKYFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { 46004eeddc0SDimitry Andric return !MF.getFrameInfo().hasVarSizedObjects(); 46104eeddc0SDimitry Andric } 46204eeddc0SDimitry Andric 46304eeddc0SDimitry Andric bool CSKYFrameLowering::spillCalleeSavedRegisters( 46404eeddc0SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, 46504eeddc0SDimitry Andric ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 46604eeddc0SDimitry Andric if (CSI.empty()) 46704eeddc0SDimitry Andric return true; 46804eeddc0SDimitry Andric 46904eeddc0SDimitry Andric MachineFunction *MF = MBB.getParent(); 47004eeddc0SDimitry Andric const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); 47104eeddc0SDimitry Andric DebugLoc DL; 47204eeddc0SDimitry Andric if (MI != MBB.end() && !MI->isDebugInstr()) 47304eeddc0SDimitry Andric DL = MI->getDebugLoc(); 47404eeddc0SDimitry Andric 47504eeddc0SDimitry Andric for (auto &CS : CSI) { 47604eeddc0SDimitry Andric // Insert the spill to the stack frame. 47704eeddc0SDimitry Andric Register Reg = CS.getReg(); 47804eeddc0SDimitry Andric const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); 47904eeddc0SDimitry Andric TII.storeRegToStackSlot(MBB, MI, Reg, true, CS.getFrameIdx(), RC, TRI); 48004eeddc0SDimitry Andric } 48104eeddc0SDimitry Andric 48204eeddc0SDimitry Andric return true; 48304eeddc0SDimitry Andric } 48404eeddc0SDimitry Andric 48504eeddc0SDimitry Andric bool CSKYFrameLowering::restoreCalleeSavedRegisters( 48604eeddc0SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, 48704eeddc0SDimitry Andric MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 48804eeddc0SDimitry Andric if (CSI.empty()) 48904eeddc0SDimitry Andric return true; 49004eeddc0SDimitry Andric 49104eeddc0SDimitry Andric MachineFunction *MF = MBB.getParent(); 49204eeddc0SDimitry Andric const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); 49304eeddc0SDimitry Andric DebugLoc DL; 49404eeddc0SDimitry Andric if (MI != MBB.end() && !MI->isDebugInstr()) 49504eeddc0SDimitry Andric DL = MI->getDebugLoc(); 49604eeddc0SDimitry Andric 49704eeddc0SDimitry Andric for (auto &CS : reverse(CSI)) { 49804eeddc0SDimitry Andric Register Reg = CS.getReg(); 49904eeddc0SDimitry Andric const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); 50004eeddc0SDimitry Andric TII.loadRegFromStackSlot(MBB, MI, Reg, CS.getFrameIdx(), RC, TRI); 50104eeddc0SDimitry Andric assert(MI != MBB.begin() && "loadRegFromStackSlot didn't insert any code!"); 50204eeddc0SDimitry Andric } 50304eeddc0SDimitry Andric 50404eeddc0SDimitry Andric return true; 50504eeddc0SDimitry Andric } 50604eeddc0SDimitry Andric 50704eeddc0SDimitry Andric // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions. 50804eeddc0SDimitry Andric MachineBasicBlock::iterator CSKYFrameLowering::eliminateCallFramePseudoInstr( 50904eeddc0SDimitry Andric MachineFunction &MF, MachineBasicBlock &MBB, 51004eeddc0SDimitry Andric MachineBasicBlock::iterator MI) const { 51104eeddc0SDimitry Andric Register SPReg = CSKY::R14; 51204eeddc0SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 51304eeddc0SDimitry Andric 51404eeddc0SDimitry Andric if (!hasReservedCallFrame(MF)) { 51504eeddc0SDimitry Andric // If space has not been reserved for a call frame, ADJCALLSTACKDOWN and 51604eeddc0SDimitry Andric // ADJCALLSTACKUP must be converted to instructions manipulating the stack 51704eeddc0SDimitry Andric // pointer. This is necessary when there is a variable length stack 51804eeddc0SDimitry Andric // allocation (e.g. alloca), which means it's not possible to allocate 51904eeddc0SDimitry Andric // space for outgoing arguments from within the function prologue. 52004eeddc0SDimitry Andric int64_t Amount = MI->getOperand(0).getImm(); 52104eeddc0SDimitry Andric 52204eeddc0SDimitry Andric if (Amount != 0) { 52304eeddc0SDimitry Andric // Ensure the stack remains aligned after adjustment. 52404eeddc0SDimitry Andric Amount = alignSPAdjust(Amount); 52504eeddc0SDimitry Andric 52604eeddc0SDimitry Andric if (MI->getOpcode() == CSKY::ADJCALLSTACKDOWN) 52704eeddc0SDimitry Andric Amount = -Amount; 52804eeddc0SDimitry Andric 52904eeddc0SDimitry Andric adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags); 53004eeddc0SDimitry Andric } 53104eeddc0SDimitry Andric } 53204eeddc0SDimitry Andric 53304eeddc0SDimitry Andric return MBB.erase(MI); 53404eeddc0SDimitry Andric } 53504eeddc0SDimitry Andric 53604eeddc0SDimitry Andric void CSKYFrameLowering::adjustReg(MachineBasicBlock &MBB, 53704eeddc0SDimitry Andric MachineBasicBlock::iterator MBBI, 53804eeddc0SDimitry Andric const DebugLoc &DL, Register DestReg, 53904eeddc0SDimitry Andric Register SrcReg, int64_t Val, 54004eeddc0SDimitry Andric MachineInstr::MIFlag Flag) const { 54104eeddc0SDimitry Andric const CSKYInstrInfo *TII = STI.getInstrInfo(); 54204eeddc0SDimitry Andric 54304eeddc0SDimitry Andric if (DestReg == SrcReg && Val == 0) 54404eeddc0SDimitry Andric return; 54504eeddc0SDimitry Andric 54604eeddc0SDimitry Andric // TODO: Add 16-bit instruction support with immediate num 54704eeddc0SDimitry Andric if (STI.hasE2() && isUInt<12>(std::abs(Val) - 1)) { 54804eeddc0SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(Val < 0 ? CSKY::SUBI32 : CSKY::ADDI32), 54904eeddc0SDimitry Andric DestReg) 55004eeddc0SDimitry Andric .addReg(SrcReg) 55104eeddc0SDimitry Andric .addImm(std::abs(Val)) 55204eeddc0SDimitry Andric .setMIFlag(Flag); 55304eeddc0SDimitry Andric } else if (!STI.hasE2() && isShiftedUInt<7, 2>(std::abs(Val))) { 55404eeddc0SDimitry Andric BuildMI(MBB, MBBI, DL, 55504eeddc0SDimitry Andric TII->get(Val < 0 ? CSKY::SUBI16SPSP : CSKY::ADDI16SPSP), CSKY::R14) 55604eeddc0SDimitry Andric .addReg(CSKY::R14, RegState::Kill) 55704eeddc0SDimitry Andric .addImm(std::abs(Val)) 55804eeddc0SDimitry Andric .setMIFlag(Flag); 55904eeddc0SDimitry Andric } else { 56004eeddc0SDimitry Andric 56104eeddc0SDimitry Andric unsigned Op = 0; 56204eeddc0SDimitry Andric 56304eeddc0SDimitry Andric if (STI.hasE2()) { 56404eeddc0SDimitry Andric Op = Val < 0 ? CSKY::SUBU32 : CSKY::ADDU32; 56504eeddc0SDimitry Andric } else { 56604eeddc0SDimitry Andric assert(SrcReg == DestReg); 56704eeddc0SDimitry Andric Op = Val < 0 ? CSKY::SUBU16XZ : CSKY::ADDU16XZ; 56804eeddc0SDimitry Andric } 56904eeddc0SDimitry Andric 57004eeddc0SDimitry Andric Register ScratchReg = TII->movImm(MBB, MBBI, DL, std::abs(Val), Flag); 57104eeddc0SDimitry Andric 57204eeddc0SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(Op), DestReg) 57304eeddc0SDimitry Andric .addReg(SrcReg) 57404eeddc0SDimitry Andric .addReg(ScratchReg, RegState::Kill) 57504eeddc0SDimitry Andric .setMIFlag(Flag); 57604eeddc0SDimitry Andric } 57704eeddc0SDimitry Andric } 57804eeddc0SDimitry Andric 57904eeddc0SDimitry Andric StackOffset 58004eeddc0SDimitry Andric CSKYFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, 58104eeddc0SDimitry Andric Register &FrameReg) const { 58204eeddc0SDimitry Andric const CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>(); 58304eeddc0SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 58404eeddc0SDimitry Andric const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo(); 58504eeddc0SDimitry Andric const auto &CSI = MFI.getCalleeSavedInfo(); 58604eeddc0SDimitry Andric 58704eeddc0SDimitry Andric int MinCSFI = 0; 58804eeddc0SDimitry Andric int MaxCSFI = -1; 58904eeddc0SDimitry Andric 59004eeddc0SDimitry Andric int Offset = MFI.getObjectOffset(FI) + MFI.getOffsetAdjustment(); 59104eeddc0SDimitry Andric 59204eeddc0SDimitry Andric if (CSI.size()) { 59304eeddc0SDimitry Andric MinCSFI = CSI[0].getFrameIdx(); 59404eeddc0SDimitry Andric MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); 59504eeddc0SDimitry Andric } 59604eeddc0SDimitry Andric 59704eeddc0SDimitry Andric if (FI >= MinCSFI && FI <= MaxCSFI) { 59804eeddc0SDimitry Andric FrameReg = CSKY::R14; 59904eeddc0SDimitry Andric Offset += CFI->getVarArgsSaveSize() + CFI->getCalleeSaveAreaSize(); 60004eeddc0SDimitry Andric } else if (RI->hasStackRealignment(MF)) { 60104eeddc0SDimitry Andric assert(hasFP(MF)); 60204eeddc0SDimitry Andric if (!MFI.isFixedObjectIndex(FI)) { 60304eeddc0SDimitry Andric FrameReg = hasBP(MF) ? getBPReg(STI) : CSKY::R14; 60404eeddc0SDimitry Andric Offset += MFI.getStackSize(); 60504eeddc0SDimitry Andric } else { 60604eeddc0SDimitry Andric FrameReg = getFPReg(STI); 60704eeddc0SDimitry Andric Offset += CFI->getVarArgsSaveSize() + CFI->getCalleeSaveAreaSize(); 60804eeddc0SDimitry Andric } 60904eeddc0SDimitry Andric } else { 61004eeddc0SDimitry Andric if (MFI.isFixedObjectIndex(FI) && hasFP(MF)) { 61104eeddc0SDimitry Andric FrameReg = getFPReg(STI); 61204eeddc0SDimitry Andric Offset += CFI->getVarArgsSaveSize() + CFI->getCalleeSaveAreaSize(); 61304eeddc0SDimitry Andric } else { 61404eeddc0SDimitry Andric FrameReg = hasBP(MF) ? getBPReg(STI) : CSKY::R14; 61504eeddc0SDimitry Andric Offset += MFI.getStackSize(); 61604eeddc0SDimitry Andric } 61704eeddc0SDimitry Andric } 61804eeddc0SDimitry Andric 61904eeddc0SDimitry Andric return StackOffset::getFixed(Offset); 620349cc55cSDimitry Andric } 621