123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- //===-- StackFrameLayoutAnalysisPass.cpp
- //------------------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // StackFrameLayoutAnalysisPass implementation. Outputs information about the
- // layout of the stack frame, using the remarks interface. On the CLI it prints
- // a textual representation of the stack frame. When possible it prints the
- // values that occupy a stack slot using any available debug information. Since
- // output is remarks based, it is also available in a machine readable file
- // format, such as YAML.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/ADT/SetVector.h"
- #include "llvm/Analysis/OptimizationRemarkEmitter.h"
- #include "llvm/CodeGen/MachineFrameInfo.h"
- #include "llvm/CodeGen/MachineFunction.h"
- #include "llvm/CodeGen/MachineFunctionPass.h"
- #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
- #include "llvm/CodeGen/Passes.h"
- #include "llvm/CodeGen/SlotIndexes.h"
- #include "llvm/CodeGen/StackProtector.h"
- #include "llvm/CodeGen/TargetFrameLowering.h"
- #include "llvm/CodeGen/TargetSubtargetInfo.h"
- #include "llvm/IR/DebugInfoMetadata.h"
- #include "llvm/IR/PrintPasses.h"
- #include "llvm/InitializePasses.h"
- #include "llvm/Support/Debug.h"
- #include "llvm/Support/FormatVariadic.h"
- #include "llvm/Support/raw_ostream.h"
- #include <sstream>
- using namespace llvm;
- #define DEBUG_TYPE "stack-frame-layout"
- namespace {
- /// StackFrameLayoutAnalysisPass - This is a pass to dump the stack frame of a
- /// MachineFunction.
- ///
- struct StackFrameLayoutAnalysisPass : public MachineFunctionPass {
- using SlotDbgMap = SmallDenseMap<int, SetVector<const DILocalVariable *>>;
- static char ID;
- enum SlotType {
- Spill, // a Spill slot
- StackProtector, // Stack Protector slot
- Variable, // a slot used to store a local data (could be a tmp)
- Invalid // It's an error for a slot to have this type
- };
- struct SlotData {
- int Slot;
- int Size;
- int Align;
- int Offset;
- SlotType SlotTy;
- SlotData(const MachineFrameInfo &MFI, const int ValOffset, const int Idx)
- : Slot(Idx), Size(MFI.getObjectSize(Idx)),
- Align(MFI.getObjectAlign(Idx).value()),
- Offset(MFI.getObjectOffset(Idx) - ValOffset), SlotTy(Invalid) {
- if (MFI.isSpillSlotObjectIndex(Idx))
- SlotTy = SlotType::Spill;
- else if (Idx == MFI.getStackProtectorIndex())
- SlotTy = SlotType::StackProtector;
- else
- SlotTy = SlotType::Variable;
- }
- // we use this to sort in reverse order, so that the layout is displayed
- // correctly
- bool operator<(const SlotData &Rhs) const { return Offset > Rhs.Offset; }
- };
- StackFrameLayoutAnalysisPass() : MachineFunctionPass(ID) {}
- StringRef getPassName() const override {
- return "Stack Frame Layout Analysis";
- }
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.setPreservesAll();
- MachineFunctionPass::getAnalysisUsage(AU);
- AU.addRequired<MachineOptimizationRemarkEmitterPass>();
- }
- bool runOnMachineFunction(MachineFunction &MF) override {
- // TODO: We should implement a similar filter for remarks:
- // -Rpass-func-filter=<regex>
- if (!isFunctionInPrintList(MF.getName()))
- return false;
- LLVMContext &Ctx = MF.getFunction().getContext();
- if (!Ctx.getDiagHandlerPtr()->isAnalysisRemarkEnabled(DEBUG_TYPE))
- return false;
- MachineOptimizationRemarkAnalysis Rem(DEBUG_TYPE, "StackLayout",
- MF.getFunction().getSubprogram(),
- &MF.front());
- Rem << ("\nFunction: " + MF.getName()).str();
- emitStackFrameLayoutRemarks(MF, Rem);
- getAnalysis<MachineOptimizationRemarkEmitterPass>().getORE().emit(Rem);
- return false;
- }
- std::string getTypeString(SlotType Ty) {
- switch (Ty) {
- case SlotType::Spill:
- return "Spill";
- case SlotType::StackProtector:
- return "Protector";
- case SlotType::Variable:
- return "Variable";
- default:
- llvm_unreachable("bad slot type for stack layout");
- }
- }
- void emitStackSlotRemark(const MachineFunction &MF, const SlotData &D,
- MachineOptimizationRemarkAnalysis &Rem) {
- // To make it easy to understand the stack layout from the CLI, we want to
- // print each slot like the following:
- //
- // Offset: [SP+8], Type: Spill, Align: 8, Size: 16
- // foo @ /path/to/file.c:25
- // bar @ /path/to/file.c:35
- //
- // Which prints the size, alignment, and offset from the SP at function
- // entry.
- //
- // But we also want the machine readable remarks data to be nicely
- // organized. So we print some additional data as strings for the CLI
- // output, but maintain more structured data for the YAML.
- //
- // For example we store the Offset in YAML as:
- // ...
- // - Offset: -8
- //
- // But we print it to the CLI as
- // Offset: [SP-8]
- // Negative offsets will print a leading `-`, so only add `+`
- std::string Prefix =
- formatv("\nOffset: [SP{0}", (D.Offset < 0) ? "" : "+").str();
- Rem << Prefix << ore::NV("Offset", D.Offset)
- << "], Type: " << ore::NV("Type", getTypeString(D.SlotTy))
- << ", Align: " << ore::NV("Align", D.Align)
- << ", Size: " << ore::NV("Size", D.Size);
- }
- void emitSourceLocRemark(const MachineFunction &MF, const DILocalVariable *N,
- MachineOptimizationRemarkAnalysis &Rem) {
- std::string Loc =
- formatv("{0} @ {1}:{2}", N->getName(), N->getFilename(), N->getLine())
- .str();
- Rem << "\n " << ore::NV("DataLoc", Loc);
- }
- void emitStackFrameLayoutRemarks(MachineFunction &MF,
- MachineOptimizationRemarkAnalysis &Rem) {
- const MachineFrameInfo &MFI = MF.getFrameInfo();
- if (!MFI.hasStackObjects())
- return;
- // ValOffset is the offset to the local area from the SP at function entry.
- // To display the true offset from SP, we need to subtract ValOffset from
- // MFI's ObjectOffset.
- const TargetFrameLowering *FI = MF.getSubtarget().getFrameLowering();
- const int ValOffset = (FI ? FI->getOffsetOfLocalArea() : 0);
- LLVM_DEBUG(dbgs() << "getStackProtectorIndex =="
- << MFI.getStackProtectorIndex() << "\n");
- std::vector<SlotData> SlotInfo;
- const unsigned int NumObj = MFI.getNumObjects();
- SlotInfo.reserve(NumObj);
- // initialize slot info
- for (int Idx = MFI.getObjectIndexBegin(), EndIdx = MFI.getObjectIndexEnd();
- Idx != EndIdx; ++Idx) {
- if (MFI.isDeadObjectIndex(Idx))
- continue;
- SlotInfo.emplace_back(MFI, ValOffset, Idx);
- }
- // sort the ordering, to match the actual layout in memory
- llvm::sort(SlotInfo);
- SlotDbgMap SlotMap = genSlotDbgMapping(MF);
- for (const SlotData &Info : SlotInfo) {
- emitStackSlotRemark(MF, Info, Rem);
- for (const DILocalVariable *N : SlotMap[Info.Slot])
- emitSourceLocRemark(MF, N, Rem);
- }
- }
- // We need to generate a mapping of slots to the values that are stored to
- // them. This information is lost by the time we need to print out the frame,
- // so we reconstruct it here by walking the CFG, and generating the mapping.
- SlotDbgMap genSlotDbgMapping(MachineFunction &MF) {
- SlotDbgMap SlotDebugMap;
- // add variables to the map
- for (MachineFunction::VariableDbgInfo &DI : MF.getVariableDbgInfo())
- SlotDebugMap[DI.Slot].insert(DI.Var);
- // Then add all the spills that have debug data
- for (MachineBasicBlock &MBB : MF) {
- for (MachineInstr &MI : MBB) {
- for (MachineMemOperand *MO : MI.memoperands()) {
- if (!MO->isStore())
- continue;
- auto *FI = dyn_cast_or_null<FixedStackPseudoSourceValue>(
- MO->getPseudoValue());
- if (!FI)
- continue;
- int FrameIdx = FI->getFrameIndex();
- SmallVector<MachineInstr *> Dbg;
- MI.collectDebugValues(Dbg);
- for (MachineInstr *MI : Dbg)
- SlotDebugMap[FrameIdx].insert(MI->getDebugVariable());
- }
- }
- }
- return SlotDebugMap;
- }
- };
- char StackFrameLayoutAnalysisPass::ID = 0;
- } // namespace
- char &llvm::StackFrameLayoutAnalysisPassID = StackFrameLayoutAnalysisPass::ID;
- INITIALIZE_PASS(StackFrameLayoutAnalysisPass, "stack-frame-layout",
- "Stack Frame Layout", false, false)
- namespace llvm {
- /// Returns a newly-created StackFrameLayout pass.
- MachineFunctionPass *createStackFrameLayoutAnalysisPass() {
- return new StackFrameLayoutAnalysisPass();
- }
- } // namespace llvm
|