xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/NVPTX/NVPTXPrologEpilogPass.cpp (revision 753f127f3ace09432b2baeffd71a308760641a62)
10b57cec5SDimitry Andric //===-- NVPTXPrologEpilogPass.cpp - NVPTX prolog/epilog inserter ----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file is a copy of the generic LLVM PrologEpilogInserter pass, modified
100b57cec5SDimitry Andric // to remove unneeded functionality and to handle virtual registers. Most code
110b57cec5SDimitry Andric // here is a copy of PrologEpilogInserter.cpp.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "NVPTX.h"
160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
220b57cec5SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
230b57cec5SDimitry Andric #include "llvm/Pass.h"
240b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
250b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric using namespace llvm;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric #define DEBUG_TYPE "nvptx-prolog-epilog"
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric namespace {
320b57cec5SDimitry Andric class NVPTXPrologEpilogPass : public MachineFunctionPass {
330b57cec5SDimitry Andric public:
340b57cec5SDimitry Andric   static char ID;
NVPTXPrologEpilogPass()350b57cec5SDimitry Andric   NVPTXPrologEpilogPass() : MachineFunctionPass(ID) {}
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
380b57cec5SDimitry Andric 
getPassName() const39*753f127fSDimitry Andric   StringRef getPassName() const override { return "NVPTX Prolog Epilog Pass"; }
40*753f127fSDimitry Andric 
410b57cec5SDimitry Andric private:
420b57cec5SDimitry Andric   void calculateFrameObjectOffsets(MachineFunction &Fn);
430b57cec5SDimitry Andric };
440b57cec5SDimitry Andric }
450b57cec5SDimitry Andric 
createNVPTXPrologEpilogPass()460b57cec5SDimitry Andric MachineFunctionPass *llvm::createNVPTXPrologEpilogPass() {
470b57cec5SDimitry Andric   return new NVPTXPrologEpilogPass();
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric char NVPTXPrologEpilogPass::ID = 0;
510b57cec5SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)520b57cec5SDimitry Andric bool NVPTXPrologEpilogPass::runOnMachineFunction(MachineFunction &MF) {
530b57cec5SDimitry Andric   const TargetSubtargetInfo &STI = MF.getSubtarget();
540b57cec5SDimitry Andric   const TargetFrameLowering &TFI = *STI.getFrameLowering();
550b57cec5SDimitry Andric   const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
560b57cec5SDimitry Andric   bool Modified = false;
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   calculateFrameObjectOffsets(MF);
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   for (MachineBasicBlock &MBB : MF) {
610b57cec5SDimitry Andric     for (MachineInstr &MI : MBB) {
620b57cec5SDimitry Andric       for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
630b57cec5SDimitry Andric         if (!MI.getOperand(i).isFI())
640b57cec5SDimitry Andric           continue;
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric         // Frame indices in debug values are encoded in a target independent
670b57cec5SDimitry Andric         // way with simply the frame index and offset rather than any
680b57cec5SDimitry Andric         // target-specific addressing mode.
690b57cec5SDimitry Andric         if (MI.isDebugValue()) {
70fe6060f1SDimitry Andric           MachineOperand &Op = MI.getOperand(i);
71fe6060f1SDimitry Andric           assert(
72fe6060f1SDimitry Andric               MI.isDebugOperand(&Op) &&
73fe6060f1SDimitry Andric               "Frame indices can only appear as a debug operand in a DBG_VALUE*"
74fe6060f1SDimitry Andric               " machine instruction");
755ffd83dbSDimitry Andric           Register Reg;
76fe6060f1SDimitry Andric           auto Offset =
77fe6060f1SDimitry Andric               TFI.getFrameIndexReference(MF, Op.getIndex(), Reg);
78fe6060f1SDimitry Andric           Op.ChangeToRegister(Reg, /*isDef=*/false);
79fe6060f1SDimitry Andric           const DIExpression *DIExpr = MI.getDebugExpression();
80fe6060f1SDimitry Andric           if (MI.isNonListDebugValue()) {
81fe6060f1SDimitry Andric             DIExpr = TRI.prependOffsetExpression(MI.getDebugExpression(), DIExpression::ApplyOffset, Offset);
82fe6060f1SDimitry Andric           } else {
83fe6060f1SDimitry Andric 	    SmallVector<uint64_t, 3> Ops;
84fe6060f1SDimitry Andric             TRI.getOffsetOpcodes(Offset, Ops);
85fe6060f1SDimitry Andric             unsigned OpIdx = MI.getDebugOperandIndex(&Op);
86fe6060f1SDimitry Andric             DIExpr = DIExpression::appendOpsToArg(DIExpr, Ops, OpIdx);
87fe6060f1SDimitry Andric           }
885ffd83dbSDimitry Andric           MI.getDebugExpressionOp().setMetadata(DIExpr);
890b57cec5SDimitry Andric           continue;
900b57cec5SDimitry Andric         }
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric         TRI.eliminateFrameIndex(MI, 0, i, nullptr);
930b57cec5SDimitry Andric         Modified = true;
940b57cec5SDimitry Andric       }
950b57cec5SDimitry Andric     }
960b57cec5SDimitry Andric   }
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   // Add function prolog/epilog
990b57cec5SDimitry Andric   TFI.emitPrologue(MF, MF.front());
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) {
1020b57cec5SDimitry Andric     // If last instruction is a return instruction, add an epilogue
1030b57cec5SDimitry Andric     if (I->isReturnBlock())
1040b57cec5SDimitry Andric       TFI.emitEpilogue(MF, *I);
1050b57cec5SDimitry Andric   }
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   return Modified;
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric /// AdjustStackOffset - Helper function used to adjust the stack frame offset.
AdjustStackOffset(MachineFrameInfo & MFI,int FrameIdx,bool StackGrowsDown,int64_t & Offset,Align & MaxAlign)1115ffd83dbSDimitry Andric static inline void AdjustStackOffset(MachineFrameInfo &MFI, int FrameIdx,
1120b57cec5SDimitry Andric                                      bool StackGrowsDown, int64_t &Offset,
1135ffd83dbSDimitry Andric                                      Align &MaxAlign) {
1140b57cec5SDimitry Andric   // If the stack grows down, add the object size to find the lowest address.
1150b57cec5SDimitry Andric   if (StackGrowsDown)
1160b57cec5SDimitry Andric     Offset += MFI.getObjectSize(FrameIdx);
1170b57cec5SDimitry Andric 
1185ffd83dbSDimitry Andric   Align Alignment = MFI.getObjectAlign(FrameIdx);
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric   // If the alignment of this object is greater than that of the stack, then
1210b57cec5SDimitry Andric   // increase the stack alignment to match.
1225ffd83dbSDimitry Andric   MaxAlign = std::max(MaxAlign, Alignment);
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric   // Adjust to alignment boundary.
1255ffd83dbSDimitry Andric   Offset = alignTo(Offset, Alignment);
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric   if (StackGrowsDown) {
1280b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "alloc FI(" << FrameIdx << ") at SP[" << -Offset
1290b57cec5SDimitry Andric                       << "]\n");
1300b57cec5SDimitry Andric     MFI.setObjectOffset(FrameIdx, -Offset); // Set the computed offset
1310b57cec5SDimitry Andric   } else {
1320b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "alloc FI(" << FrameIdx << ") at SP[" << Offset
1330b57cec5SDimitry Andric                       << "]\n");
1340b57cec5SDimitry Andric     MFI.setObjectOffset(FrameIdx, Offset);
1350b57cec5SDimitry Andric     Offset += MFI.getObjectSize(FrameIdx);
1360b57cec5SDimitry Andric   }
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric void
calculateFrameObjectOffsets(MachineFunction & Fn)1400b57cec5SDimitry Andric NVPTXPrologEpilogPass::calculateFrameObjectOffsets(MachineFunction &Fn) {
1410b57cec5SDimitry Andric   const TargetFrameLowering &TFI = *Fn.getSubtarget().getFrameLowering();
1420b57cec5SDimitry Andric   const TargetRegisterInfo *RegInfo = Fn.getSubtarget().getRegisterInfo();
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric   bool StackGrowsDown =
1450b57cec5SDimitry Andric     TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown;
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   // Loop over all of the stack objects, assigning sequential addresses...
1480b57cec5SDimitry Andric   MachineFrameInfo &MFI = Fn.getFrameInfo();
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric   // Start at the beginning of the local area.
1510b57cec5SDimitry Andric   // The Offset is the distance from the stack top in the direction
1520b57cec5SDimitry Andric   // of stack growth -- so it's always nonnegative.
1530b57cec5SDimitry Andric   int LocalAreaOffset = TFI.getOffsetOfLocalArea();
1540b57cec5SDimitry Andric   if (StackGrowsDown)
1550b57cec5SDimitry Andric     LocalAreaOffset = -LocalAreaOffset;
1560b57cec5SDimitry Andric   assert(LocalAreaOffset >= 0
1570b57cec5SDimitry Andric          && "Local area offset should be in direction of stack growth");
1580b57cec5SDimitry Andric   int64_t Offset = LocalAreaOffset;
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   // If there are fixed sized objects that are preallocated in the local area,
1610b57cec5SDimitry Andric   // non-fixed objects can't be allocated right at the start of local area.
1620b57cec5SDimitry Andric   // We currently don't support filling in holes in between fixed sized
1630b57cec5SDimitry Andric   // objects, so we adjust 'Offset' to point to the end of last fixed sized
1640b57cec5SDimitry Andric   // preallocated object.
1650b57cec5SDimitry Andric   for (int i = MFI.getObjectIndexBegin(); i != 0; ++i) {
1660b57cec5SDimitry Andric     int64_t FixedOff;
1670b57cec5SDimitry Andric     if (StackGrowsDown) {
1680b57cec5SDimitry Andric       // The maximum distance from the stack pointer is at lower address of
1690b57cec5SDimitry Andric       // the object -- which is given by offset. For down growing stack
1700b57cec5SDimitry Andric       // the offset is negative, so we negate the offset to get the distance.
1710b57cec5SDimitry Andric       FixedOff = -MFI.getObjectOffset(i);
1720b57cec5SDimitry Andric     } else {
1730b57cec5SDimitry Andric       // The maximum distance from the start pointer is at the upper
1740b57cec5SDimitry Andric       // address of the object.
1750b57cec5SDimitry Andric       FixedOff = MFI.getObjectOffset(i) + MFI.getObjectSize(i);
1760b57cec5SDimitry Andric     }
1770b57cec5SDimitry Andric     if (FixedOff > Offset) Offset = FixedOff;
1780b57cec5SDimitry Andric   }
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric   // NOTE: We do not have a call stack
1810b57cec5SDimitry Andric 
1825ffd83dbSDimitry Andric   Align MaxAlign = MFI.getMaxAlign();
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric   // No scavenger
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric   // FIXME: Once this is working, then enable flag will change to a target
1870b57cec5SDimitry Andric   // check for whether the frame is large enough to want to use virtual
1880b57cec5SDimitry Andric   // frame index registers. Functions which don't want/need this optimization
1890b57cec5SDimitry Andric   // will continue to use the existing code path.
1900b57cec5SDimitry Andric   if (MFI.getUseLocalStackAllocationBlock()) {
1915ffd83dbSDimitry Andric     Align Alignment = MFI.getLocalFrameMaxAlign();
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric     // Adjust to alignment boundary.
1945ffd83dbSDimitry Andric     Offset = alignTo(Offset, Alignment);
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Local frame base offset: " << Offset << "\n");
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric     // Resolve offsets for objects in the local block.
1990b57cec5SDimitry Andric     for (unsigned i = 0, e = MFI.getLocalFrameObjectCount(); i != e; ++i) {
2000b57cec5SDimitry Andric       std::pair<int, int64_t> Entry = MFI.getLocalFrameObjectMap(i);
2010b57cec5SDimitry Andric       int64_t FIOffset = (StackGrowsDown ? -Offset : Offset) + Entry.second;
2020b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "alloc FI(" << Entry.first << ") at SP[" << FIOffset
2030b57cec5SDimitry Andric                         << "]\n");
2040b57cec5SDimitry Andric       MFI.setObjectOffset(Entry.first, FIOffset);
2050b57cec5SDimitry Andric     }
2060b57cec5SDimitry Andric     // Allocate the local block
2070b57cec5SDimitry Andric     Offset += MFI.getLocalFrameSize();
2080b57cec5SDimitry Andric 
2095ffd83dbSDimitry Andric     MaxAlign = std::max(Alignment, MaxAlign);
2100b57cec5SDimitry Andric   }
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric   // No stack protector
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric   // Then assign frame offsets to stack objects that are not used to spill
2150b57cec5SDimitry Andric   // callee saved registers.
2160b57cec5SDimitry Andric   for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) {
2170b57cec5SDimitry Andric     if (MFI.isObjectPreAllocated(i) &&
2180b57cec5SDimitry Andric         MFI.getUseLocalStackAllocationBlock())
2190b57cec5SDimitry Andric       continue;
2200b57cec5SDimitry Andric     if (MFI.isDeadObjectIndex(i))
2210b57cec5SDimitry Andric       continue;
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric     AdjustStackOffset(MFI, i, StackGrowsDown, Offset, MaxAlign);
2240b57cec5SDimitry Andric   }
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric   // No scavenger
2270b57cec5SDimitry Andric 
2280b57cec5SDimitry Andric   if (!TFI.targetHandlesStackFrameRounding()) {
2290b57cec5SDimitry Andric     // If we have reserved argument space for call sites in the function
2300b57cec5SDimitry Andric     // immediately on entry to the current function, count it as part of the
2310b57cec5SDimitry Andric     // overall stack size.
2320b57cec5SDimitry Andric     if (MFI.adjustsStack() && TFI.hasReservedCallFrame(Fn))
2330b57cec5SDimitry Andric       Offset += MFI.getMaxCallFrameSize();
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric     // Round up the size to a multiple of the alignment.  If the function has
2360b57cec5SDimitry Andric     // any calls or alloca's, align to the target's StackAlignment value to
2370b57cec5SDimitry Andric     // ensure that the callee's frame or the alloca data is suitably aligned;
2380b57cec5SDimitry Andric     // otherwise, for leaf functions, align to the TransientStackAlignment
2390b57cec5SDimitry Andric     // value.
2405ffd83dbSDimitry Andric     Align StackAlign;
2410b57cec5SDimitry Andric     if (MFI.adjustsStack() || MFI.hasVarSizedObjects() ||
242fe6060f1SDimitry Andric         (RegInfo->hasStackRealignment(Fn) && MFI.getObjectIndexEnd() != 0))
2435ffd83dbSDimitry Andric       StackAlign = TFI.getStackAlign();
2440b57cec5SDimitry Andric     else
2455ffd83dbSDimitry Andric       StackAlign = TFI.getTransientStackAlign();
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric     // If the frame pointer is eliminated, all frame offsets will be relative to
2480b57cec5SDimitry Andric     // SP not FP. Align to MaxAlign so this works.
2495ffd83dbSDimitry Andric     Offset = alignTo(Offset, std::max(StackAlign, MaxAlign));
2500b57cec5SDimitry Andric   }
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric   // Update frame info to pretend that this is part of the stack...
2530b57cec5SDimitry Andric   int64_t StackSize = Offset - LocalAreaOffset;
2540b57cec5SDimitry Andric   MFI.setStackSize(StackSize);
2550b57cec5SDimitry Andric }
256