StackFrameLayoutAnalysisPass.cpp 8.7 KB

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