1 //===-- StackFrameLayoutAnalysisPass.cpp
2 //------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
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"
41 #define DEBUG_TYPE "stack-frame-layout"
45 /// StackFrameLayoutAnalysisPass - This is a pass to dump the stack frame of a
48 struct StackFrameLayoutAnalysisPass
: public MachineFunctionPass
{
49 using SlotDbgMap
= SmallDenseMap
<int, SetVector
<const DILocalVariable
*>>;
53 Spill
, // a Spill slot
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
66 SlotData(const MachineFrameInfo
&MFI
, const int ValOffset
, const int Idx
)
67 : Slot(Idx
), Size(MFI
.getObjectSize(Idx
)),
68 Align(MFI
.getObjectAlign(Idx
).value()),
69 Offset(MFI
.getObjectOffset(Idx
) - ValOffset
), SlotTy(Invalid
) {
70 if (MFI
.isSpillSlotObjectIndex(Idx
))
71 SlotTy
= SlotType::Spill
;
72 else if (Idx
== MFI
.getStackProtectorIndex())
73 SlotTy
= SlotType::StackProtector
;
75 SlotTy
= SlotType::Variable
;
78 // we use this to sort in reverse order, so that the layout is displayed
80 bool operator<(const SlotData
&Rhs
) const { return Offset
> Rhs
.Offset
; }
83 StackFrameLayoutAnalysisPass() : MachineFunctionPass(ID
) {}
85 StringRef
getPassName() const override
{
86 return "Stack Frame Layout Analysis";
89 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
91 MachineFunctionPass::getAnalysisUsage(AU
);
92 AU
.addRequired
<MachineOptimizationRemarkEmitterPass
>();
95 bool runOnMachineFunction(MachineFunction
&MF
) override
{
96 // TODO: We should implement a similar filter for remarks:
97 // -Rpass-func-filter=<regex>
98 if (!isFunctionInPrintList(MF
.getName()))
101 LLVMContext
&Ctx
= MF
.getFunction().getContext();
102 if (!Ctx
.getDiagHandlerPtr()->isAnalysisRemarkEnabled(DEBUG_TYPE
))
105 MachineOptimizationRemarkAnalysis
Rem(DEBUG_TYPE
, "StackLayout",
106 MF
.getFunction().getSubprogram(),
108 Rem
<< ("\nFunction: " + MF
.getName()).str();
109 emitStackFrameLayoutRemarks(MF
, Rem
);
110 getAnalysis
<MachineOptimizationRemarkEmitterPass
>().getORE().emit(Rem
);
114 std::string
getTypeString(SlotType Ty
) {
116 case SlotType::Spill
:
118 case SlotType::StackProtector
:
120 case SlotType::Variable
:
123 llvm_unreachable("bad slot type for stack layout");
127 void emitStackSlotRemark(const MachineFunction
&MF
, const SlotData
&D
,
128 MachineOptimizationRemarkAnalysis
&Rem
) {
129 // To make it easy to understand the stack layout from the CLI, we want to
130 // print each slot like the following:
132 // Offset: [SP+8], Type: Spill, Align: 8, Size: 16
133 // foo @ /path/to/file.c:25
134 // bar @ /path/to/file.c:35
136 // Which prints the size, alignment, and offset from the SP at function
139 // But we also want the machine readable remarks data to be nicely
140 // organized. So we print some additional data as strings for the CLI
141 // output, but maintain more structured data for the YAML.
143 // For example we store the Offset in YAML as:
147 // But we print it to the CLI as
150 // Negative offsets will print a leading `-`, so only add `+`
152 formatv("\nOffset: [SP{0}", (D
.Offset
< 0) ? "" : "+").str();
153 Rem
<< Prefix
<< ore::NV("Offset", D
.Offset
)
154 << "], Type: " << ore::NV("Type", getTypeString(D
.SlotTy
))
155 << ", Align: " << ore::NV("Align", D
.Align
)
156 << ", Size: " << ore::NV("Size", D
.Size
);
159 void emitSourceLocRemark(const MachineFunction
&MF
, const DILocalVariable
*N
,
160 MachineOptimizationRemarkAnalysis
&Rem
) {
162 formatv("{0} @ {1}:{2}", N
->getName(), N
->getFilename(), N
->getLine())
164 Rem
<< "\n " << ore::NV("DataLoc", Loc
);
167 void emitStackFrameLayoutRemarks(MachineFunction
&MF
,
168 MachineOptimizationRemarkAnalysis
&Rem
) {
169 const MachineFrameInfo
&MFI
= MF
.getFrameInfo();
170 if (!MFI
.hasStackObjects())
173 // ValOffset is the offset to the local area from the SP at function entry.
174 // To display the true offset from SP, we need to subtract ValOffset from
175 // MFI's ObjectOffset.
176 const TargetFrameLowering
*FI
= MF
.getSubtarget().getFrameLowering();
177 const int ValOffset
= (FI
? FI
->getOffsetOfLocalArea() : 0);
179 LLVM_DEBUG(dbgs() << "getStackProtectorIndex =="
180 << MFI
.getStackProtectorIndex() << "\n");
182 std::vector
<SlotData
> SlotInfo
;
184 const unsigned int NumObj
= MFI
.getNumObjects();
185 SlotInfo
.reserve(NumObj
);
186 // initialize slot info
187 for (int Idx
= MFI
.getObjectIndexBegin(), EndIdx
= MFI
.getObjectIndexEnd();
188 Idx
!= EndIdx
; ++Idx
) {
189 if (MFI
.isDeadObjectIndex(Idx
))
191 SlotInfo
.emplace_back(MFI
, ValOffset
, Idx
);
194 // sort the ordering, to match the actual layout in memory
195 llvm::sort(SlotInfo
);
197 SlotDbgMap SlotMap
= genSlotDbgMapping(MF
);
199 for (const SlotData
&Info
: SlotInfo
) {
200 emitStackSlotRemark(MF
, Info
, Rem
);
201 for (const DILocalVariable
*N
: SlotMap
[Info
.Slot
])
202 emitSourceLocRemark(MF
, N
, Rem
);
206 // We need to generate a mapping of slots to the values that are stored to
207 // them. This information is lost by the time we need to print out the frame,
208 // so we reconstruct it here by walking the CFG, and generating the mapping.
209 SlotDbgMap
genSlotDbgMapping(MachineFunction
&MF
) {
210 SlotDbgMap SlotDebugMap
;
212 // add variables to the map
213 for (MachineFunction::VariableDbgInfo
&DI
:
214 MF
.getInStackSlotVariableDbgInfo())
215 SlotDebugMap
[DI
.getStackSlot()].insert(DI
.Var
);
217 // Then add all the spills that have debug data
218 for (MachineBasicBlock
&MBB
: MF
) {
219 for (MachineInstr
&MI
: MBB
) {
220 for (MachineMemOperand
*MO
: MI
.memoperands()) {
223 auto *FI
= dyn_cast_or_null
<FixedStackPseudoSourceValue
>(
224 MO
->getPseudoValue());
227 int FrameIdx
= FI
->getFrameIndex();
228 SmallVector
<MachineInstr
*> Dbg
;
229 MI
.collectDebugValues(Dbg
);
231 for (MachineInstr
*MI
: Dbg
)
232 SlotDebugMap
[FrameIdx
].insert(MI
->getDebugVariable());
241 char StackFrameLayoutAnalysisPass::ID
= 0;
244 char &llvm::StackFrameLayoutAnalysisPassID
= StackFrameLayoutAnalysisPass::ID
;
245 INITIALIZE_PASS(StackFrameLayoutAnalysisPass
, "stack-frame-layout",
246 "Stack Frame Layout", false, false)
249 /// Returns a newly-created StackFrameLayout pass.
250 MachineFunctionPass
*createStackFrameLayoutAnalysisPass() {
251 return new StackFrameLayoutAnalysisPass();