| //===- XtensaFrameLowering.cpp - Xtensa 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 Xtensa implementation of TargetFrameLowering class. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "XtensaFrameLowering.h" |
| #include "XtensaInstrInfo.h" |
| #include "XtensaMachineFunctionInfo.h" |
| #include "XtensaSubtarget.h" |
| #include "llvm/CodeGen/MachineFrameInfo.h" |
| #include "llvm/CodeGen/MachineInstrBuilder.h" |
| #include "llvm/CodeGen/MachineModuleInfo.h" |
| #include "llvm/CodeGen/MachineRegisterInfo.h" |
| #include "llvm/CodeGen/RegisterScavenging.h" |
| #include "llvm/IR/Function.h" |
| |
| using namespace llvm; |
| |
| // Minimum frame = reg save area (4 words) plus static chain (1 word) |
| // and the total number of words must be a multiple of 128 bits. |
| // Width of a word, in units (bytes). |
| #define UNITS_PER_WORD 4 |
| #define MIN_FRAME_SIZE (8 * UNITS_PER_WORD) |
| |
| XtensaFrameLowering::XtensaFrameLowering(const XtensaSubtarget &STI) |
| : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(4), 0, |
| Align(4)), |
| STI(STI), TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) {} |
| |
| bool XtensaFrameLowering::hasFPImpl(const MachineFunction &MF) const { |
| const MachineFrameInfo &MFI = MF.getFrameInfo(); |
| return MF.getTarget().Options.DisableFramePointerElim(MF) || |
| MFI.hasVarSizedObjects(); |
| } |
| |
| void XtensaFrameLowering::emitPrologue(MachineFunction &MF, |
| MachineBasicBlock &MBB) const { |
| assert(&MBB == &MF.front() && "Shrink-wrapping not yet implemented"); |
| MachineFrameInfo &MFI = MF.getFrameInfo(); |
| MachineBasicBlock::iterator MBBI = MBB.begin(); |
| DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); |
| MCRegister SP = Xtensa::SP; |
| MCRegister FP = TRI->getFrameRegister(MF); |
| const MCRegisterInfo *MRI = MF.getContext().getRegisterInfo(); |
| XtensaMachineFunctionInfo *XtensaFI = MF.getInfo<XtensaMachineFunctionInfo>(); |
| |
| // First, compute final stack size. |
| uint64_t StackSize = MFI.getStackSize(); |
| uint64_t PrevStackSize = StackSize; |
| |
| // Round up StackSize to 16*N |
| StackSize += (16 - StackSize) & 0xf; |
| |
| if (STI.isWindowedABI()) { |
| StackSize += 32; |
| uint64_t MaxAlignment = MFI.getMaxAlign().value(); |
| if (MaxAlignment > 32) |
| StackSize += MaxAlignment; |
| |
| if (StackSize <= 32760) { |
| BuildMI(MBB, MBBI, DL, TII.get(Xtensa::ENTRY)) |
| .addReg(SP) |
| .addImm(StackSize); |
| } else { |
| // Use a8 as a temporary since a0-a7 may be live. |
| MCRegister TmpReg = Xtensa::A8; |
| |
| BuildMI(MBB, MBBI, DL, TII.get(Xtensa::ENTRY)) |
| .addReg(SP) |
| .addImm(MIN_FRAME_SIZE); |
| TII.loadImmediate(MBB, MBBI, &TmpReg, StackSize - MIN_FRAME_SIZE); |
| BuildMI(MBB, MBBI, DL, TII.get(Xtensa::SUB), TmpReg) |
| .addReg(SP) |
| .addReg(TmpReg); |
| BuildMI(MBB, MBBI, DL, TII.get(Xtensa::MOVSP), SP).addReg(TmpReg); |
| } |
| |
| // Calculate how much is needed to have the correct alignment. |
| // Change offset to: alignment + difference. |
| // For example, in case of alignment of 128: |
| // diff_to_128_aligned_address = (128 - (SP & 127)) |
| // new_offset = SP + diff_to_128_aligned_address |
| // This is safe to do because we increased the stack size by MaxAlignment. |
| MCRegister Reg, RegMisAlign; |
| if (MaxAlignment > 32) { |
| TII.loadImmediate(MBB, MBBI, &RegMisAlign, MaxAlignment - 1); |
| TII.loadImmediate(MBB, MBBI, &Reg, MaxAlignment); |
| BuildMI(MBB, MBBI, DL, TII.get(Xtensa::AND)) |
| .addReg(RegMisAlign, RegState::Define) |
| .addReg(FP) |
| .addReg(RegMisAlign); |
| BuildMI(MBB, MBBI, DL, TII.get(Xtensa::SUB), RegMisAlign) |
| .addReg(Reg) |
| .addReg(RegMisAlign); |
| BuildMI(MBB, MBBI, DL, TII.get(Xtensa::ADD), SP) |
| .addReg(SP) |
| .addReg(RegMisAlign, RegState::Kill); |
| } |
| |
| // Store FP register in A8, because FP may be used to pass function |
| // arguments |
| if (XtensaFI->isSaveFrameRegister()) { |
| BuildMI(MBB, MBBI, DL, TII.get(Xtensa::OR), Xtensa::A8) |
| .addReg(FP) |
| .addReg(FP); |
| } |
| |
| // if framepointer enabled, set it to point to the stack pointer. |
| if (hasFP(MF)) { |
| // Insert instruction "move $fp, $sp" at this location. |
| BuildMI(MBB, MBBI, DL, TII.get(Xtensa::OR), FP) |
| .addReg(SP) |
| .addReg(SP) |
| .setMIFlag(MachineInstr::FrameSetup); |
| |
| MCCFIInstruction Inst = MCCFIInstruction::cfiDefCfa( |
| nullptr, MRI->getDwarfRegNum(FP, true), StackSize); |
| unsigned CFIIndex = MF.addFrameInst(Inst); |
| BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION)) |
| .addCFIIndex(CFIIndex); |
| } else { |
| // emit ".cfi_def_cfa_offset StackSize" |
| unsigned CFIIndex = MF.addFrameInst( |
| MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize)); |
| BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION)) |
| .addCFIIndex(CFIIndex); |
| } |
| } else { |
| // No need to allocate space on the stack. |
| if (StackSize == 0 && !MFI.adjustsStack()) |
| return; |
| |
| // Adjust stack. |
| TII.adjustStackPtr(SP, -StackSize, MBB, MBBI); |
| |
| // emit ".cfi_def_cfa_offset StackSize" |
| unsigned CFIIndex = |
| MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize)); |
| BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION)) |
| .addCFIIndex(CFIIndex); |
| |
| const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); |
| |
| if (!CSI.empty()) { |
| // Find the instruction past the last instruction that saves a |
| // callee-saved register to the stack. The callee-saved store |
| // instructions are placed at the begin of basic block, so |
| // iterate over instruction sequence and check that |
| // save instructions are placed correctly. |
| for (unsigned i = 0, e = CSI.size(); i < e; ++i) { |
| #ifndef NDEBUG |
| const CalleeSavedInfo &Info = CSI[i]; |
| int FI = Info.getFrameIdx(); |
| int StoreFI = 0; |
| |
| // Checking that the instruction is exactly as expected |
| bool IsStoreInst = false; |
| if (MBBI->getOpcode() == TargetOpcode::COPY && Info.isSpilledToReg()) { |
| Register DstReg = MBBI->getOperand(0).getReg(); |
| Register Reg = MBBI->getOperand(1).getReg(); |
| IsStoreInst = Info.getDstReg() == DstReg.asMCReg() && |
| Info.getReg() == Reg.asMCReg(); |
| } else { |
| Register Reg = TII.isStoreToStackSlot(*MBBI, StoreFI); |
| IsStoreInst = Reg.asMCReg() == Info.getReg() && StoreFI == FI; |
| } |
| assert(IsStoreInst && |
| "Unexpected callee-saved register store instruction"); |
| #endif |
| ++MBBI; |
| } |
| |
| // Iterate over list of callee-saved registers and emit .cfi_offset |
| // directives. |
| for (const auto &I : CSI) { |
| int64_t Offset = MFI.getObjectOffset(I.getFrameIdx()); |
| MCRegister Reg = I.getReg(); |
| |
| unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( |
| nullptr, MRI->getDwarfRegNum(Reg, 1), Offset)); |
| BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION)) |
| .addCFIIndex(CFIIndex); |
| } |
| } |
| |
| // if framepointer enabled, set it to point to the stack pointer. |
| if (hasFP(MF)) { |
| // Insert instruction "move $fp, $sp" at this location. |
| BuildMI(MBB, MBBI, DL, TII.get(Xtensa::OR), FP) |
| .addReg(SP) |
| .addReg(SP) |
| .setMIFlag(MachineInstr::FrameSetup); |
| |
| // emit ".cfi_def_cfa_register $fp" |
| unsigned CFIIndex = |
| MF.addFrameInst(MCCFIInstruction::createDefCfaRegister( |
| nullptr, MRI->getDwarfRegNum(FP, true))); |
| BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION)) |
| .addCFIIndex(CFIIndex); |
| } |
| } |
| |
| if (StackSize != PrevStackSize) { |
| MFI.setStackSize(StackSize); |
| |
| for (int i = MFI.getObjectIndexBegin(); i < MFI.getObjectIndexEnd(); i++) { |
| if (!MFI.isDeadObjectIndex(i)) { |
| int64_t SPOffset = MFI.getObjectOffset(i); |
| |
| if (SPOffset < 0) |
| MFI.setObjectOffset(i, SPOffset - StackSize + PrevStackSize); |
| } |
| } |
| } |
| } |
| |
| void XtensaFrameLowering::emitEpilogue(MachineFunction &MF, |
| MachineBasicBlock &MBB) const { |
| MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); |
| MachineFrameInfo &MFI = MF.getFrameInfo(); |
| DebugLoc DL = MBBI->getDebugLoc(); |
| MCRegister SP = Xtensa::SP; |
| MCRegister FP = TRI->getFrameRegister(MF); |
| |
| // if framepointer enabled, restore the stack pointer. |
| if (hasFP(MF)) { |
| // We should place restore stack pointer instruction just before |
| // sequence of instructions which restores callee-saved registers. |
| // This sequence is placed at the end of the basic block, |
| // so we should find first instruction of the sequence. |
| MachineBasicBlock::iterator I = MBBI; |
| |
| const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); |
| |
| // Find the first instruction at the end that restores a callee-saved |
| // register. |
| for (unsigned i = 0, e = CSI.size(); i < e; ++i) { |
| --I; |
| #ifndef NDEBUG |
| const CalleeSavedInfo &Info = CSI[i]; |
| int FI = Info.getFrameIdx(); |
| int LoadFI = 0; |
| |
| // Checking that the instruction is exactly as expected |
| bool IsRestoreInst = false; |
| if (I->getOpcode() == TargetOpcode::COPY && Info.isSpilledToReg()) { |
| Register Reg = I->getOperand(0).getReg(); |
| Register DstReg = I->getOperand(1).getReg(); |
| IsRestoreInst = Info.getDstReg() == DstReg.asMCReg() && |
| Info.getReg() == Reg.asMCReg(); |
| } else { |
| Register Reg = TII.isLoadFromStackSlot(*I, LoadFI); |
| IsRestoreInst = Info.getReg() == Reg.asMCReg() && LoadFI == FI; |
| } |
| assert(IsRestoreInst && |
| "Unexpected callee-saved register restore instruction"); |
| #endif |
| } |
| if (STI.isWindowedABI()) { |
| // In most architectures, we need to explicitly restore the stack pointer |
| // before returning. |
| // |
| // For Xtensa Windowed Register option, it is not needed to explicitly |
| // restore the stack pointer. Reason being is that on function return, |
| // the window of the caller (including the old stack pointer) gets |
| // restored anyways. |
| } else { |
| BuildMI(MBB, I, DL, TII.get(Xtensa::OR), SP).addReg(FP).addReg(FP); |
| } |
| } |
| |
| if (STI.isWindowedABI()) |
| return; |
| |
| // Get the number of bytes from FrameInfo |
| uint64_t StackSize = MFI.getStackSize(); |
| |
| if (!StackSize) |
| return; |
| |
| // Adjust stack. |
| TII.adjustStackPtr(SP, StackSize, MBB, MBBI); |
| } |
| |
| bool XtensaFrameLowering::spillCalleeSavedRegisters( |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, |
| ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { |
| MachineFunction *MF = MBB.getParent(); |
| MachineBasicBlock &EntryBlock = *(MF->begin()); |
| |
| if (STI.isWindowedABI()) |
| return true; |
| |
| for (unsigned i = 0, e = CSI.size(); i != e; ++i) { |
| // Add the callee-saved register as live-in. Do not add if the register is |
| // A0 and return address is taken, because it will be implemented in |
| // method XtensaTargetLowering::LowerRETURNADDR. |
| // It's killed at the spill, unless the register is RA and return address |
| // is taken. |
| MCRegister Reg = CSI[i].getReg(); |
| bool IsA0AndRetAddrIsTaken = |
| (Reg == Xtensa::A0) && MF->getFrameInfo().isReturnAddressTaken(); |
| if (!IsA0AndRetAddrIsTaken) |
| EntryBlock.addLiveIn(Reg); |
| |
| // Insert the spill to the stack frame. |
| bool IsKill = !IsA0AndRetAddrIsTaken; |
| const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); |
| TII.storeRegToStackSlot(EntryBlock, MI, Reg, IsKill, CSI[i].getFrameIdx(), |
| RC, TRI, Register()); |
| } |
| |
| return true; |
| } |
| |
| bool XtensaFrameLowering::restoreCalleeSavedRegisters( |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, |
| MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { |
| if (STI.isWindowedABI()) |
| return true; |
| return TargetFrameLowering::restoreCalleeSavedRegisters(MBB, MI, CSI, TRI); |
| } |
| |
| // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions |
| MachineBasicBlock::iterator XtensaFrameLowering::eliminateCallFramePseudoInstr( |
| MachineFunction &MF, MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator I) const { |
| if (!hasReservedCallFrame(MF)) { |
| int64_t Amount = I->getOperand(0).getImm(); |
| |
| if (I->getOpcode() == Xtensa::ADJCALLSTACKDOWN) |
| Amount = -Amount; |
| |
| TII.adjustStackPtr(Xtensa::SP, Amount, MBB, I); |
| } |
| |
| return MBB.erase(I); |
| } |
| |
| void XtensaFrameLowering::determineCalleeSaves(MachineFunction &MF, |
| BitVector &SavedRegs, |
| RegScavenger *RS) const { |
| MCRegister FP = TRI->getFrameRegister(MF); |
| |
| if (STI.isWindowedABI()) { |
| return; |
| } |
| |
| TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); |
| |
| // Mark $fp as used if function has dedicated frame pointer. |
| if (hasFP(MF)) |
| SavedRegs.set(FP); |
| } |
| |
| void XtensaFrameLowering::processFunctionBeforeFrameFinalized( |
| MachineFunction &MF, RegScavenger *RS) const { |
| // Set scavenging frame index if necessary. |
| MachineFrameInfo &MFI = MF.getFrameInfo(); |
| uint64_t MaxSPOffset = MFI.estimateStackSize(MF); |
| auto *XtensaFI = MF.getInfo<XtensaMachineFunctionInfo>(); |
| unsigned ScavSlotsNum = 0; |
| |
| if (!isInt<12>(MaxSPOffset)) |
| ScavSlotsNum = 1; |
| |
| // Far branches over 18-bit offset require a spill slot for scratch register. |
| bool IsLargeFunction = !isInt<18>(MF.estimateFunctionSizeInBytes()); |
| if (IsLargeFunction) |
| ScavSlotsNum = std::max(ScavSlotsNum, 1u); |
| |
| const TargetRegisterClass &RC = Xtensa::ARRegClass; |
| unsigned Size = TRI->getSpillSize(RC); |
| Align Alignment = TRI->getSpillAlign(RC); |
| for (unsigned I = 0; I < ScavSlotsNum; I++) { |
| int FI = MFI.CreateSpillStackObject(Size, Alignment); |
| RS->addScavengingFrameIndex(FI); |
| |
| if (IsLargeFunction && |
| XtensaFI->getBranchRelaxationScratchFrameIndex() == -1) |
| XtensaFI->setBranchRelaxationScratchFrameIndex(FI); |
| } |
| } |