1*bdd1243dSDimitry Andric //===-- StackFrameLayoutAnalysisPass.cpp 2*bdd1243dSDimitry Andric //------------------------------------===// 3*bdd1243dSDimitry Andric // 4*bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5*bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 6*bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7*bdd1243dSDimitry Andric // 8*bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 9*bdd1243dSDimitry Andric // 10*bdd1243dSDimitry Andric // StackFrameLayoutAnalysisPass implementation. Outputs information about the 11*bdd1243dSDimitry Andric // layout of the stack frame, using the remarks interface. On the CLI it prints 12*bdd1243dSDimitry Andric // a textual representation of the stack frame. When possible it prints the 13*bdd1243dSDimitry Andric // values that occupy a stack slot using any available debug information. Since 14*bdd1243dSDimitry Andric // output is remarks based, it is also available in a machine readable file 15*bdd1243dSDimitry Andric // format, such as YAML. 16*bdd1243dSDimitry Andric // 17*bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 18*bdd1243dSDimitry Andric 19*bdd1243dSDimitry Andric #include "llvm/ADT/SetVector.h" 20*bdd1243dSDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h" 21*bdd1243dSDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 22*bdd1243dSDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 23*bdd1243dSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 24*bdd1243dSDimitry Andric #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" 25*bdd1243dSDimitry Andric #include "llvm/CodeGen/Passes.h" 26*bdd1243dSDimitry Andric #include "llvm/CodeGen/SlotIndexes.h" 27*bdd1243dSDimitry Andric #include "llvm/CodeGen/StackProtector.h" 28*bdd1243dSDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h" 29*bdd1243dSDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 30*bdd1243dSDimitry Andric #include "llvm/IR/DebugInfoMetadata.h" 31*bdd1243dSDimitry Andric #include "llvm/IR/PrintPasses.h" 32*bdd1243dSDimitry Andric #include "llvm/InitializePasses.h" 33*bdd1243dSDimitry Andric #include "llvm/Support/Debug.h" 34*bdd1243dSDimitry Andric #include "llvm/Support/FormatVariadic.h" 35*bdd1243dSDimitry Andric #include "llvm/Support/raw_ostream.h" 36*bdd1243dSDimitry Andric 37*bdd1243dSDimitry Andric #include <sstream> 38*bdd1243dSDimitry Andric 39*bdd1243dSDimitry Andric using namespace llvm; 40*bdd1243dSDimitry Andric 41*bdd1243dSDimitry Andric #define DEBUG_TYPE "stack-frame-layout" 42*bdd1243dSDimitry Andric 43*bdd1243dSDimitry Andric namespace { 44*bdd1243dSDimitry Andric 45*bdd1243dSDimitry Andric /// StackFrameLayoutAnalysisPass - This is a pass to dump the stack frame of a 46*bdd1243dSDimitry Andric /// MachineFunction. 47*bdd1243dSDimitry Andric /// 48*bdd1243dSDimitry Andric struct StackFrameLayoutAnalysisPass : public MachineFunctionPass { 49*bdd1243dSDimitry Andric using SlotDbgMap = SmallDenseMap<int, SetVector<const DILocalVariable *>>; 50*bdd1243dSDimitry Andric static char ID; 51*bdd1243dSDimitry Andric 52*bdd1243dSDimitry Andric enum SlotType { 53*bdd1243dSDimitry Andric Spill, // a Spill slot 54*bdd1243dSDimitry Andric StackProtector, // Stack Protector slot 55*bdd1243dSDimitry Andric Variable, // a slot used to store a local data (could be a tmp) 56*bdd1243dSDimitry Andric Invalid // It's an error for a slot to have this type 57*bdd1243dSDimitry Andric }; 58*bdd1243dSDimitry Andric 59*bdd1243dSDimitry Andric struct SlotData { 60*bdd1243dSDimitry Andric int Slot; 61*bdd1243dSDimitry Andric int Size; 62*bdd1243dSDimitry Andric int Align; 63*bdd1243dSDimitry Andric int Offset; 64*bdd1243dSDimitry Andric SlotType SlotTy; 65*bdd1243dSDimitry Andric 66*bdd1243dSDimitry Andric SlotData(const MachineFrameInfo &MFI, const int ValOffset, const int Idx) 67*bdd1243dSDimitry Andric : Slot(Idx), Size(MFI.getObjectSize(Idx)), 68*bdd1243dSDimitry Andric Align(MFI.getObjectAlign(Idx).value()), 69*bdd1243dSDimitry Andric Offset(MFI.getObjectOffset(Idx) - ValOffset), SlotTy(Invalid) { 70*bdd1243dSDimitry Andric if (MFI.isSpillSlotObjectIndex(Idx)) 71*bdd1243dSDimitry Andric SlotTy = SlotType::Spill; 72*bdd1243dSDimitry Andric else if (Idx == MFI.getStackProtectorIndex()) 73*bdd1243dSDimitry Andric SlotTy = SlotType::StackProtector; 74*bdd1243dSDimitry Andric else 75*bdd1243dSDimitry Andric SlotTy = SlotType::Variable; 76*bdd1243dSDimitry Andric } 77*bdd1243dSDimitry Andric 78*bdd1243dSDimitry Andric // we use this to sort in reverse order, so that the layout is displayed 79*bdd1243dSDimitry Andric // correctly 80*bdd1243dSDimitry Andric bool operator<(const SlotData &Rhs) const { return Offset > Rhs.Offset; } 81*bdd1243dSDimitry Andric }; 82*bdd1243dSDimitry Andric 83*bdd1243dSDimitry Andric StackFrameLayoutAnalysisPass() : MachineFunctionPass(ID) {} 84*bdd1243dSDimitry Andric 85*bdd1243dSDimitry Andric StringRef getPassName() const override { 86*bdd1243dSDimitry Andric return "Stack Frame Layout Analysis"; 87*bdd1243dSDimitry Andric } 88*bdd1243dSDimitry Andric 89*bdd1243dSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 90*bdd1243dSDimitry Andric AU.setPreservesAll(); 91*bdd1243dSDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 92*bdd1243dSDimitry Andric AU.addRequired<MachineOptimizationRemarkEmitterPass>(); 93*bdd1243dSDimitry Andric } 94*bdd1243dSDimitry Andric 95*bdd1243dSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 96*bdd1243dSDimitry Andric // TODO: We should implement a similar filter for remarks: 97*bdd1243dSDimitry Andric // -Rpass-func-filter=<regex> 98*bdd1243dSDimitry Andric if (!isFunctionInPrintList(MF.getName())) 99*bdd1243dSDimitry Andric return false; 100*bdd1243dSDimitry Andric 101*bdd1243dSDimitry Andric LLVMContext &Ctx = MF.getFunction().getContext(); 102*bdd1243dSDimitry Andric if (!Ctx.getDiagHandlerPtr()->isAnalysisRemarkEnabled(DEBUG_TYPE)) 103*bdd1243dSDimitry Andric return false; 104*bdd1243dSDimitry Andric 105*bdd1243dSDimitry Andric MachineOptimizationRemarkAnalysis Rem(DEBUG_TYPE, "StackLayout", 106*bdd1243dSDimitry Andric MF.getFunction().getSubprogram(), 107*bdd1243dSDimitry Andric &MF.front()); 108*bdd1243dSDimitry Andric Rem << ("\nFunction: " + MF.getName()).str(); 109*bdd1243dSDimitry Andric emitStackFrameLayoutRemarks(MF, Rem); 110*bdd1243dSDimitry Andric getAnalysis<MachineOptimizationRemarkEmitterPass>().getORE().emit(Rem); 111*bdd1243dSDimitry Andric return false; 112*bdd1243dSDimitry Andric } 113*bdd1243dSDimitry Andric 114*bdd1243dSDimitry Andric std::string getTypeString(SlotType Ty) { 115*bdd1243dSDimitry Andric switch (Ty) { 116*bdd1243dSDimitry Andric case SlotType::Spill: 117*bdd1243dSDimitry Andric return "Spill"; 118*bdd1243dSDimitry Andric case SlotType::StackProtector: 119*bdd1243dSDimitry Andric return "Protector"; 120*bdd1243dSDimitry Andric case SlotType::Variable: 121*bdd1243dSDimitry Andric return "Variable"; 122*bdd1243dSDimitry Andric default: 123*bdd1243dSDimitry Andric llvm_unreachable("bad slot type for stack layout"); 124*bdd1243dSDimitry Andric } 125*bdd1243dSDimitry Andric } 126*bdd1243dSDimitry Andric 127*bdd1243dSDimitry Andric void emitStackSlotRemark(const MachineFunction &MF, const SlotData &D, 128*bdd1243dSDimitry Andric MachineOptimizationRemarkAnalysis &Rem) { 129*bdd1243dSDimitry Andric // To make it easy to understand the stack layout from the CLI, we want to 130*bdd1243dSDimitry Andric // print each slot like the following: 131*bdd1243dSDimitry Andric // 132*bdd1243dSDimitry Andric // Offset: [SP+8], Type: Spill, Align: 8, Size: 16 133*bdd1243dSDimitry Andric // foo @ /path/to/file.c:25 134*bdd1243dSDimitry Andric // bar @ /path/to/file.c:35 135*bdd1243dSDimitry Andric // 136*bdd1243dSDimitry Andric // Which prints the size, alignment, and offset from the SP at function 137*bdd1243dSDimitry Andric // entry. 138*bdd1243dSDimitry Andric // 139*bdd1243dSDimitry Andric // But we also want the machine readable remarks data to be nicely 140*bdd1243dSDimitry Andric // organized. So we print some additional data as strings for the CLI 141*bdd1243dSDimitry Andric // output, but maintain more structured data for the YAML. 142*bdd1243dSDimitry Andric // 143*bdd1243dSDimitry Andric // For example we store the Offset in YAML as: 144*bdd1243dSDimitry Andric // ... 145*bdd1243dSDimitry Andric // - Offset: -8 146*bdd1243dSDimitry Andric // 147*bdd1243dSDimitry Andric // But we print it to the CLI as 148*bdd1243dSDimitry Andric // Offset: [SP-8] 149*bdd1243dSDimitry Andric 150*bdd1243dSDimitry Andric // Negative offsets will print a leading `-`, so only add `+` 151*bdd1243dSDimitry Andric std::string Prefix = 152*bdd1243dSDimitry Andric formatv("\nOffset: [SP{0}", (D.Offset < 0) ? "" : "+").str(); 153*bdd1243dSDimitry Andric Rem << Prefix << ore::NV("Offset", D.Offset) 154*bdd1243dSDimitry Andric << "], Type: " << ore::NV("Type", getTypeString(D.SlotTy)) 155*bdd1243dSDimitry Andric << ", Align: " << ore::NV("Align", D.Align) 156*bdd1243dSDimitry Andric << ", Size: " << ore::NV("Size", D.Size); 157*bdd1243dSDimitry Andric } 158*bdd1243dSDimitry Andric 159*bdd1243dSDimitry Andric void emitSourceLocRemark(const MachineFunction &MF, const DILocalVariable *N, 160*bdd1243dSDimitry Andric MachineOptimizationRemarkAnalysis &Rem) { 161*bdd1243dSDimitry Andric std::string Loc = 162*bdd1243dSDimitry Andric formatv("{0} @ {1}:{2}", N->getName(), N->getFilename(), N->getLine()) 163*bdd1243dSDimitry Andric .str(); 164*bdd1243dSDimitry Andric Rem << "\n " << ore::NV("DataLoc", Loc); 165*bdd1243dSDimitry Andric } 166*bdd1243dSDimitry Andric 167*bdd1243dSDimitry Andric void emitStackFrameLayoutRemarks(MachineFunction &MF, 168*bdd1243dSDimitry Andric MachineOptimizationRemarkAnalysis &Rem) { 169*bdd1243dSDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 170*bdd1243dSDimitry Andric if (!MFI.hasStackObjects()) 171*bdd1243dSDimitry Andric return; 172*bdd1243dSDimitry Andric 173*bdd1243dSDimitry Andric // ValOffset is the offset to the local area from the SP at function entry. 174*bdd1243dSDimitry Andric // To display the true offset from SP, we need to subtract ValOffset from 175*bdd1243dSDimitry Andric // MFI's ObjectOffset. 176*bdd1243dSDimitry Andric const TargetFrameLowering *FI = MF.getSubtarget().getFrameLowering(); 177*bdd1243dSDimitry Andric const int ValOffset = (FI ? FI->getOffsetOfLocalArea() : 0); 178*bdd1243dSDimitry Andric 179*bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "getStackProtectorIndex ==" 180*bdd1243dSDimitry Andric << MFI.getStackProtectorIndex() << "\n"); 181*bdd1243dSDimitry Andric 182*bdd1243dSDimitry Andric std::vector<SlotData> SlotInfo; 183*bdd1243dSDimitry Andric 184*bdd1243dSDimitry Andric const unsigned int NumObj = MFI.getNumObjects(); 185*bdd1243dSDimitry Andric SlotInfo.reserve(NumObj); 186*bdd1243dSDimitry Andric // initialize slot info 187*bdd1243dSDimitry Andric for (int Idx = MFI.getObjectIndexBegin(), EndIdx = MFI.getObjectIndexEnd(); 188*bdd1243dSDimitry Andric Idx != EndIdx; ++Idx) { 189*bdd1243dSDimitry Andric if (MFI.isDeadObjectIndex(Idx)) 190*bdd1243dSDimitry Andric continue; 191*bdd1243dSDimitry Andric SlotInfo.emplace_back(MFI, ValOffset, Idx); 192*bdd1243dSDimitry Andric } 193*bdd1243dSDimitry Andric 194*bdd1243dSDimitry Andric // sort the ordering, to match the actual layout in memory 195*bdd1243dSDimitry Andric llvm::sort(SlotInfo); 196*bdd1243dSDimitry Andric 197*bdd1243dSDimitry Andric SlotDbgMap SlotMap = genSlotDbgMapping(MF); 198*bdd1243dSDimitry Andric 199*bdd1243dSDimitry Andric for (const SlotData &Info : SlotInfo) { 200*bdd1243dSDimitry Andric emitStackSlotRemark(MF, Info, Rem); 201*bdd1243dSDimitry Andric for (const DILocalVariable *N : SlotMap[Info.Slot]) 202*bdd1243dSDimitry Andric emitSourceLocRemark(MF, N, Rem); 203*bdd1243dSDimitry Andric } 204*bdd1243dSDimitry Andric } 205*bdd1243dSDimitry Andric 206*bdd1243dSDimitry Andric // We need to generate a mapping of slots to the values that are stored to 207*bdd1243dSDimitry Andric // them. This information is lost by the time we need to print out the frame, 208*bdd1243dSDimitry Andric // so we reconstruct it here by walking the CFG, and generating the mapping. 209*bdd1243dSDimitry Andric SlotDbgMap genSlotDbgMapping(MachineFunction &MF) { 210*bdd1243dSDimitry Andric SlotDbgMap SlotDebugMap; 211*bdd1243dSDimitry Andric 212*bdd1243dSDimitry Andric // add variables to the map 213*bdd1243dSDimitry Andric for (MachineFunction::VariableDbgInfo &DI : MF.getVariableDbgInfo()) 214*bdd1243dSDimitry Andric SlotDebugMap[DI.Slot].insert(DI.Var); 215*bdd1243dSDimitry Andric 216*bdd1243dSDimitry Andric // Then add all the spills that have debug data 217*bdd1243dSDimitry Andric for (MachineBasicBlock &MBB : MF) { 218*bdd1243dSDimitry Andric for (MachineInstr &MI : MBB) { 219*bdd1243dSDimitry Andric for (MachineMemOperand *MO : MI.memoperands()) { 220*bdd1243dSDimitry Andric if (!MO->isStore()) 221*bdd1243dSDimitry Andric continue; 222*bdd1243dSDimitry Andric auto *FI = dyn_cast_or_null<FixedStackPseudoSourceValue>( 223*bdd1243dSDimitry Andric MO->getPseudoValue()); 224*bdd1243dSDimitry Andric if (!FI) 225*bdd1243dSDimitry Andric continue; 226*bdd1243dSDimitry Andric int FrameIdx = FI->getFrameIndex(); 227*bdd1243dSDimitry Andric SmallVector<MachineInstr *> Dbg; 228*bdd1243dSDimitry Andric MI.collectDebugValues(Dbg); 229*bdd1243dSDimitry Andric 230*bdd1243dSDimitry Andric for (MachineInstr *MI : Dbg) 231*bdd1243dSDimitry Andric SlotDebugMap[FrameIdx].insert(MI->getDebugVariable()); 232*bdd1243dSDimitry Andric } 233*bdd1243dSDimitry Andric } 234*bdd1243dSDimitry Andric } 235*bdd1243dSDimitry Andric 236*bdd1243dSDimitry Andric return SlotDebugMap; 237*bdd1243dSDimitry Andric } 238*bdd1243dSDimitry Andric }; 239*bdd1243dSDimitry Andric 240*bdd1243dSDimitry Andric char StackFrameLayoutAnalysisPass::ID = 0; 241*bdd1243dSDimitry Andric } // namespace 242*bdd1243dSDimitry Andric 243*bdd1243dSDimitry Andric char &llvm::StackFrameLayoutAnalysisPassID = StackFrameLayoutAnalysisPass::ID; 244*bdd1243dSDimitry Andric INITIALIZE_PASS(StackFrameLayoutAnalysisPass, "stack-frame-layout", 245*bdd1243dSDimitry Andric "Stack Frame Layout", false, false) 246*bdd1243dSDimitry Andric 247*bdd1243dSDimitry Andric namespace llvm { 248*bdd1243dSDimitry Andric /// Returns a newly-created StackFrameLayout pass. 249*bdd1243dSDimitry Andric MachineFunctionPass *createStackFrameLayoutAnalysisPass() { 250*bdd1243dSDimitry Andric return new StackFrameLayoutAnalysisPass(); 251*bdd1243dSDimitry Andric } 252*bdd1243dSDimitry Andric 253*bdd1243dSDimitry Andric } // namespace llvm 254