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