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