diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/CodeGen/StackFrameLayoutAnalysisPass.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/CodeGen/StackFrameLayoutAnalysisPass.cpp | 253 | 
1 files changed, 253 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/CodeGen/StackFrameLayoutAnalysisPass.cpp b/contrib/llvm-project/llvm/lib/CodeGen/StackFrameLayoutAnalysisPass.cpp new file mode 100644 index 000000000000..3a48dd5b0a03 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/CodeGen/StackFrameLayoutAnalysisPass.cpp @@ -0,0 +1,253 @@ +//===-- 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  | 
