104eeddc0SDimitry Andric //===-- M68kFrameLowering.cpp - M68k Frame Information ----------*- C++ -*-===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric /// 9fe6060f1SDimitry Andric /// \file 10fe6060f1SDimitry Andric /// This file contains the M68k implementation of TargetFrameLowering class. 11fe6060f1SDimitry Andric /// 12fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 13fe6060f1SDimitry Andric 14fe6060f1SDimitry Andric #include "M68kFrameLowering.h" 15fe6060f1SDimitry Andric 16fe6060f1SDimitry Andric #include "M68kInstrBuilder.h" 17fe6060f1SDimitry Andric #include "M68kInstrInfo.h" 18fe6060f1SDimitry Andric #include "M68kMachineFunction.h" 19fe6060f1SDimitry Andric #include "M68kSubtarget.h" 20fe6060f1SDimitry Andric 21fe6060f1SDimitry Andric #include "llvm/ADT/SmallSet.h" 22fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 23fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 24fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 25fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 26fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 27fe6060f1SDimitry Andric #include "llvm/IR/DataLayout.h" 28fe6060f1SDimitry Andric #include "llvm/IR/Function.h" 29fe6060f1SDimitry Andric #include "llvm/Support/Alignment.h" 30fe6060f1SDimitry Andric #include "llvm/Support/CommandLine.h" 31fe6060f1SDimitry Andric #include "llvm/Target/TargetMachine.h" 32fe6060f1SDimitry Andric #include "llvm/Target/TargetOptions.h" 33fe6060f1SDimitry Andric 34fe6060f1SDimitry Andric using namespace llvm; 35fe6060f1SDimitry Andric 36fe6060f1SDimitry Andric M68kFrameLowering::M68kFrameLowering(const M68kSubtarget &STI, Align Alignment) 37fe6060f1SDimitry Andric : TargetFrameLowering(StackGrowsDown, Alignment, -4), STI(STI), 38fe6060f1SDimitry Andric TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) { 39fe6060f1SDimitry Andric SlotSize = STI.getSlotSize(); 40fe6060f1SDimitry Andric StackPtr = TRI->getStackRegister(); 41fe6060f1SDimitry Andric } 42fe6060f1SDimitry Andric 43fe6060f1SDimitry Andric bool M68kFrameLowering::hasFP(const MachineFunction &MF) const { 44fe6060f1SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 45fe6060f1SDimitry Andric const TargetRegisterInfo *TRI = STI.getRegisterInfo(); 46fe6060f1SDimitry Andric 47fe6060f1SDimitry Andric return MF.getTarget().Options.DisableFramePointerElim(MF) || 48fe6060f1SDimitry Andric MFI.hasVarSizedObjects() || MFI.isFrameAddressTaken() || 49fe6060f1SDimitry Andric TRI->hasStackRealignment(MF); 50fe6060f1SDimitry Andric } 51fe6060f1SDimitry Andric 52fe6060f1SDimitry Andric // FIXME Make sure no other factors prevent us from reserving call frame 53fe6060f1SDimitry Andric bool M68kFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { 54fe6060f1SDimitry Andric return !MF.getFrameInfo().hasVarSizedObjects() && 55fe6060f1SDimitry Andric !MF.getInfo<M68kMachineFunctionInfo>()->getHasPushSequences(); 56fe6060f1SDimitry Andric } 57fe6060f1SDimitry Andric 58fe6060f1SDimitry Andric bool M68kFrameLowering::canSimplifyCallFramePseudos( 59fe6060f1SDimitry Andric const MachineFunction &MF) const { 60fe6060f1SDimitry Andric return hasReservedCallFrame(MF) || 61fe6060f1SDimitry Andric (hasFP(MF) && !TRI->hasStackRealignment(MF)) || 62fe6060f1SDimitry Andric TRI->hasBasePointer(MF); 63fe6060f1SDimitry Andric } 64fe6060f1SDimitry Andric 65fe6060f1SDimitry Andric bool M68kFrameLowering::needsFrameIndexResolution( 66fe6060f1SDimitry Andric const MachineFunction &MF) const { 67fe6060f1SDimitry Andric return MF.getFrameInfo().hasStackObjects() || 68fe6060f1SDimitry Andric MF.getInfo<M68kMachineFunctionInfo>()->getHasPushSequences(); 69fe6060f1SDimitry Andric } 70fe6060f1SDimitry Andric 71fe6060f1SDimitry Andric // NOTE: this only has a subset of the full frame index logic. In 72fe6060f1SDimitry Andric // particular, the FI < 0 and AfterFPPop logic is handled in 73fe6060f1SDimitry Andric // M68kRegisterInfo::eliminateFrameIndex, but not here. Possibly 74fe6060f1SDimitry Andric // (probably?) it should be moved into here. 75fe6060f1SDimitry Andric StackOffset 76fe6060f1SDimitry Andric M68kFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, 77fe6060f1SDimitry Andric Register &FrameReg) const { 78fe6060f1SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 79fe6060f1SDimitry Andric 80fe6060f1SDimitry Andric // We can't calculate offset from frame pointer if the stack is realigned, 81fe6060f1SDimitry Andric // so enforce usage of stack/base pointer. The base pointer is used when we 82fe6060f1SDimitry Andric // have dynamic allocas in addition to dynamic realignment. 83fe6060f1SDimitry Andric if (TRI->hasBasePointer(MF)) 84fe6060f1SDimitry Andric FrameReg = TRI->getBaseRegister(); 85fe6060f1SDimitry Andric else if (TRI->hasStackRealignment(MF)) 86fe6060f1SDimitry Andric FrameReg = TRI->getStackRegister(); 87fe6060f1SDimitry Andric else 88fe6060f1SDimitry Andric FrameReg = TRI->getFrameRegister(MF); 89fe6060f1SDimitry Andric 90fe6060f1SDimitry Andric // Offset will hold the offset from the stack pointer at function entry to the 91fe6060f1SDimitry Andric // object. 92fe6060f1SDimitry Andric // We need to factor in additional offsets applied during the prologue to the 93fe6060f1SDimitry Andric // frame, base, and stack pointer depending on which is used. 94fe6060f1SDimitry Andric int Offset = MFI.getObjectOffset(FI) - getOffsetOfLocalArea(); 95fe6060f1SDimitry Andric const M68kMachineFunctionInfo *MMFI = MF.getInfo<M68kMachineFunctionInfo>(); 96fe6060f1SDimitry Andric uint64_t StackSize = MFI.getStackSize(); 97fe6060f1SDimitry Andric bool HasFP = hasFP(MF); 98fe6060f1SDimitry Andric 99fe6060f1SDimitry Andric // TODO: Support tail calls 100fe6060f1SDimitry Andric if (TRI->hasBasePointer(MF)) { 101fe6060f1SDimitry Andric assert(HasFP && "VLAs and dynamic stack realign, but no FP?!"); 102fe6060f1SDimitry Andric if (FI < 0) { 103fe6060f1SDimitry Andric // Skip the saved FP. 104fe6060f1SDimitry Andric return StackOffset::getFixed(Offset + SlotSize); 105fe6060f1SDimitry Andric } 106fe6060f1SDimitry Andric 107fe6060f1SDimitry Andric assert((-(Offset + StackSize)) % MFI.getObjectAlign(FI).value() == 0); 108fe6060f1SDimitry Andric return StackOffset::getFixed(Offset + StackSize); 109fe6060f1SDimitry Andric } 110fe6060f1SDimitry Andric if (TRI->hasStackRealignment(MF)) { 111fe6060f1SDimitry Andric if (FI < 0) { 112fe6060f1SDimitry Andric // Skip the saved FP. 113fe6060f1SDimitry Andric return StackOffset::getFixed(Offset + SlotSize); 114fe6060f1SDimitry Andric } 115fe6060f1SDimitry Andric 116fe6060f1SDimitry Andric assert((-(Offset + StackSize)) % MFI.getObjectAlign(FI).value() == 0); 117fe6060f1SDimitry Andric return StackOffset::getFixed(Offset + StackSize); 118fe6060f1SDimitry Andric } 119fe6060f1SDimitry Andric 120fe6060f1SDimitry Andric if (!HasFP) 121fe6060f1SDimitry Andric return StackOffset::getFixed(Offset + StackSize); 122fe6060f1SDimitry Andric 123fe6060f1SDimitry Andric // Skip the saved FP. 124fe6060f1SDimitry Andric Offset += SlotSize; 125fe6060f1SDimitry Andric 126fe6060f1SDimitry Andric // Skip the RETADDR move area 127fe6060f1SDimitry Andric int TailCallReturnAddrDelta = MMFI->getTCReturnAddrDelta(); 128fe6060f1SDimitry Andric if (TailCallReturnAddrDelta < 0) 129fe6060f1SDimitry Andric Offset -= TailCallReturnAddrDelta; 130fe6060f1SDimitry Andric 131fe6060f1SDimitry Andric return StackOffset::getFixed(Offset); 132fe6060f1SDimitry Andric } 133fe6060f1SDimitry Andric 134fe6060f1SDimitry Andric /// Return a caller-saved register that isn't live 135fe6060f1SDimitry Andric /// when it reaches the "return" instruction. We can then pop a stack object 136fe6060f1SDimitry Andric /// to this register without worry about clobbering it. 137fe6060f1SDimitry Andric static unsigned findDeadCallerSavedReg(MachineBasicBlock &MBB, 138fe6060f1SDimitry Andric MachineBasicBlock::iterator &MBBI, 139fe6060f1SDimitry Andric const M68kRegisterInfo *TRI) { 140fe6060f1SDimitry Andric const MachineFunction *MF = MBB.getParent(); 141fe6060f1SDimitry Andric if (MF->callsEHReturn()) 142fe6060f1SDimitry Andric return 0; 143fe6060f1SDimitry Andric 144fe6060f1SDimitry Andric const TargetRegisterClass &AvailableRegs = *TRI->getRegsForTailCall(*MF); 145fe6060f1SDimitry Andric 146fe6060f1SDimitry Andric if (MBBI == MBB.end()) 147fe6060f1SDimitry Andric return 0; 148fe6060f1SDimitry Andric 149fe6060f1SDimitry Andric switch (MBBI->getOpcode()) { 150fe6060f1SDimitry Andric default: 151fe6060f1SDimitry Andric return 0; 152fe6060f1SDimitry Andric case TargetOpcode::PATCHABLE_RET: 153fe6060f1SDimitry Andric case M68k::RET: { 154fe6060f1SDimitry Andric SmallSet<uint16_t, 8> Uses; 155fe6060f1SDimitry Andric 156fe6060f1SDimitry Andric for (unsigned i = 0, e = MBBI->getNumOperands(); i != e; ++i) { 157fe6060f1SDimitry Andric MachineOperand &MO = MBBI->getOperand(i); 158fe6060f1SDimitry Andric if (!MO.isReg() || MO.isDef()) 159fe6060f1SDimitry Andric continue; 16004eeddc0SDimitry Andric Register Reg = MO.getReg(); 161fe6060f1SDimitry Andric if (!Reg) 162fe6060f1SDimitry Andric continue; 163fe6060f1SDimitry Andric for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI) 164fe6060f1SDimitry Andric Uses.insert(*AI); 165fe6060f1SDimitry Andric } 166fe6060f1SDimitry Andric 167fe6060f1SDimitry Andric for (auto CS : AvailableRegs) 168fe6060f1SDimitry Andric if (!Uses.count(CS)) 169fe6060f1SDimitry Andric return CS; 170fe6060f1SDimitry Andric } 171fe6060f1SDimitry Andric } 172fe6060f1SDimitry Andric 173fe6060f1SDimitry Andric return 0; 174fe6060f1SDimitry Andric } 175fe6060f1SDimitry Andric 176fe6060f1SDimitry Andric static bool isRegLiveIn(MachineBasicBlock &MBB, unsigned Reg) { 177fe6060f1SDimitry Andric return llvm::any_of(MBB.liveins(), 178fe6060f1SDimitry Andric [Reg](MachineBasicBlock::RegisterMaskPair RegMask) { 179fe6060f1SDimitry Andric return RegMask.PhysReg == Reg; 180fe6060f1SDimitry Andric }); 181fe6060f1SDimitry Andric } 182fe6060f1SDimitry Andric 183fe6060f1SDimitry Andric uint64_t 184fe6060f1SDimitry Andric M68kFrameLowering::calculateMaxStackAlign(const MachineFunction &MF) const { 185fe6060f1SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 186fe6060f1SDimitry Andric uint64_t MaxAlign = MFI.getMaxAlign().value(); // Desired stack alignment. 187fe6060f1SDimitry Andric unsigned StackAlign = getStackAlignment(); // ABI alignment 188fe6060f1SDimitry Andric if (MF.getFunction().hasFnAttribute("stackrealign")) { 189fe6060f1SDimitry Andric if (MFI.hasCalls()) 190fe6060f1SDimitry Andric MaxAlign = (StackAlign > MaxAlign) ? StackAlign : MaxAlign; 191fe6060f1SDimitry Andric else if (MaxAlign < SlotSize) 192fe6060f1SDimitry Andric MaxAlign = SlotSize; 193fe6060f1SDimitry Andric } 194fe6060f1SDimitry Andric return MaxAlign; 195fe6060f1SDimitry Andric } 196fe6060f1SDimitry Andric 197fe6060f1SDimitry Andric void M68kFrameLowering::BuildStackAlignAND(MachineBasicBlock &MBB, 198fe6060f1SDimitry Andric MachineBasicBlock::iterator MBBI, 199fe6060f1SDimitry Andric const DebugLoc &DL, unsigned Reg, 200fe6060f1SDimitry Andric uint64_t MaxAlign) const { 201fe6060f1SDimitry Andric uint64_t Val = -MaxAlign; 202fe6060f1SDimitry Andric unsigned AndOp = M68k::AND32di; 203fe6060f1SDimitry Andric unsigned MovOp = M68k::MOV32rr; 204fe6060f1SDimitry Andric 205fe6060f1SDimitry Andric // This function is normally used with SP which is Address Register, but AND, 206fe6060f1SDimitry Andric // or any other logical instructions in M68k do not support ARs so we need 207fe6060f1SDimitry Andric // to use a temp Data Register to perform the op. 208fe6060f1SDimitry Andric unsigned Tmp = M68k::D0; 209fe6060f1SDimitry Andric 210fe6060f1SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MovOp), Tmp) 211fe6060f1SDimitry Andric .addReg(Reg) 212fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 213fe6060f1SDimitry Andric 214fe6060f1SDimitry Andric MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(AndOp), Tmp) 215fe6060f1SDimitry Andric .addReg(Tmp) 216fe6060f1SDimitry Andric .addImm(Val) 217fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 218fe6060f1SDimitry Andric 219fe6060f1SDimitry Andric // The CCR implicit def is dead. 220fe6060f1SDimitry Andric MI->getOperand(3).setIsDead(); 221fe6060f1SDimitry Andric 222fe6060f1SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(MovOp), Reg) 223fe6060f1SDimitry Andric .addReg(Tmp) 224fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 225fe6060f1SDimitry Andric } 226fe6060f1SDimitry Andric 227fe6060f1SDimitry Andric MachineBasicBlock::iterator M68kFrameLowering::eliminateCallFramePseudoInstr( 228fe6060f1SDimitry Andric MachineFunction &MF, MachineBasicBlock &MBB, 229fe6060f1SDimitry Andric MachineBasicBlock::iterator I) const { 230fe6060f1SDimitry Andric bool ReserveCallFrame = hasReservedCallFrame(MF); 231fe6060f1SDimitry Andric unsigned Opcode = I->getOpcode(); 232fe6060f1SDimitry Andric bool IsDestroy = Opcode == TII.getCallFrameDestroyOpcode(); 233fe6060f1SDimitry Andric DebugLoc DL = I->getDebugLoc(); 234fe6060f1SDimitry Andric uint64_t Amount = !ReserveCallFrame ? I->getOperand(0).getImm() : 0; 235fe6060f1SDimitry Andric uint64_t InternalAmt = (IsDestroy && Amount) ? I->getOperand(1).getImm() : 0; 236fe6060f1SDimitry Andric I = MBB.erase(I); 237fe6060f1SDimitry Andric 238fe6060f1SDimitry Andric if (!ReserveCallFrame) { 239fe6060f1SDimitry Andric // If the stack pointer can be changed after prologue, turn the 240fe6060f1SDimitry Andric // adjcallstackup instruction into a 'sub %SP, <amt>' and the 241fe6060f1SDimitry Andric // adjcallstackdown instruction into 'add %SP, <amt>' 242fe6060f1SDimitry Andric 243fe6060f1SDimitry Andric // We need to keep the stack aligned properly. To do this, we round the 244fe6060f1SDimitry Andric // amount of space needed for the outgoing arguments up to the next 245fe6060f1SDimitry Andric // alignment boundary. 246fe6060f1SDimitry Andric unsigned StackAlign = getStackAlignment(); 247fe6060f1SDimitry Andric Amount = alignTo(Amount, StackAlign); 248fe6060f1SDimitry Andric 249fe6060f1SDimitry Andric MachineModuleInfo &MMI = MF.getMMI(); 250fe6060f1SDimitry Andric const auto &Fn = MF.getFunction(); 251fe6060f1SDimitry Andric bool DwarfCFI = MMI.hasDebugInfo() || Fn.needsUnwindTableEntry(); 252fe6060f1SDimitry Andric 253fe6060f1SDimitry Andric // If we have any exception handlers in this function, and we adjust 254fe6060f1SDimitry Andric // the SP before calls, we may need to indicate this to the unwinder 255fe6060f1SDimitry Andric // using GNU_ARGS_SIZE. Note that this may be necessary even when 256fe6060f1SDimitry Andric // Amount == 0, because the preceding function may have set a non-0 257fe6060f1SDimitry Andric // GNU_ARGS_SIZE. 258fe6060f1SDimitry Andric // TODO: We don't need to reset this between subsequent functions, 259fe6060f1SDimitry Andric // if it didn't change. 260fe6060f1SDimitry Andric bool HasDwarfEHHandlers = !MF.getLandingPads().empty(); 261fe6060f1SDimitry Andric 262fe6060f1SDimitry Andric if (HasDwarfEHHandlers && !IsDestroy && 263fe6060f1SDimitry Andric MF.getInfo<M68kMachineFunctionInfo>()->getHasPushSequences()) { 264fe6060f1SDimitry Andric BuildCFI(MBB, I, DL, 265fe6060f1SDimitry Andric MCCFIInstruction::createGnuArgsSize(nullptr, Amount)); 266fe6060f1SDimitry Andric } 267fe6060f1SDimitry Andric 268fe6060f1SDimitry Andric if (Amount == 0) 269fe6060f1SDimitry Andric return I; 270fe6060f1SDimitry Andric 271fe6060f1SDimitry Andric // Factor out the amount that gets handled inside the sequence 272fe6060f1SDimitry Andric // (Pushes of argument for frame setup, callee pops for frame destroy) 273fe6060f1SDimitry Andric Amount -= InternalAmt; 274fe6060f1SDimitry Andric 275fe6060f1SDimitry Andric // TODO: This is needed only if we require precise CFA. 276fe6060f1SDimitry Andric // If this is a callee-pop calling convention, emit a CFA adjust for 277fe6060f1SDimitry Andric // the amount the callee popped. 278fe6060f1SDimitry Andric if (IsDestroy && InternalAmt && DwarfCFI && !hasFP(MF)) 279fe6060f1SDimitry Andric BuildCFI(MBB, I, DL, 280fe6060f1SDimitry Andric MCCFIInstruction::createAdjustCfaOffset(nullptr, -InternalAmt)); 281fe6060f1SDimitry Andric 282fe6060f1SDimitry Andric // Add Amount to SP to destroy a frame, or subtract to setup. 283fe6060f1SDimitry Andric int64_t StackAdjustment = IsDestroy ? Amount : -Amount; 284fe6060f1SDimitry Andric int64_t CfaAdjustment = -StackAdjustment; 285fe6060f1SDimitry Andric 286fe6060f1SDimitry Andric if (StackAdjustment) { 287fe6060f1SDimitry Andric // Merge with any previous or following adjustment instruction. Note: the 288fe6060f1SDimitry Andric // instructions merged with here do not have CFI, so their stack 289fe6060f1SDimitry Andric // adjustments do not feed into CfaAdjustment. 290fe6060f1SDimitry Andric StackAdjustment += mergeSPUpdates(MBB, I, true); 291fe6060f1SDimitry Andric StackAdjustment += mergeSPUpdates(MBB, I, false); 292fe6060f1SDimitry Andric 293fe6060f1SDimitry Andric if (StackAdjustment) { 294fe6060f1SDimitry Andric BuildStackAdjustment(MBB, I, DL, StackAdjustment, false); 295fe6060f1SDimitry Andric } 296fe6060f1SDimitry Andric } 297fe6060f1SDimitry Andric 298fe6060f1SDimitry Andric if (DwarfCFI && !hasFP(MF)) { 299fe6060f1SDimitry Andric // If we don't have FP, but need to generate unwind information, 300fe6060f1SDimitry Andric // we need to set the correct CFA offset after the stack adjustment. 301fe6060f1SDimitry Andric // How much we adjust the CFA offset depends on whether we're emitting 302fe6060f1SDimitry Andric // CFI only for EH purposes or for debugging. EH only requires the CFA 303fe6060f1SDimitry Andric // offset to be correct at each call site, while for debugging we want 304fe6060f1SDimitry Andric // it to be more precise. 305fe6060f1SDimitry Andric 306fe6060f1SDimitry Andric // TODO: When not using precise CFA, we also need to adjust for the 307fe6060f1SDimitry Andric // InternalAmt here. 308fe6060f1SDimitry Andric if (CfaAdjustment) { 309fe6060f1SDimitry Andric BuildCFI( 310fe6060f1SDimitry Andric MBB, I, DL, 311fe6060f1SDimitry Andric MCCFIInstruction::createAdjustCfaOffset(nullptr, CfaAdjustment)); 312fe6060f1SDimitry Andric } 313fe6060f1SDimitry Andric } 314fe6060f1SDimitry Andric 315fe6060f1SDimitry Andric return I; 316fe6060f1SDimitry Andric } 317fe6060f1SDimitry Andric 318fe6060f1SDimitry Andric if (IsDestroy && InternalAmt) { 319fe6060f1SDimitry Andric // If we are performing frame pointer elimination and if the callee pops 320fe6060f1SDimitry Andric // something off the stack pointer, add it back. We do this until we have 321fe6060f1SDimitry Andric // more advanced stack pointer tracking ability. 322fe6060f1SDimitry Andric // We are not tracking the stack pointer adjustment by the callee, so make 323fe6060f1SDimitry Andric // sure we restore the stack pointer immediately after the call, there may 324fe6060f1SDimitry Andric // be spill code inserted between the CALL and ADJCALLSTACKUP instructions. 325fe6060f1SDimitry Andric MachineBasicBlock::iterator CI = I; 326fe6060f1SDimitry Andric MachineBasicBlock::iterator B = MBB.begin(); 327fe6060f1SDimitry Andric while (CI != B && !std::prev(CI)->isCall()) 328fe6060f1SDimitry Andric --CI; 329fe6060f1SDimitry Andric BuildStackAdjustment(MBB, CI, DL, -InternalAmt, /*InEpilogue=*/false); 330fe6060f1SDimitry Andric } 331fe6060f1SDimitry Andric 332fe6060f1SDimitry Andric return I; 333fe6060f1SDimitry Andric } 334fe6060f1SDimitry Andric 335fe6060f1SDimitry Andric /// Emit a series of instructions to increment / decrement the stack pointer by 336fe6060f1SDimitry Andric /// a constant value. 337fe6060f1SDimitry Andric void M68kFrameLowering::emitSPUpdate(MachineBasicBlock &MBB, 338fe6060f1SDimitry Andric MachineBasicBlock::iterator &MBBI, 339fe6060f1SDimitry Andric int64_t NumBytes, bool InEpilogue) const { 340fe6060f1SDimitry Andric bool IsSub = NumBytes < 0; 341fe6060f1SDimitry Andric uint64_t Offset = IsSub ? -NumBytes : NumBytes; 342fe6060f1SDimitry Andric 343fe6060f1SDimitry Andric uint64_t Chunk = (1LL << 31) - 1; 344fe6060f1SDimitry Andric DebugLoc DL = MBB.findDebugLoc(MBBI); 345fe6060f1SDimitry Andric 346fe6060f1SDimitry Andric while (Offset) { 347fe6060f1SDimitry Andric if (Offset > Chunk) { 348fe6060f1SDimitry Andric // Rather than emit a long series of instructions for large offsets, 349fe6060f1SDimitry Andric // load the offset into a register and do one sub/add 350fe6060f1SDimitry Andric Register Reg; 351fe6060f1SDimitry Andric 352fe6060f1SDimitry Andric if (IsSub && !isRegLiveIn(MBB, M68k::D0)) 353fe6060f1SDimitry Andric Reg = M68k::D0; 354fe6060f1SDimitry Andric else 355fe6060f1SDimitry Andric Reg = findDeadCallerSavedReg(MBB, MBBI, TRI); 356fe6060f1SDimitry Andric 357fe6060f1SDimitry Andric if (Reg) { 358fe6060f1SDimitry Andric unsigned Opc = M68k::MOV32ri; 359fe6060f1SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(Opc), Reg).addImm(Offset); 360349cc55cSDimitry Andric Opc = IsSub ? M68k::SUB32ar : M68k::ADD32ar; 361fe6060f1SDimitry Andric MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr) 362fe6060f1SDimitry Andric .addReg(StackPtr) 363fe6060f1SDimitry Andric .addReg(Reg); 364fe6060f1SDimitry Andric // ??? still no CCR 365fe6060f1SDimitry Andric MI->getOperand(3).setIsDead(); // The CCR implicit def is dead. 366fe6060f1SDimitry Andric Offset = 0; 367fe6060f1SDimitry Andric continue; 368fe6060f1SDimitry Andric } 369fe6060f1SDimitry Andric } 370fe6060f1SDimitry Andric 371fe6060f1SDimitry Andric uint64_t ThisVal = std::min(Offset, Chunk); 372fe6060f1SDimitry Andric 373fe6060f1SDimitry Andric MachineInstrBuilder MI = BuildStackAdjustment( 374fe6060f1SDimitry Andric MBB, MBBI, DL, IsSub ? -ThisVal : ThisVal, InEpilogue); 375fe6060f1SDimitry Andric if (IsSub) 376fe6060f1SDimitry Andric MI.setMIFlag(MachineInstr::FrameSetup); 377fe6060f1SDimitry Andric else 378fe6060f1SDimitry Andric MI.setMIFlag(MachineInstr::FrameDestroy); 379fe6060f1SDimitry Andric 380fe6060f1SDimitry Andric Offset -= ThisVal; 381fe6060f1SDimitry Andric } 382fe6060f1SDimitry Andric } 383fe6060f1SDimitry Andric 384fe6060f1SDimitry Andric int M68kFrameLowering::mergeSPUpdates(MachineBasicBlock &MBB, 385fe6060f1SDimitry Andric MachineBasicBlock::iterator &MBBI, 386fe6060f1SDimitry Andric bool MergeWithPrevious) const { 387fe6060f1SDimitry Andric if ((MergeWithPrevious && MBBI == MBB.begin()) || 388fe6060f1SDimitry Andric (!MergeWithPrevious && MBBI == MBB.end())) 389fe6060f1SDimitry Andric return 0; 390fe6060f1SDimitry Andric 391fe6060f1SDimitry Andric MachineBasicBlock::iterator PI = MergeWithPrevious ? std::prev(MBBI) : MBBI; 392fe6060f1SDimitry Andric MachineBasicBlock::iterator NI = 393fe6060f1SDimitry Andric MergeWithPrevious ? nullptr : std::next(MBBI); 394fe6060f1SDimitry Andric unsigned Opc = PI->getOpcode(); 395fe6060f1SDimitry Andric int Offset = 0; 396fe6060f1SDimitry Andric 397fe6060f1SDimitry Andric if (!MergeWithPrevious && NI != MBB.end() && 398fe6060f1SDimitry Andric NI->getOpcode() == TargetOpcode::CFI_INSTRUCTION) { 399fe6060f1SDimitry Andric // Don't merge with the next instruction if it has CFI. 400fe6060f1SDimitry Andric return Offset; 401fe6060f1SDimitry Andric } 402fe6060f1SDimitry Andric 403349cc55cSDimitry Andric if (Opc == M68k::ADD32ai && PI->getOperand(0).getReg() == StackPtr) { 404fe6060f1SDimitry Andric assert(PI->getOperand(1).getReg() == StackPtr); 405fe6060f1SDimitry Andric Offset += PI->getOperand(2).getImm(); 406fe6060f1SDimitry Andric MBB.erase(PI); 407fe6060f1SDimitry Andric if (!MergeWithPrevious) 408fe6060f1SDimitry Andric MBBI = NI; 409349cc55cSDimitry Andric } else if (Opc == M68k::SUB32ai && PI->getOperand(0).getReg() == StackPtr) { 410fe6060f1SDimitry Andric assert(PI->getOperand(1).getReg() == StackPtr); 411fe6060f1SDimitry Andric Offset -= PI->getOperand(2).getImm(); 412fe6060f1SDimitry Andric MBB.erase(PI); 413fe6060f1SDimitry Andric if (!MergeWithPrevious) 414fe6060f1SDimitry Andric MBBI = NI; 415fe6060f1SDimitry Andric } 416fe6060f1SDimitry Andric 417fe6060f1SDimitry Andric return Offset; 418fe6060f1SDimitry Andric } 419fe6060f1SDimitry Andric 420fe6060f1SDimitry Andric MachineInstrBuilder M68kFrameLowering::BuildStackAdjustment( 421fe6060f1SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 422fe6060f1SDimitry Andric const DebugLoc &DL, int64_t Offset, bool InEpilogue) const { 423fe6060f1SDimitry Andric assert(Offset != 0 && "zero offset stack adjustment requested"); 424fe6060f1SDimitry Andric 425fe6060f1SDimitry Andric // TODO can `lea` be used to adjust stack? 426fe6060f1SDimitry Andric 427fe6060f1SDimitry Andric bool IsSub = Offset < 0; 428fe6060f1SDimitry Andric uint64_t AbsOffset = IsSub ? -Offset : Offset; 429349cc55cSDimitry Andric unsigned Opc = IsSub ? M68k::SUB32ai : M68k::ADD32ai; 430fe6060f1SDimitry Andric 431fe6060f1SDimitry Andric MachineInstrBuilder MI = BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr) 432fe6060f1SDimitry Andric .addReg(StackPtr) 433fe6060f1SDimitry Andric .addImm(AbsOffset); 434fe6060f1SDimitry Andric // FIXME Update CCR as well. For now we just 435fe6060f1SDimitry Andric // conservatively say CCR implicit def is dead 436fe6060f1SDimitry Andric MI->getOperand(3).setIsDead(); 437fe6060f1SDimitry Andric return MI; 438fe6060f1SDimitry Andric } 439fe6060f1SDimitry Andric 440fe6060f1SDimitry Andric void M68kFrameLowering::BuildCFI(MachineBasicBlock &MBB, 441fe6060f1SDimitry Andric MachineBasicBlock::iterator MBBI, 442fe6060f1SDimitry Andric const DebugLoc &DL, 443fe6060f1SDimitry Andric const MCCFIInstruction &CFIInst) const { 444fe6060f1SDimitry Andric MachineFunction &MF = *MBB.getParent(); 445fe6060f1SDimitry Andric unsigned CFIIndex = MF.addFrameInst(CFIInst); 446fe6060f1SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION)) 447fe6060f1SDimitry Andric .addCFIIndex(CFIIndex); 448fe6060f1SDimitry Andric } 449fe6060f1SDimitry Andric 450fe6060f1SDimitry Andric void M68kFrameLowering::emitPrologueCalleeSavedFrameMoves( 451fe6060f1SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 452fe6060f1SDimitry Andric const DebugLoc &DL) const { 453fe6060f1SDimitry Andric MachineFunction &MF = *MBB.getParent(); 454fe6060f1SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 455fe6060f1SDimitry Andric MachineModuleInfo &MMI = MF.getMMI(); 456fe6060f1SDimitry Andric const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); 457fe6060f1SDimitry Andric 458fe6060f1SDimitry Andric // Add callee saved registers to move list. 459fe6060f1SDimitry Andric const auto &CSI = MFI.getCalleeSavedInfo(); 460fe6060f1SDimitry Andric if (CSI.empty()) 461fe6060f1SDimitry Andric return; 462fe6060f1SDimitry Andric 463fe6060f1SDimitry Andric // Calculate offsets. 464fe6060f1SDimitry Andric for (const auto &I : CSI) { 465fe6060f1SDimitry Andric int64_t Offset = MFI.getObjectOffset(I.getFrameIdx()); 46604eeddc0SDimitry Andric Register Reg = I.getReg(); 467fe6060f1SDimitry Andric 468fe6060f1SDimitry Andric unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true); 469fe6060f1SDimitry Andric BuildCFI(MBB, MBBI, DL, 470fe6060f1SDimitry Andric MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset)); 471fe6060f1SDimitry Andric } 472fe6060f1SDimitry Andric } 473fe6060f1SDimitry Andric 474fe6060f1SDimitry Andric void M68kFrameLowering::emitPrologue(MachineFunction &MF, 475fe6060f1SDimitry Andric MachineBasicBlock &MBB) const { 476fe6060f1SDimitry Andric assert(&STI == &MF.getSubtarget<M68kSubtarget>() && 477fe6060f1SDimitry Andric "MF used frame lowering for wrong subtarget"); 478fe6060f1SDimitry Andric 479fe6060f1SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin(); 480fe6060f1SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 481fe6060f1SDimitry Andric const auto &Fn = MF.getFunction(); 482fe6060f1SDimitry Andric MachineModuleInfo &MMI = MF.getMMI(); 483fe6060f1SDimitry Andric M68kMachineFunctionInfo *MMFI = MF.getInfo<M68kMachineFunctionInfo>(); 484fe6060f1SDimitry Andric uint64_t MaxAlign = calculateMaxStackAlign(MF); // Desired stack alignment. 485fe6060f1SDimitry Andric uint64_t StackSize = MFI.getStackSize(); // Number of bytes to allocate. 486fe6060f1SDimitry Andric bool HasFP = hasFP(MF); 487fe6060f1SDimitry Andric bool NeedsDwarfCFI = MMI.hasDebugInfo() || Fn.needsUnwindTableEntry(); 48804eeddc0SDimitry Andric Register FramePtr = TRI->getFrameRegister(MF); 489fe6060f1SDimitry Andric const unsigned MachineFramePtr = FramePtr; 490fe6060f1SDimitry Andric unsigned BasePtr = TRI->getBaseRegister(); 491fe6060f1SDimitry Andric 492fe6060f1SDimitry Andric // Debug location must be unknown since the first debug location is used 493fe6060f1SDimitry Andric // to determine the end of the prologue. 494fe6060f1SDimitry Andric DebugLoc DL; 495fe6060f1SDimitry Andric 496fe6060f1SDimitry Andric // Add RETADDR move area to callee saved frame size. 497fe6060f1SDimitry Andric int TailCallReturnAddrDelta = MMFI->getTCReturnAddrDelta(); 498fe6060f1SDimitry Andric 499fe6060f1SDimitry Andric if (TailCallReturnAddrDelta < 0) { 500fe6060f1SDimitry Andric MMFI->setCalleeSavedFrameSize(MMFI->getCalleeSavedFrameSize() - 501fe6060f1SDimitry Andric TailCallReturnAddrDelta); 502fe6060f1SDimitry Andric } 503fe6060f1SDimitry Andric 504fe6060f1SDimitry Andric // Insert stack pointer adjustment for later moving of return addr. Only 505fe6060f1SDimitry Andric // applies to tail call optimized functions where the callee argument stack 506fe6060f1SDimitry Andric // size is bigger than the callers. 507fe6060f1SDimitry Andric if (TailCallReturnAddrDelta < 0) { 508fe6060f1SDimitry Andric BuildStackAdjustment(MBB, MBBI, DL, TailCallReturnAddrDelta, 509fe6060f1SDimitry Andric /*InEpilogue=*/false) 510fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 511fe6060f1SDimitry Andric } 512fe6060f1SDimitry Andric 513fe6060f1SDimitry Andric // Mapping for machine moves: 514fe6060f1SDimitry Andric // 515fe6060f1SDimitry Andric // DST: VirtualFP AND 516fe6060f1SDimitry Andric // SRC: VirtualFP => DW_CFA_def_cfa_offset 517fe6060f1SDimitry Andric // ELSE => DW_CFA_def_cfa 518fe6060f1SDimitry Andric // 519fe6060f1SDimitry Andric // SRC: VirtualFP AND 520fe6060f1SDimitry Andric // DST: Register => DW_CFA_def_cfa_register 521fe6060f1SDimitry Andric // 522fe6060f1SDimitry Andric // ELSE 523fe6060f1SDimitry Andric // OFFSET < 0 => DW_CFA_offset_extended_sf 524fe6060f1SDimitry Andric // REG < 64 => DW_CFA_offset + Reg 525fe6060f1SDimitry Andric // ELSE => DW_CFA_offset_extended 526fe6060f1SDimitry Andric 527fe6060f1SDimitry Andric uint64_t NumBytes = 0; 528fe6060f1SDimitry Andric int stackGrowth = -SlotSize; 529fe6060f1SDimitry Andric 530fe6060f1SDimitry Andric if (HasFP) { 531fe6060f1SDimitry Andric // Calculate required stack adjustment. 532fe6060f1SDimitry Andric uint64_t FrameSize = StackSize - SlotSize; 533fe6060f1SDimitry Andric // If required, include space for extra hidden slot for stashing base 534fe6060f1SDimitry Andric // pointer. 535fe6060f1SDimitry Andric if (MMFI->getRestoreBasePointer()) 536fe6060f1SDimitry Andric FrameSize += SlotSize; 537fe6060f1SDimitry Andric 538fe6060f1SDimitry Andric NumBytes = FrameSize - MMFI->getCalleeSavedFrameSize(); 539fe6060f1SDimitry Andric 540fe6060f1SDimitry Andric // Callee-saved registers are pushed on stack before the stack is realigned. 541fe6060f1SDimitry Andric if (TRI->hasStackRealignment(MF)) 542fe6060f1SDimitry Andric NumBytes = alignTo(NumBytes, MaxAlign); 543fe6060f1SDimitry Andric 544fe6060f1SDimitry Andric // Get the offset of the stack slot for the FP register, which is 545fe6060f1SDimitry Andric // guaranteed to be the last slot by processFunctionBeforeFrameFinalized. 546fe6060f1SDimitry Andric // Update the frame offset adjustment. 547fe6060f1SDimitry Andric MFI.setOffsetAdjustment(-NumBytes); 548fe6060f1SDimitry Andric 549*bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(M68k::LINK16)) 550*bdd1243dSDimitry Andric .addReg(M68k::WA6, RegState::Kill) 551*bdd1243dSDimitry Andric .addImm(-NumBytes) 552fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 553fe6060f1SDimitry Andric 554fe6060f1SDimitry Andric if (NeedsDwarfCFI) { 555fe6060f1SDimitry Andric // Mark the place where FP was saved. 556fe6060f1SDimitry Andric // Define the current CFA rule to use the provided offset. 557fe6060f1SDimitry Andric assert(StackSize); 558fe6060f1SDimitry Andric BuildCFI(MBB, MBBI, DL, 559fe6060f1SDimitry Andric MCCFIInstruction::cfiDefCfaOffset(nullptr, 2 * stackGrowth)); 560fe6060f1SDimitry Andric 561fe6060f1SDimitry Andric // Change the rule for the FramePtr to be an "offset" rule. 562fe6060f1SDimitry Andric int DwarfFramePtr = TRI->getDwarfRegNum(MachineFramePtr, true); 563fe6060f1SDimitry Andric assert(DwarfFramePtr > 0); 564fe6060f1SDimitry Andric BuildCFI(MBB, MBBI, DL, 565fe6060f1SDimitry Andric MCCFIInstruction::createOffset(nullptr, DwarfFramePtr, 566fe6060f1SDimitry Andric 2 * stackGrowth)); 567fe6060f1SDimitry Andric } 568fe6060f1SDimitry Andric 569fe6060f1SDimitry Andric if (NeedsDwarfCFI) { 570fe6060f1SDimitry Andric // Mark effective beginning of when frame pointer becomes valid. 571fe6060f1SDimitry Andric // Define the current CFA to use the FP register. 572fe6060f1SDimitry Andric unsigned DwarfFramePtr = TRI->getDwarfRegNum(MachineFramePtr, true); 573fe6060f1SDimitry Andric BuildCFI(MBB, MBBI, DL, 574fe6060f1SDimitry Andric MCCFIInstruction::createDefCfaRegister(nullptr, DwarfFramePtr)); 575fe6060f1SDimitry Andric } 576fe6060f1SDimitry Andric 577fe6060f1SDimitry Andric // Mark the FramePtr as live-in in every block. Don't do this again for 578fe6060f1SDimitry Andric // funclet prologues. 579fe6060f1SDimitry Andric for (MachineBasicBlock &EveryMBB : MF) 580fe6060f1SDimitry Andric EveryMBB.addLiveIn(MachineFramePtr); 581fe6060f1SDimitry Andric } else { 582fe6060f1SDimitry Andric NumBytes = StackSize - MMFI->getCalleeSavedFrameSize(); 583fe6060f1SDimitry Andric } 584fe6060f1SDimitry Andric 585fe6060f1SDimitry Andric // Skip the callee-saved push instructions. 586fe6060f1SDimitry Andric bool PushedRegs = false; 587fe6060f1SDimitry Andric int StackOffset = 2 * stackGrowth; 588fe6060f1SDimitry Andric 589fe6060f1SDimitry Andric while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup) && 590fe6060f1SDimitry Andric MBBI->getOpcode() == M68k::PUSH32r) { 591fe6060f1SDimitry Andric PushedRegs = true; 592fe6060f1SDimitry Andric ++MBBI; 593fe6060f1SDimitry Andric 594fe6060f1SDimitry Andric if (!HasFP && NeedsDwarfCFI) { 595fe6060f1SDimitry Andric // Mark callee-saved push instruction. 596fe6060f1SDimitry Andric // Define the current CFA rule to use the provided offset. 597fe6060f1SDimitry Andric assert(StackSize); 598fe6060f1SDimitry Andric BuildCFI(MBB, MBBI, DL, 599fe6060f1SDimitry Andric MCCFIInstruction::cfiDefCfaOffset(nullptr, StackOffset)); 600fe6060f1SDimitry Andric StackOffset += stackGrowth; 601fe6060f1SDimitry Andric } 602fe6060f1SDimitry Andric } 603fe6060f1SDimitry Andric 604fe6060f1SDimitry Andric // Realign stack after we pushed callee-saved registers (so that we'll be 605fe6060f1SDimitry Andric // able to calculate their offsets from the frame pointer). 606fe6060f1SDimitry Andric if (TRI->hasStackRealignment(MF)) { 607fe6060f1SDimitry Andric assert(HasFP && "There should be a frame pointer if stack is realigned."); 608fe6060f1SDimitry Andric BuildStackAlignAND(MBB, MBBI, DL, StackPtr, MaxAlign); 609fe6060f1SDimitry Andric } 610fe6060f1SDimitry Andric 611fe6060f1SDimitry Andric // If there is an SUB32ri of SP immediately before this instruction, merge 612fe6060f1SDimitry Andric // the two. This can be the case when tail call elimination is enabled and 613fe6060f1SDimitry Andric // the callee has more arguments then the caller. 614fe6060f1SDimitry Andric NumBytes -= mergeSPUpdates(MBB, MBBI, true); 615fe6060f1SDimitry Andric 616fe6060f1SDimitry Andric // Adjust stack pointer: ESP -= numbytes. 617*bdd1243dSDimitry Andric if (!HasFP) 618fe6060f1SDimitry Andric emitSPUpdate(MBB, MBBI, -(int64_t)NumBytes, /*InEpilogue=*/false); 619fe6060f1SDimitry Andric 620fe6060f1SDimitry Andric unsigned SPOrEstablisher = StackPtr; 621fe6060f1SDimitry Andric 622fe6060f1SDimitry Andric // If we need a base pointer, set it up here. It's whatever the value 623fe6060f1SDimitry Andric // of the stack pointer is at this point. Any variable size objects 624fe6060f1SDimitry Andric // will be allocated after this, so we can still use the base pointer 625fe6060f1SDimitry Andric // to reference locals. 626fe6060f1SDimitry Andric if (TRI->hasBasePointer(MF)) { 627fe6060f1SDimitry Andric // Update the base pointer with the current stack pointer. 628fe6060f1SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(M68k::MOV32aa), BasePtr) 629fe6060f1SDimitry Andric .addReg(SPOrEstablisher) 630fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 631fe6060f1SDimitry Andric if (MMFI->getRestoreBasePointer()) { 632fe6060f1SDimitry Andric // Stash value of base pointer. Saving SP instead of FP shortens 633fe6060f1SDimitry Andric // dependence chain. Used by SjLj EH. 634fe6060f1SDimitry Andric unsigned Opm = M68k::MOV32ja; 635fe6060f1SDimitry Andric M68k::addRegIndirectWithDisp(BuildMI(MBB, MBBI, DL, TII.get(Opm)), 636fe6060f1SDimitry Andric FramePtr, true, 637fe6060f1SDimitry Andric MMFI->getRestoreBasePointerOffset()) 638fe6060f1SDimitry Andric .addReg(SPOrEstablisher) 639fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 640fe6060f1SDimitry Andric } 641fe6060f1SDimitry Andric } 642fe6060f1SDimitry Andric 643fe6060f1SDimitry Andric if (((!HasFP && NumBytes) || PushedRegs) && NeedsDwarfCFI) { 644fe6060f1SDimitry Andric // Mark end of stack pointer adjustment. 645fe6060f1SDimitry Andric if (!HasFP && NumBytes) { 646fe6060f1SDimitry Andric // Define the current CFA rule to use the provided offset. 647fe6060f1SDimitry Andric assert(StackSize); 648fe6060f1SDimitry Andric BuildCFI( 649fe6060f1SDimitry Andric MBB, MBBI, DL, 650fe6060f1SDimitry Andric MCCFIInstruction::cfiDefCfaOffset(nullptr, -StackSize + stackGrowth)); 651fe6060f1SDimitry Andric } 652fe6060f1SDimitry Andric 653fe6060f1SDimitry Andric // Emit DWARF info specifying the offsets of the callee-saved registers. 654fe6060f1SDimitry Andric if (PushedRegs) 655fe6060f1SDimitry Andric emitPrologueCalleeSavedFrameMoves(MBB, MBBI, DL); 656fe6060f1SDimitry Andric } 657fe6060f1SDimitry Andric 658fe6060f1SDimitry Andric // TODO Interrupt handlers 659fe6060f1SDimitry Andric // M68k Interrupt handling function cannot assume anything about the 660fe6060f1SDimitry Andric // direction flag (DF in CCR register). Clear this flag by creating "cld" 661fe6060f1SDimitry Andric // instruction in each prologue of interrupt handler function. The "cld" 662fe6060f1SDimitry Andric // instruction should only in these cases: 663fe6060f1SDimitry Andric // 1. The interrupt handling function uses any of the "rep" instructions. 664fe6060f1SDimitry Andric // 2. Interrupt handling function calls another function. 665fe6060f1SDimitry Andric } 666fe6060f1SDimitry Andric 667fe6060f1SDimitry Andric static bool isTailCallOpcode(unsigned Opc) { 668fe6060f1SDimitry Andric return Opc == M68k::TCRETURNj || Opc == M68k::TCRETURNq; 669fe6060f1SDimitry Andric } 670fe6060f1SDimitry Andric 671fe6060f1SDimitry Andric void M68kFrameLowering::emitEpilogue(MachineFunction &MF, 672fe6060f1SDimitry Andric MachineBasicBlock &MBB) const { 673fe6060f1SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 674fe6060f1SDimitry Andric M68kMachineFunctionInfo *MMFI = MF.getInfo<M68kMachineFunctionInfo>(); 675fe6060f1SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(); 676*bdd1243dSDimitry Andric std::optional<unsigned> RetOpcode; 677fe6060f1SDimitry Andric if (MBBI != MBB.end()) 678fe6060f1SDimitry Andric RetOpcode = MBBI->getOpcode(); 679fe6060f1SDimitry Andric DebugLoc DL; 680fe6060f1SDimitry Andric if (MBBI != MBB.end()) 681fe6060f1SDimitry Andric DL = MBBI->getDebugLoc(); 68204eeddc0SDimitry Andric Register FramePtr = TRI->getFrameRegister(MF); 683fe6060f1SDimitry Andric unsigned MachineFramePtr = FramePtr; 684fe6060f1SDimitry Andric 685fe6060f1SDimitry Andric // Get the number of bytes to allocate from the FrameInfo. 686fe6060f1SDimitry Andric uint64_t StackSize = MFI.getStackSize(); 687fe6060f1SDimitry Andric uint64_t MaxAlign = calculateMaxStackAlign(MF); 688fe6060f1SDimitry Andric unsigned CSSize = MMFI->getCalleeSavedFrameSize(); 689fe6060f1SDimitry Andric uint64_t NumBytes = 0; 690fe6060f1SDimitry Andric 691fe6060f1SDimitry Andric if (hasFP(MF)) { 692fe6060f1SDimitry Andric // Calculate required stack adjustment. 693fe6060f1SDimitry Andric uint64_t FrameSize = StackSize - SlotSize; 694fe6060f1SDimitry Andric NumBytes = FrameSize - CSSize; 695fe6060f1SDimitry Andric 696fe6060f1SDimitry Andric // Callee-saved registers were pushed on stack before the stack was 697fe6060f1SDimitry Andric // realigned. 698fe6060f1SDimitry Andric if (TRI->hasStackRealignment(MF)) 699fe6060f1SDimitry Andric NumBytes = alignTo(FrameSize, MaxAlign); 700fe6060f1SDimitry Andric 701fe6060f1SDimitry Andric } else { 702fe6060f1SDimitry Andric NumBytes = StackSize - CSSize; 703fe6060f1SDimitry Andric } 704fe6060f1SDimitry Andric 705fe6060f1SDimitry Andric // Skip the callee-saved pop instructions. 706fe6060f1SDimitry Andric while (MBBI != MBB.begin()) { 707fe6060f1SDimitry Andric MachineBasicBlock::iterator PI = std::prev(MBBI); 708fe6060f1SDimitry Andric unsigned Opc = PI->getOpcode(); 709fe6060f1SDimitry Andric 710fe6060f1SDimitry Andric if ((Opc != M68k::POP32r || !PI->getFlag(MachineInstr::FrameDestroy)) && 711fe6060f1SDimitry Andric Opc != M68k::DBG_VALUE && !PI->isTerminator()) 712fe6060f1SDimitry Andric break; 713fe6060f1SDimitry Andric 714fe6060f1SDimitry Andric --MBBI; 715fe6060f1SDimitry Andric } 716fe6060f1SDimitry Andric MachineBasicBlock::iterator FirstCSPop = MBBI; 717fe6060f1SDimitry Andric 718fe6060f1SDimitry Andric if (MBBI != MBB.end()) 719fe6060f1SDimitry Andric DL = MBBI->getDebugLoc(); 720fe6060f1SDimitry Andric 721fe6060f1SDimitry Andric // If there is an ADD32ri or SUB32ri of SP immediately before this 722fe6060f1SDimitry Andric // instruction, merge the two instructions. 723fe6060f1SDimitry Andric if (NumBytes || MFI.hasVarSizedObjects()) 724fe6060f1SDimitry Andric NumBytes += mergeSPUpdates(MBB, MBBI, true); 725fe6060f1SDimitry Andric 726fe6060f1SDimitry Andric // If dynamic alloca is used, then reset SP to point to the last callee-saved 727fe6060f1SDimitry Andric // slot before popping them off! Same applies for the case, when stack was 728fe6060f1SDimitry Andric // realigned. Don't do this if this was a funclet epilogue, since the funclets 729fe6060f1SDimitry Andric // will not do realignment or dynamic stack allocation. 730fe6060f1SDimitry Andric if ((TRI->hasStackRealignment(MF) || MFI.hasVarSizedObjects())) { 731fe6060f1SDimitry Andric if (TRI->hasStackRealignment(MF)) 732fe6060f1SDimitry Andric MBBI = FirstCSPop; 733fe6060f1SDimitry Andric uint64_t LEAAmount = -CSSize; 734fe6060f1SDimitry Andric 735fe6060f1SDimitry Andric // 'move %FramePtr, SP' will not be recognized as an epilogue sequence. 736fe6060f1SDimitry Andric // However, we may use this sequence if we have a frame pointer because the 737fe6060f1SDimitry Andric // effects of the prologue can safely be undone. 738fe6060f1SDimitry Andric if (LEAAmount != 0) { 739fe6060f1SDimitry Andric unsigned Opc = M68k::LEA32p; 740fe6060f1SDimitry Andric M68k::addRegIndirectWithDisp( 741fe6060f1SDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr), FramePtr, false, 742fe6060f1SDimitry Andric LEAAmount); 743fe6060f1SDimitry Andric --MBBI; 744fe6060f1SDimitry Andric } else { 745*bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(M68k::UNLK)) 746*bdd1243dSDimitry Andric .addReg(MachineFramePtr, RegState::Kill) 747*bdd1243dSDimitry Andric .setMIFlag(MachineInstr::FrameDestroy); 748fe6060f1SDimitry Andric --MBBI; 749fe6060f1SDimitry Andric } 750*bdd1243dSDimitry Andric } else if (hasFP(MF)) { 751*bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, TII.get(M68k::UNLK)) 752*bdd1243dSDimitry Andric .addReg(MachineFramePtr, RegState::Kill) 753*bdd1243dSDimitry Andric .setMIFlag(MachineInstr::FrameDestroy); 754fe6060f1SDimitry Andric } else if (NumBytes) { 755fe6060f1SDimitry Andric // Adjust stack pointer back: SP += numbytes. 756fe6060f1SDimitry Andric emitSPUpdate(MBB, MBBI, NumBytes, /*InEpilogue=*/true); 757fe6060f1SDimitry Andric --MBBI; 758fe6060f1SDimitry Andric } 759fe6060f1SDimitry Andric 760fe6060f1SDimitry Andric if (!RetOpcode || !isTailCallOpcode(*RetOpcode)) { 761fe6060f1SDimitry Andric // Add the return addr area delta back since we are not tail calling. 762fe6060f1SDimitry Andric int Offset = -1 * MMFI->getTCReturnAddrDelta(); 763fe6060f1SDimitry Andric assert(Offset >= 0 && "TCDelta should never be positive"); 764fe6060f1SDimitry Andric if (Offset) { 765fe6060f1SDimitry Andric MBBI = MBB.getFirstTerminator(); 766fe6060f1SDimitry Andric 767fe6060f1SDimitry Andric // Check for possible merge with preceding ADD instruction. 768fe6060f1SDimitry Andric Offset += mergeSPUpdates(MBB, MBBI, true); 769fe6060f1SDimitry Andric emitSPUpdate(MBB, MBBI, Offset, /*InEpilogue=*/true); 770fe6060f1SDimitry Andric } 771fe6060f1SDimitry Andric } 772fe6060f1SDimitry Andric } 773fe6060f1SDimitry Andric 774fe6060f1SDimitry Andric void M68kFrameLowering::determineCalleeSaves(MachineFunction &MF, 775fe6060f1SDimitry Andric BitVector &SavedRegs, 776fe6060f1SDimitry Andric RegScavenger *RS) const { 777fe6060f1SDimitry Andric TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); 778fe6060f1SDimitry Andric 779fe6060f1SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 780fe6060f1SDimitry Andric 781fe6060f1SDimitry Andric M68kMachineFunctionInfo *M68kFI = MF.getInfo<M68kMachineFunctionInfo>(); 782fe6060f1SDimitry Andric int64_t TailCallReturnAddrDelta = M68kFI->getTCReturnAddrDelta(); 783fe6060f1SDimitry Andric 784fe6060f1SDimitry Andric if (TailCallReturnAddrDelta < 0) { 785fe6060f1SDimitry Andric // create RETURNADDR area 786fe6060f1SDimitry Andric // arg 787fe6060f1SDimitry Andric // arg 788fe6060f1SDimitry Andric // RETADDR 789fe6060f1SDimitry Andric // { ... 790fe6060f1SDimitry Andric // RETADDR area 791fe6060f1SDimitry Andric // ... 792fe6060f1SDimitry Andric // } 793fe6060f1SDimitry Andric // [FP] 794fe6060f1SDimitry Andric MFI.CreateFixedObject(-TailCallReturnAddrDelta, 795fe6060f1SDimitry Andric TailCallReturnAddrDelta - SlotSize, true); 796fe6060f1SDimitry Andric } 797fe6060f1SDimitry Andric 798fe6060f1SDimitry Andric // Spill the BasePtr if it's used. 799fe6060f1SDimitry Andric if (TRI->hasBasePointer(MF)) { 800fe6060f1SDimitry Andric SavedRegs.set(TRI->getBaseRegister()); 801fe6060f1SDimitry Andric } 802fe6060f1SDimitry Andric } 803fe6060f1SDimitry Andric 804fe6060f1SDimitry Andric bool M68kFrameLowering::assignCalleeSavedSpillSlots( 805fe6060f1SDimitry Andric MachineFunction &MF, const TargetRegisterInfo *TRI, 806fe6060f1SDimitry Andric std::vector<CalleeSavedInfo> &CSI) const { 807fe6060f1SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 808fe6060f1SDimitry Andric M68kMachineFunctionInfo *M68kFI = MF.getInfo<M68kMachineFunctionInfo>(); 809fe6060f1SDimitry Andric 810fe6060f1SDimitry Andric int SpillSlotOffset = getOffsetOfLocalArea() + M68kFI->getTCReturnAddrDelta(); 811fe6060f1SDimitry Andric 812fe6060f1SDimitry Andric if (hasFP(MF)) { 813fe6060f1SDimitry Andric // emitPrologue always spills frame register the first thing. 814fe6060f1SDimitry Andric SpillSlotOffset -= SlotSize; 815fe6060f1SDimitry Andric MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset); 816fe6060f1SDimitry Andric 817fe6060f1SDimitry Andric // Since emitPrologue and emitEpilogue will handle spilling and restoring of 818fe6060f1SDimitry Andric // the frame register, we can delete it from CSI list and not have to worry 819fe6060f1SDimitry Andric // about avoiding it later. 82004eeddc0SDimitry Andric Register FPReg = TRI->getFrameRegister(MF); 821fe6060f1SDimitry Andric for (unsigned i = 0, e = CSI.size(); i < e; ++i) { 822fe6060f1SDimitry Andric if (TRI->regsOverlap(CSI[i].getReg(), FPReg)) { 823fe6060f1SDimitry Andric CSI.erase(CSI.begin() + i); 824fe6060f1SDimitry Andric break; 825fe6060f1SDimitry Andric } 826fe6060f1SDimitry Andric } 827fe6060f1SDimitry Andric } 828fe6060f1SDimitry Andric 829fe6060f1SDimitry Andric // The rest is fine 830fe6060f1SDimitry Andric return false; 831fe6060f1SDimitry Andric } 832fe6060f1SDimitry Andric 833fe6060f1SDimitry Andric bool M68kFrameLowering::spillCalleeSavedRegisters( 834fe6060f1SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, 835fe6060f1SDimitry Andric ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 836fe6060f1SDimitry Andric auto &MRI = *static_cast<const M68kRegisterInfo *>(TRI); 837fe6060f1SDimitry Andric auto DL = MBB.findDebugLoc(MI); 838fe6060f1SDimitry Andric 839fe6060f1SDimitry Andric int FI = 0; 840fe6060f1SDimitry Andric unsigned Mask = 0; 841fe6060f1SDimitry Andric for (const auto &Info : CSI) { 842fe6060f1SDimitry Andric FI = std::max(FI, Info.getFrameIdx()); 84304eeddc0SDimitry Andric Register Reg = Info.getReg(); 844fe6060f1SDimitry Andric unsigned Shift = MRI.getSpillRegisterOrder(Reg); 845fe6060f1SDimitry Andric Mask |= 1 << Shift; 846fe6060f1SDimitry Andric } 847fe6060f1SDimitry Andric 848fe6060f1SDimitry Andric auto I = 849fe6060f1SDimitry Andric M68k::addFrameReference(BuildMI(MBB, MI, DL, TII.get(M68k::MOVM32pm)), FI) 850fe6060f1SDimitry Andric .addImm(Mask) 851fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameSetup); 852fe6060f1SDimitry Andric 853fe6060f1SDimitry Andric // Append implicit registers and mem locations 854fe6060f1SDimitry Andric const MachineFunction &MF = *MBB.getParent(); 855fe6060f1SDimitry Andric const MachineRegisterInfo &RI = MF.getRegInfo(); 856fe6060f1SDimitry Andric for (const auto &Info : CSI) { 85704eeddc0SDimitry Andric Register Reg = Info.getReg(); 858fe6060f1SDimitry Andric bool IsLiveIn = RI.isLiveIn(Reg); 859fe6060f1SDimitry Andric if (!IsLiveIn) 860fe6060f1SDimitry Andric MBB.addLiveIn(Reg); 861fe6060f1SDimitry Andric I.addReg(Reg, IsLiveIn ? RegState::Implicit : RegState::ImplicitKill); 862fe6060f1SDimitry Andric M68k::addMemOperand(I, Info.getFrameIdx(), 0); 863fe6060f1SDimitry Andric } 864fe6060f1SDimitry Andric 865fe6060f1SDimitry Andric return true; 866fe6060f1SDimitry Andric } 867fe6060f1SDimitry Andric 868fe6060f1SDimitry Andric bool M68kFrameLowering::restoreCalleeSavedRegisters( 869fe6060f1SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, 870fe6060f1SDimitry Andric MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 871fe6060f1SDimitry Andric auto &MRI = *static_cast<const M68kRegisterInfo *>(TRI); 872fe6060f1SDimitry Andric auto DL = MBB.findDebugLoc(MI); 873fe6060f1SDimitry Andric 874fe6060f1SDimitry Andric int FI = 0; 875fe6060f1SDimitry Andric unsigned Mask = 0; 876fe6060f1SDimitry Andric for (const auto &Info : CSI) { 877fe6060f1SDimitry Andric FI = std::max(FI, Info.getFrameIdx()); 87804eeddc0SDimitry Andric Register Reg = Info.getReg(); 879fe6060f1SDimitry Andric unsigned Shift = MRI.getSpillRegisterOrder(Reg); 880fe6060f1SDimitry Andric Mask |= 1 << Shift; 881fe6060f1SDimitry Andric } 882fe6060f1SDimitry Andric 883fe6060f1SDimitry Andric auto I = M68k::addFrameReference( 884fe6060f1SDimitry Andric BuildMI(MBB, MI, DL, TII.get(M68k::MOVM32mp)).addImm(Mask), FI) 885fe6060f1SDimitry Andric .setMIFlag(MachineInstr::FrameDestroy); 886fe6060f1SDimitry Andric 887fe6060f1SDimitry Andric // Append implicit registers and mem locations 888fe6060f1SDimitry Andric for (const auto &Info : CSI) { 889fe6060f1SDimitry Andric I.addReg(Info.getReg(), RegState::ImplicitDefine); 890fe6060f1SDimitry Andric M68k::addMemOperand(I, Info.getFrameIdx(), 0); 891fe6060f1SDimitry Andric } 892fe6060f1SDimitry Andric 893fe6060f1SDimitry Andric return true; 894fe6060f1SDimitry Andric } 895