brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.0 KiB · 95a9c3f Raw
313 lines · cpp
1//===-- StackFrameLayoutAnalysisPass.cpp2//------------------------------------===//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-exception7//8//===----------------------------------------------------------------------===//9//10// StackFrameLayoutAnalysisPass implementation. Outputs information about the11// layout of the stack frame, using the remarks interface. On the CLI it prints12// a textual representation of the stack frame. When possible it prints the13// values that occupy a stack slot using any available debug information. Since14// output is remarks based, it is also available in a machine readable file15// format, such as YAML.16//17//===----------------------------------------------------------------------===//18 19#include "llvm/CodeGen/StackFrameLayoutAnalysisPass.h"20#include "llvm/ADT/SetVector.h"21#include "llvm/Analysis/OptimizationRemarkEmitter.h"22#include "llvm/CodeGen/MachineFrameInfo.h"23#include "llvm/CodeGen/MachineFunction.h"24#include "llvm/CodeGen/MachineFunctionPass.h"25#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"26#include "llvm/CodeGen/Passes.h"27#include "llvm/CodeGen/SlotIndexes.h"28#include "llvm/CodeGen/StackProtector.h"29#include "llvm/CodeGen/TargetFrameLowering.h"30#include "llvm/CodeGen/TargetSubtargetInfo.h"31#include "llvm/IR/DebugInfoMetadata.h"32#include "llvm/IR/PrintPasses.h"33#include "llvm/InitializePasses.h"34#include "llvm/Support/Debug.h"35#include "llvm/Support/FormatVariadic.h"36#include "llvm/Support/raw_ostream.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 a45/// MachineFunction.46///47struct StackFrameLayoutAnalysis {48  using SlotDbgMap = SmallDenseMap<int, SetVector<const DILocalVariable *>>;49  MachineOptimizationRemarkEmitter &ORE;50 51  StackFrameLayoutAnalysis(MachineOptimizationRemarkEmitter &ORE) : ORE(ORE) {}52 53  enum SlotType {54    Spill,          // a Spill slot55    Fixed,          // a Fixed slot (e.g. arguments passed on the stack)56    VariableSized,  // a variable sized object57    StackProtector, // Stack Protector slot58    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 type60  };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) {75      Scalable = MFI.hasScalableStackID(Idx);76      if (MFI.isSpillSlotObjectIndex(Idx))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() &&83               Idx == MFI.getStackProtectorIndex())84        SlotTy = SlotType::StackProtector;85      else86        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 displayed92    // correctly. Variable sized slots are sorted to the end of the list, as93    // offsets are currently incorrect for these but they reside at the end of94    // the stack frame. The Slot index is used to ensure deterministic order95    // 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>108    if (!isFunctionInPrintList(MF.getName()))109      return false;110 111    LLVMContext &Ctx = MF.getFunction().getContext();112    if (!Ctx.getDiagHandlerPtr()->isAnalysisRemarkEnabled(DEBUG_TYPE))113      return false;114 115    MachineOptimizationRemarkAnalysis Rem(DEBUG_TYPE, "StackLayout",116                                          MF.getFunction().getSubprogram(),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,142                           MachineOptimizationRemarkAnalysis &Rem) {143    // To make it easy to understand the stack layout from the CLI, we want to144    // print each slot like the following:145    //146    //   Offset: [SP+8], Type: Spill, Align: 8, Size: 16147    //       foo @ /path/to/file.c:25148    //       bar @ /path/to/file.c:35149    //150    // Which prints the size, alignment, and offset from the SP at function151    // entry.152    //153    // But we also want the machine readable remarks data to be nicely154    // organized. So we print some additional data as strings for the CLI155    // output, but maintain more structured data for the YAML.156    //157    // For example we store the Offset in YAML as:158    //    ...159    //    - Offset: -8160    //    - ScalableOffset: -16161    // Note: the ScalableOffset entries are added only for slots with non-zero162    // 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,186                           MachineOptimizationRemarkAnalysis &Rem) {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 193  StackOffset getStackOffset(const MachineFunction &MF,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,203                                   MachineOptimizationRemarkAnalysis &Rem) {204    const MachineFrameInfo &MFI = MF.getFrameInfo();205    if (!MFI.hasStackObjects())206      return;207 208    const TargetFrameLowering *FI = MF.getSubtarget().getFrameLowering();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 info218    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 memory226    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 to238  // 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 map244    for (MachineFunction::VariableDbgInfo &DI :245         MF.getInStackSlotVariableDbgInfo())246      SlotDebugMap[DI.getStackSlot()].insert(DI.Var);247 248    // Then add all the spills that have debug data249    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();259          SmallVector<MachineInstr *> Dbg;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();284    MachineFunctionPass::getAnalysisUsage(AU);285    AU.addRequired<MachineOptimizationRemarkEmitterPass>();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} // namespace296 297PreservedAnalyses298llvm::StackFrameLayoutAnalysisPass::run(MachineFunction &MF,299                                        MachineFunctionAnalysisManager &MFAM) {300  auto &ORE = MFAM.getResult<MachineOptimizationRemarkEmitterAnalysis>(MF);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 309/// Returns a newly-created StackFrameLayout pass.310MachineFunctionPass *llvm::createStackFrameLayoutAnalysisPass() {311  return new StackFrameLayoutAnalysisLegacy();312}313