LLVM 22.0.0git
StackFrameLayoutAnalysisPass.cpp
Go to the documentation of this file.
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.
16//
17//===----------------------------------------------------------------------===//
18
20#include "llvm/ADT/SetVector.h"
26#include "llvm/CodeGen/Passes.h"
32#include "llvm/IR/PrintPasses.h"
34#include "llvm/Support/Debug.h"
37
38using namespace llvm;
39
40#define DEBUG_TYPE "stack-frame-layout"
41
42namespace {
43
44/// StackFrameLayoutAnalysisPass - This is a pass to dump the stack frame of a
45/// MachineFunction.
46///
47struct StackFrameLayoutAnalysis {
50
51 StackFrameLayoutAnalysis(MachineOptimizationRemarkEmitter &ORE) : ORE(ORE) {}
52
53 enum SlotType {
54 Spill, // a Spill slot
55 Fixed, // a Fixed slot (e.g. arguments passed on the stack)
56 VariableSized, // a variable sized object
57 StackProtector, // Stack Protector slot
58 Variable, // a slot used to store a local data (could be a tmp)
59 Invalid // It's an error for a slot to have this type
60 };
61
62 struct SlotData {
63 int Slot;
64 int Size;
65 int Align;
66 StackOffset Offset;
67 SlotType SlotTy;
68 bool Scalable;
69
70 SlotData(const MachineFrameInfo &MFI, const StackOffset Offset,
71 const int Idx)
72 : Slot(Idx), Size(MFI.getObjectSize(Idx)),
73 Align(MFI.getObjectAlign(Idx).value()), Offset(Offset),
74 SlotTy(Invalid), Scalable(false) {
77 SlotTy = SlotType::Spill;
78 else if (MFI.isFixedObjectIndex(Idx))
79 SlotTy = SlotType::Fixed;
80 else if (MFI.isVariableSizedObjectIndex(Idx))
81 SlotTy = SlotType::VariableSized;
82 else if (MFI.hasStackProtectorIndex() &&
84 SlotTy = SlotType::StackProtector;
85 else
86 SlotTy = SlotType::Variable;
87 }
88
89 bool isVarSize() const { return SlotTy == SlotType::VariableSized; }
90
91 // We use this to sort in reverse order, so that the layout is displayed
92 // correctly. Variable sized slots are sorted to the end of the list, as
93 // offsets are currently incorrect for these but they reside at the end of
94 // the stack frame. The Slot index is used to ensure deterministic order
95 // when offsets are equal.
96 bool operator<(const SlotData &Rhs) const {
97 return std::make_tuple(!isVarSize(),
98 Offset.getFixed() + Offset.getScalable(), Slot) >
99 std::make_tuple(!Rhs.isVarSize(),
100 Rhs.Offset.getFixed() + Rhs.Offset.getScalable(),
101 Rhs.Slot);
102 }
103 };
104
105 bool run(MachineFunction &MF) {
106 // TODO: We should implement a similar filter for remarks:
107 // -Rpass-func-filter=<regex>
109 return false;
110
111 LLVMContext &Ctx = MF.getFunction().getContext();
113 return false;
114
117 &MF.front());
118 Rem << ("\nFunction: " + MF.getName()).str();
119 emitStackFrameLayoutRemarks(MF, Rem);
120 ORE.emit(Rem);
121 return false;
122 }
123
124 std::string getTypeString(SlotType Ty) {
125 switch (Ty) {
126 case SlotType::Spill:
127 return "Spill";
128 case SlotType::Fixed:
129 return "Fixed";
130 case SlotType::VariableSized:
131 return "VariableSized";
132 case SlotType::StackProtector:
133 return "Protector";
134 case SlotType::Variable:
135 return "Variable";
136 default:
137 llvm_unreachable("bad slot type for stack layout");
138 }
139 }
140
141 void emitStackSlotRemark(const MachineFunction &MF, const SlotData &D,
143 // To make it easy to understand the stack layout from the CLI, we want to
144 // print each slot like the following:
145 //
146 // Offset: [SP+8], Type: Spill, Align: 8, Size: 16
147 // foo @ /path/to/file.c:25
148 // bar @ /path/to/file.c:35
149 //
150 // Which prints the size, alignment, and offset from the SP at function
151 // entry.
152 //
153 // But we also want the machine readable remarks data to be nicely
154 // organized. So we print some additional data as strings for the CLI
155 // output, but maintain more structured data for the YAML.
156 //
157 // For example we store the Offset in YAML as:
158 // ...
159 // - Offset: -8
160 // - ScalableOffset: -16
161 // Note: the ScalableOffset entries are added only for slots with non-zero
162 // scalable offsets.
163 //
164 // But we print it to the CLI as:
165 // Offset: [SP-8]
166 //
167 // Or with non-zero scalable offset:
168 // Offset: [SP-8-16 x vscale]
169
170 // Negative offsets will print a leading `-`, so only add `+`
171 std::string Prefix =
172 formatv("\nOffset: [SP{0}", (D.Offset.getFixed() < 0) ? "" : "+").str();
173 Rem << Prefix << ore::NV("Offset", D.Offset.getFixed());
174
175 if (D.Offset.getScalable()) {
176 Rem << ((D.Offset.getScalable() < 0) ? "" : "+")
177 << ore::NV("ScalableOffset", D.Offset.getScalable()) << " x vscale";
178 }
179
180 Rem << "], Type: " << ore::NV("Type", getTypeString(D.SlotTy))
181 << ", Align: " << ore::NV("Align", D.Align)
182 << ", Size: " << ore::NV("Size", ElementCount::get(D.Size, D.Scalable));
183 }
184
185 void emitSourceLocRemark(const MachineFunction &MF, const DILocalVariable *N,
187 std::string Loc =
188 formatv("{0} @ {1}:{2}", N->getName(), N->getFilename(), N->getLine())
189 .str();
190 Rem << "\n " << ore::NV("DataLoc", Loc);
191 }
192
194 const MachineFrameInfo &MFI,
195 const TargetFrameLowering *FI, int FrameIdx) {
196 if (!FI)
197 return StackOffset::getFixed(MFI.getObjectOffset(FrameIdx));
198
199 return FI->getFrameIndexReferenceFromSP(MF, FrameIdx);
200 }
201
202 void emitStackFrameLayoutRemarks(MachineFunction &MF,
204 const MachineFrameInfo &MFI = MF.getFrameInfo();
205 if (!MFI.hasStackObjects())
206 return;
207
209
210 LLVM_DEBUG(dbgs() << "getStackProtectorIndex =="
211 << MFI.getStackProtectorIndex() << "\n");
212
213 std::vector<SlotData> SlotInfo;
214
215 const unsigned int NumObj = MFI.getNumObjects();
216 SlotInfo.reserve(NumObj);
217 // initialize slot info
218 for (int Idx = MFI.getObjectIndexBegin(), EndIdx = MFI.getObjectIndexEnd();
219 Idx != EndIdx; ++Idx) {
220 if (MFI.isDeadObjectIndex(Idx))
221 continue;
222 SlotInfo.emplace_back(MFI, getStackOffset(MF, MFI, FI, Idx), Idx);
223 }
224
225 // sort the ordering, to match the actual layout in memory
226 llvm::sort(SlotInfo);
227
228 SlotDbgMap SlotMap = genSlotDbgMapping(MF);
229
230 for (const SlotData &Info : SlotInfo) {
231 emitStackSlotRemark(MF, Info, Rem);
232 for (const DILocalVariable *N : SlotMap[Info.Slot])
233 emitSourceLocRemark(MF, N, Rem);
234 }
235 }
236
237 // We need to generate a mapping of slots to the values that are stored to
238 // them. This information is lost by the time we need to print out the frame,
239 // so we reconstruct it here by walking the CFG, and generating the mapping.
240 SlotDbgMap genSlotDbgMapping(MachineFunction &MF) {
241 SlotDbgMap SlotDebugMap;
242
243 // add variables to the map
246 SlotDebugMap[DI.getStackSlot()].insert(DI.Var);
247
248 // Then add all the spills that have debug data
249 for (MachineBasicBlock &MBB : MF) {
250 for (MachineInstr &MI : MBB) {
251 for (MachineMemOperand *MO : MI.memoperands()) {
252 if (!MO->isStore())
253 continue;
254 auto *FI = dyn_cast_or_null<FixedStackPseudoSourceValue>(
255 MO->getPseudoValue());
256 if (!FI)
257 continue;
258 int FrameIdx = FI->getFrameIndex();
260 MI.collectDebugValues(Dbg);
261
262 for (MachineInstr *MI : Dbg)
263 SlotDebugMap[FrameIdx].insert(MI->getDebugVariable());
264 }
265 }
266 }
267
268 return SlotDebugMap;
269 }
270};
271
272class StackFrameLayoutAnalysisLegacy : public MachineFunctionPass {
273public:
274 static char ID;
275
276 StackFrameLayoutAnalysisLegacy() : MachineFunctionPass(ID) {}
277
278 StringRef getPassName() const override {
279 return "Stack Frame Layout Analysis";
280 }
281
282 void getAnalysisUsage(AnalysisUsage &AU) const override {
283 AU.setPreservesAll();
286 }
287
288 bool runOnMachineFunction(MachineFunction &MF) override {
289 auto &ORE = getAnalysis<MachineOptimizationRemarkEmitterPass>().getORE();
290 return StackFrameLayoutAnalysis(ORE).run(MF);
291 }
292};
293
294char StackFrameLayoutAnalysisLegacy::ID = 0;
295} // namespace
296
301 StackFrameLayoutAnalysis(ORE).run(MF);
302 return PreservedAnalyses::all();
303}
304
305char &llvm::StackFrameLayoutAnalysisPassID = StackFrameLayoutAnalysisLegacy::ID;
306INITIALIZE_PASS(StackFrameLayoutAnalysisLegacy, "stack-frame-layout",
307 "Stack Frame Layout", false, false)
308
309namespace llvm {
310/// Returns a newly-created StackFrameLayout pass.
312 return new StackFrameLayoutAnalysisLegacy();
313}
314
315} // namespace llvm
static StackOffset getStackOffset(const MachineFunction &MF, int64_t ObjectOffset)
MachineBasicBlock & MBB
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
IRTranslator LLVM IR MI
static std::string getTypeString(Type *T)
Definition: LLParser.cpp:67
===- MachineOptimizationRemarkEmitter.h - Opt Diagnostics -*- C++ -*-—===//
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:56
This file implements a set that has insertion order iteration characteristics.
#define DEBUG_TYPE
#define LLVM_DEBUG(...)
Definition: Debug.h:119
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:255
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:412
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
void setPreservesAll()
Set by analyses that do not transform their input at all.
static constexpr ElementCount get(ScalarTy MinVal, bool Scalable)
Definition: TypeSize.h:318
DISubprogram * getSubprogram() const
Get the attached subprogram.
Definition: Metadata.cpp:1915
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition: Function.cpp:359
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:68
LLVM_ABI const DiagnosticHandler * getDiagHandlerPtr() const
getDiagHandlerPtr - Returns const raw pointer of DiagnosticHandler set by setDiagnosticHandler.
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
int getStackProtectorIndex() const
Return the index for the stack protector object.
Align getObjectAlign(int ObjectIdx) const
Return the alignment of the specified stack object.
bool isSpillSlotObjectIndex(int ObjectIdx) const
Returns true if the specified index corresponds to a spill slot.
int64_t getObjectSize(int ObjectIdx) const
Return the size of the specified object.
unsigned getNumObjects() const
Return the number of objects.
bool isVariableSizedObjectIndex(int ObjectIdx) const
Returns true if the specified index corresponds to a variable sized object.
int getObjectIndexEnd() const
Return one past the maximum frame object index.
bool hasStackProtectorIndex() const
bool hasStackObjects() const
Return true if there are any stack objects in this function.
uint8_t getStackID(int ObjectIdx) const
int64_t getObjectOffset(int ObjectIdx) const
Return the assigned stack offset of the specified object from the incoming stack pointer.
bool isFixedObjectIndex(int ObjectIdx) const
Returns true if the specified index corresponds to a fixed stack object.
int getObjectIndexBegin() const
Return the minimum frame object index.
bool isDeadObjectIndex(int ObjectIdx) const
Returns true if the specified index corresponds to a dead object.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
Description of the location of a variable whose Address is valid and unchanging during function execu...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
auto getInStackSlotVariableDbgInfo()
Returns the collection of variables for which we have debug info and that have been assigned a stack ...
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineBasicBlock & front() const
Representation of each machine instruction.
Definition: MachineInstr.h:72
A description of a memory reference used in the backend.
Diagnostic information for optimization analysis remarks.
LLVM_ABI Result run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
LLVM_ABI void emit(DiagnosticInfoOptimizationBase &OptDiag)
Emit an optimization remark.
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:85
A set of analyses that are preserved following a run of a transformation pass.
Definition: Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: Analysis.h:118
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
StackOffset holds a fixed and a scalable offset in bytes.
Definition: TypeSize.h:34
int64_t getFixed() const
Returns the fixed component of the stack.
Definition: TypeSize.h:50
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
Information about stack frame layout on the target.
virtual StackOffset getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI) const
getFrameIndexReferenceFromSP - This method returns the offset from the stack pointer to the slot of t...
virtual const TargetFrameLowering * getFrameLowering() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
DiagnosticInfoOptimizationBase::Argument NV
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
bool operator<(int64_t V1, const APSInt &V2)
Definition: APSInt.h:362
LLVM_ABI MachineFunctionPass * createStackFrameLayoutAnalysisPass()
StackFramePrinter pass - This pass prints out the machine function's stack frame to the given stream ...
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1669
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:207
bool isFunctionInPrintList(StringRef FunctionName)
LLVM_ABI char & StackFrameLayoutAnalysisPassID
StackFramePrinter - This pass prints the stack frame layout and variable mappings.
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
uint64_t value() const
This is a hole in the type system and should not be abused.
Definition: Alignment.h:85
virtual bool isAnalysisRemarkEnabled(StringRef PassName) const
Return true if analysis remarks are enabled, override to provide different implementation.