[MachineScheduler] Fix physreg dependencies of ExitSU (#123541)
[llvm-project.git] / llvm / lib / CodeGen / StackFrameLayoutAnalysisPass.cpp
blobaa71be16f0552e755862ad3499e23b5bd014fa9a
1 //===-- StackFrameLayoutAnalysisPass.cpp
2 //------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // StackFrameLayoutAnalysisPass implementation. Outputs information about the
11 // layout of the stack frame, using the remarks interface. On the CLI it prints
12 // a textual representation of the stack frame. When possible it prints the
13 // values that occupy a stack slot using any available debug information. Since
14 // output is remarks based, it is also available in a machine readable file
15 // format, such as YAML.
17 //===----------------------------------------------------------------------===//
19 #include "llvm/ADT/SetVector.h"
20 #include "llvm/Analysis/OptimizationRemarkEmitter.h"
21 #include "llvm/CodeGen/MachineFrameInfo.h"
22 #include "llvm/CodeGen/MachineFunction.h"
23 #include "llvm/CodeGen/MachineFunctionPass.h"
24 #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
25 #include "llvm/CodeGen/Passes.h"
26 #include "llvm/CodeGen/SlotIndexes.h"
27 #include "llvm/CodeGen/StackProtector.h"
28 #include "llvm/CodeGen/TargetFrameLowering.h"
29 #include "llvm/CodeGen/TargetSubtargetInfo.h"
30 #include "llvm/IR/DebugInfoMetadata.h"
31 #include "llvm/IR/PrintPasses.h"
32 #include "llvm/InitializePasses.h"
33 #include "llvm/Support/Debug.h"
34 #include "llvm/Support/FormatVariadic.h"
35 #include "llvm/Support/raw_ostream.h"
37 using namespace llvm;
39 #define DEBUG_TYPE "stack-frame-layout"
41 namespace {
43 /// StackFrameLayoutAnalysisPass - This is a pass to dump the stack frame of a
44 /// MachineFunction.
45 ///
46 struct StackFrameLayoutAnalysisPass : public MachineFunctionPass {
47 using SlotDbgMap = SmallDenseMap<int, SetVector<const DILocalVariable *>>;
48 static char ID;
50 enum SlotType {
51 Spill, // a Spill slot
52 Fixed, // a Fixed slot (e.g. arguments passed on the stack)
53 VariableSized, // a variable sized object
54 StackProtector, // Stack Protector slot
55 Variable, // a slot used to store a local data (could be a tmp)
56 Invalid // It's an error for a slot to have this type
59 struct SlotData {
60 int Slot;
61 int Size;
62 int Align;
63 StackOffset Offset;
64 SlotType SlotTy;
65 bool Scalable;
67 SlotData(const MachineFrameInfo &MFI, const StackOffset Offset,
68 const int Idx)
69 : Slot(Idx), Size(MFI.getObjectSize(Idx)),
70 Align(MFI.getObjectAlign(Idx).value()), Offset(Offset),
71 SlotTy(Invalid), Scalable(false) {
72 Scalable = MFI.getStackID(Idx) == TargetStackID::ScalableVector;
73 if (MFI.isSpillSlotObjectIndex(Idx))
74 SlotTy = SlotType::Spill;
75 else if (MFI.isFixedObjectIndex(Idx))
76 SlotTy = SlotType::Fixed;
77 else if (MFI.isVariableSizedObjectIndex(Idx))
78 SlotTy = SlotType::VariableSized;
79 else if (MFI.hasStackProtectorIndex() &&
80 Idx == MFI.getStackProtectorIndex())
81 SlotTy = SlotType::StackProtector;
82 else
83 SlotTy = SlotType::Variable;
86 bool isVarSize() const { return SlotTy == SlotType::VariableSized; }
88 // We use this to sort in reverse order, so that the layout is displayed
89 // correctly. Variable sized slots are sorted to the end of the list, as
90 // offsets are currently incorrect for these but they reside at the end of
91 // the stack frame. The Slot index is used to ensure deterministic order
92 // when offsets are equal.
93 bool operator<(const SlotData &Rhs) const {
94 return std::make_tuple(!isVarSize(),
95 Offset.getFixed() + Offset.getScalable(), Slot) >
96 std::make_tuple(!Rhs.isVarSize(),
97 Rhs.Offset.getFixed() + Rhs.Offset.getScalable(),
98 Rhs.Slot);
102 StackFrameLayoutAnalysisPass() : MachineFunctionPass(ID) {}
104 StringRef getPassName() const override {
105 return "Stack Frame Layout Analysis";
108 void getAnalysisUsage(AnalysisUsage &AU) const override {
109 AU.setPreservesAll();
110 MachineFunctionPass::getAnalysisUsage(AU);
111 AU.addRequired<MachineOptimizationRemarkEmitterPass>();
114 bool runOnMachineFunction(MachineFunction &MF) override {
115 // TODO: We should implement a similar filter for remarks:
116 // -Rpass-func-filter=<regex>
117 if (!isFunctionInPrintList(MF.getName()))
118 return false;
120 LLVMContext &Ctx = MF.getFunction().getContext();
121 if (!Ctx.getDiagHandlerPtr()->isAnalysisRemarkEnabled(DEBUG_TYPE))
122 return false;
124 MachineOptimizationRemarkAnalysis Rem(DEBUG_TYPE, "StackLayout",
125 MF.getFunction().getSubprogram(),
126 &MF.front());
127 Rem << ("\nFunction: " + MF.getName()).str();
128 emitStackFrameLayoutRemarks(MF, Rem);
129 getAnalysis<MachineOptimizationRemarkEmitterPass>().getORE().emit(Rem);
130 return false;
133 std::string getTypeString(SlotType Ty) {
134 switch (Ty) {
135 case SlotType::Spill:
136 return "Spill";
137 case SlotType::Fixed:
138 return "Fixed";
139 case SlotType::VariableSized:
140 return "VariableSized";
141 case SlotType::StackProtector:
142 return "Protector";
143 case SlotType::Variable:
144 return "Variable";
145 default:
146 llvm_unreachable("bad slot type for stack layout");
150 void emitStackSlotRemark(const MachineFunction &MF, const SlotData &D,
151 MachineOptimizationRemarkAnalysis &Rem) {
152 // To make it easy to understand the stack layout from the CLI, we want to
153 // print each slot like the following:
155 // Offset: [SP+8], Type: Spill, Align: 8, Size: 16
156 // foo @ /path/to/file.c:25
157 // bar @ /path/to/file.c:35
159 // Which prints the size, alignment, and offset from the SP at function
160 // entry.
162 // But we also want the machine readable remarks data to be nicely
163 // organized. So we print some additional data as strings for the CLI
164 // output, but maintain more structured data for the YAML.
166 // For example we store the Offset in YAML as:
167 // ...
168 // - Offset: -8
169 // - ScalableOffset: -16
170 // Note: the ScalableOffset entries are added only for slots with non-zero
171 // scalable offsets.
173 // But we print it to the CLI as:
174 // Offset: [SP-8]
176 // Or with non-zero scalable offset:
177 // Offset: [SP-8-16 x vscale]
179 // Negative offsets will print a leading `-`, so only add `+`
180 std::string Prefix =
181 formatv("\nOffset: [SP{0}", (D.Offset.getFixed() < 0) ? "" : "+").str();
182 Rem << Prefix << ore::NV("Offset", D.Offset.getFixed());
184 if (D.Offset.getScalable()) {
185 Rem << ((D.Offset.getScalable() < 0) ? "" : "+")
186 << ore::NV("ScalableOffset", D.Offset.getScalable()) << " x vscale";
189 Rem << "], Type: " << ore::NV("Type", getTypeString(D.SlotTy))
190 << ", Align: " << ore::NV("Align", D.Align)
191 << ", Size: " << ore::NV("Size", ElementCount::get(D.Size, D.Scalable));
194 void emitSourceLocRemark(const MachineFunction &MF, const DILocalVariable *N,
195 MachineOptimizationRemarkAnalysis &Rem) {
196 std::string Loc =
197 formatv("{0} @ {1}:{2}", N->getName(), N->getFilename(), N->getLine())
198 .str();
199 Rem << "\n " << ore::NV("DataLoc", Loc);
202 StackOffset getStackOffset(const MachineFunction &MF,
203 const MachineFrameInfo &MFI,
204 const TargetFrameLowering *FI, int FrameIdx) {
205 if (!FI)
206 return StackOffset::getFixed(MFI.getObjectOffset(FrameIdx));
208 return FI->getFrameIndexReferenceFromSP(MF, FrameIdx);
211 void emitStackFrameLayoutRemarks(MachineFunction &MF,
212 MachineOptimizationRemarkAnalysis &Rem) {
213 const MachineFrameInfo &MFI = MF.getFrameInfo();
214 if (!MFI.hasStackObjects())
215 return;
217 const TargetFrameLowering *FI = MF.getSubtarget().getFrameLowering();
219 LLVM_DEBUG(dbgs() << "getStackProtectorIndex =="
220 << MFI.getStackProtectorIndex() << "\n");
222 std::vector<SlotData> SlotInfo;
224 const unsigned int NumObj = MFI.getNumObjects();
225 SlotInfo.reserve(NumObj);
226 // initialize slot info
227 for (int Idx = MFI.getObjectIndexBegin(), EndIdx = MFI.getObjectIndexEnd();
228 Idx != EndIdx; ++Idx) {
229 if (MFI.isDeadObjectIndex(Idx))
230 continue;
231 SlotInfo.emplace_back(MFI, getStackOffset(MF, MFI, FI, Idx), Idx);
234 // sort the ordering, to match the actual layout in memory
235 llvm::sort(SlotInfo);
237 SlotDbgMap SlotMap = genSlotDbgMapping(MF);
239 for (const SlotData &Info : SlotInfo) {
240 emitStackSlotRemark(MF, Info, Rem);
241 for (const DILocalVariable *N : SlotMap[Info.Slot])
242 emitSourceLocRemark(MF, N, Rem);
246 // We need to generate a mapping of slots to the values that are stored to
247 // them. This information is lost by the time we need to print out the frame,
248 // so we reconstruct it here by walking the CFG, and generating the mapping.
249 SlotDbgMap genSlotDbgMapping(MachineFunction &MF) {
250 SlotDbgMap SlotDebugMap;
252 // add variables to the map
253 for (MachineFunction::VariableDbgInfo &DI :
254 MF.getInStackSlotVariableDbgInfo())
255 SlotDebugMap[DI.getStackSlot()].insert(DI.Var);
257 // Then add all the spills that have debug data
258 for (MachineBasicBlock &MBB : MF) {
259 for (MachineInstr &MI : MBB) {
260 for (MachineMemOperand *MO : MI.memoperands()) {
261 if (!MO->isStore())
262 continue;
263 auto *FI = dyn_cast_or_null<FixedStackPseudoSourceValue>(
264 MO->getPseudoValue());
265 if (!FI)
266 continue;
267 int FrameIdx = FI->getFrameIndex();
268 SmallVector<MachineInstr *> Dbg;
269 MI.collectDebugValues(Dbg);
271 for (MachineInstr *MI : Dbg)
272 SlotDebugMap[FrameIdx].insert(MI->getDebugVariable());
277 return SlotDebugMap;
281 char StackFrameLayoutAnalysisPass::ID = 0;
282 } // namespace
284 char &llvm::StackFrameLayoutAnalysisPassID = StackFrameLayoutAnalysisPass::ID;
285 INITIALIZE_PASS(StackFrameLayoutAnalysisPass, "stack-frame-layout",
286 "Stack Frame Layout", false, false)
288 namespace llvm {
289 /// Returns a newly-created StackFrameLayout pass.
290 MachineFunctionPass *createStackFrameLayoutAnalysisPass() {
291 return new StackFrameLayoutAnalysisPass();
294 } // namespace llvm