MLIR  21.0.0git
DIScopeForLLVMFuncOp.cpp
Go to the documentation of this file.
1 //===- DILineTableFromLocations.cpp - -------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 
12 #include "mlir/Pass/Pass.h"
13 #include "llvm/BinaryFormat/Dwarf.h"
14 #include "llvm/Support/Debug.h"
15 #include "llvm/Support/Path.h"
16 
17 namespace mlir {
18 namespace LLVM {
19 #define GEN_PASS_DEF_DISCOPEFORLLVMFUNCOPPASS
20 #include "mlir/Dialect/LLVMIR/Transforms/Passes.h.inc"
21 } // namespace LLVM
22 } // namespace mlir
23 
24 using namespace mlir;
25 
26 /// Attempt to extract a filename for the given loc.
28  if (auto fileLoc = dyn_cast<FileLineColLoc>(loc))
29  return fileLoc;
30  if (auto nameLoc = dyn_cast<NameLoc>(loc))
31  return extractFileLoc(nameLoc.getChildLoc());
32  if (auto opaqueLoc = dyn_cast<OpaqueLoc>(loc))
33  return extractFileLoc(opaqueLoc.getFallbackLocation());
34  if (auto fusedLoc = dyn_cast<FusedLoc>(loc)) {
35  for (auto loc : fusedLoc.getLocations()) {
36  if (auto fileLoc = extractFileLoc(loc))
37  return fileLoc;
38  }
39  }
40  if (auto callerLoc = dyn_cast<CallSiteLoc>(loc))
41  return extractFileLoc(callerLoc.getCaller());
42  return FileLineColLoc();
43 }
44 
45 /// Creates a DISubprogramAttr with the provided compile unit and attaches it
46 /// to the function. Does nothing when the function already has an attached
47 /// subprogram.
48 static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc,
49  LLVM::DICompileUnitAttr compileUnitAttr) {
50 
51  Location loc = llvmFunc.getLoc();
53  return;
54 
55  MLIRContext *context = llvmFunc->getContext();
56 
57  // Filename and line associate to the function.
58  LLVM::DIFileAttr fileAttr;
59  int64_t line = 1;
60  if (FileLineColLoc fileLoc = extractFileLoc(loc)) {
61  line = fileLoc.getLine();
62  StringRef inputFilePath = fileLoc.getFilename().getValue();
63  fileAttr =
64  LLVM::DIFileAttr::get(context, llvm::sys::path::filename(inputFilePath),
65  llvm::sys::path::parent_path(inputFilePath));
66  } else {
67  fileAttr = compileUnitAttr
68  ? compileUnitAttr.getFile()
69  : LLVM::DIFileAttr::get(context, "<unknown>", "");
70  }
71  auto subroutineTypeAttr =
72  LLVM::DISubroutineTypeAttr::get(context, llvm::dwarf::DW_CC_normal, {});
73 
74  // Figure out debug information (`subprogramFlags` and `compileUnitAttr`) to
75  // attach to the function definition / declaration. External functions are
76  // declarations only and are defined in a different compile unit, so mark
77  // them appropriately in `subprogramFlags` and set an empty `compileUnitAttr`.
78  DistinctAttr id;
79  auto subprogramFlags = LLVM::DISubprogramFlags::Optimized;
80  if (!llvmFunc.isExternal()) {
81  id = DistinctAttr::create(UnitAttr::get(context));
82  subprogramFlags = subprogramFlags | LLVM::DISubprogramFlags::Definition;
83  } else {
84  compileUnitAttr = {};
85  }
86  auto funcNameAttr = llvmFunc.getNameAttr();
87  auto subprogramAttr = LLVM::DISubprogramAttr::get(
88  context, id, compileUnitAttr, fileAttr, funcNameAttr, funcNameAttr,
89  fileAttr,
90  /*line=*/line, /*scopeLine=*/line, subprogramFlags, subroutineTypeAttr,
91  /*retainedNodes=*/{}, /*annotations=*/{});
92  llvmFunc->setLoc(FusedLoc::get(context, {loc}, subprogramAttr));
93 }
94 
95 // Get a nested loc for inlined functions.
97  Location calleeLoc) {
98  auto calleeFileName = extractFileLoc(calleeLoc).getFilename();
99  auto *context = op->getContext();
100  LLVM::DIFileAttr calleeFileAttr =
101  LLVM::DIFileAttr::get(context, llvm::sys::path::filename(calleeFileName),
102  llvm::sys::path::parent_path(calleeFileName));
103  auto lexicalBlockFileAttr = LLVM::DILexicalBlockFileAttr::get(
104  context, scopeAttr, calleeFileAttr, /*discriminator=*/0);
105  Location loc = calleeLoc;
106  // Recurse if the callee location is again a call site.
107  if (auto callSiteLoc = dyn_cast<CallSiteLoc>(calleeLoc)) {
108  auto nestedLoc = callSiteLoc.getCallee();
109  loc = getNestedLoc(op, lexicalBlockFileAttr, nestedLoc);
110  }
111  return FusedLoc::get(context, {loc}, lexicalBlockFileAttr);
112 }
113 
115  if (auto callSiteLoc = dyn_cast<CallSiteLoc>(op->getLoc())) {
116  auto callerLoc = callSiteLoc.getCaller();
117  auto calleeLoc = callSiteLoc.getCallee();
118  LLVM::DIScopeAttr scopeAttr;
119  // We assemble the full inline stack so the parent of this loc must be a
120  // function
121  auto funcOp = op->getParentOfType<LLVM::LLVMFuncOp>();
122  if (auto funcOpLoc = llvm::dyn_cast_if_present<FusedLoc>(funcOp.getLoc())) {
123  scopeAttr = cast<LLVM::DISubprogramAttr>(funcOpLoc.getMetadata());
124  op->setLoc(
125  CallSiteLoc::get(getNestedLoc(op, scopeAttr, calleeLoc), callerLoc));
126  }
127  }
128 }
129 
130 namespace {
131 /// Add a debug info scope to LLVMFuncOp that are missing it.
132 struct DIScopeForLLVMFuncOpPass
133  : public LLVM::impl::DIScopeForLLVMFuncOpPassBase<
134  DIScopeForLLVMFuncOpPass> {
135  using Base::Base;
136 
137  void runOnOperation() override {
138  ModuleOp module = getOperation();
139  Location loc = module.getLoc();
140 
141  MLIRContext *context = &getContext();
142  if (!context->getLoadedDialect<LLVM::LLVMDialect>()) {
143  emitError(loc, "LLVM dialect is not loaded.");
144  return signalPassFailure();
145  }
146 
147  // Find a DICompileUnitAttr attached to a parent (the module for example),
148  // otherwise create a default one.
149  LLVM::DICompileUnitAttr compileUnitAttr;
150  if (auto fusedCompileUnitAttr =
151  module->getLoc()
152  ->findInstanceOf<FusedLocWith<LLVM::DICompileUnitAttr>>()) {
153  compileUnitAttr = fusedCompileUnitAttr.getMetadata();
154  } else {
155  LLVM::DIFileAttr fileAttr;
156  if (FileLineColLoc fileLoc = extractFileLoc(loc)) {
157  StringRef inputFilePath = fileLoc.getFilename().getValue();
158  fileAttr = LLVM::DIFileAttr::get(
159  context, llvm::sys::path::filename(inputFilePath),
160  llvm::sys::path::parent_path(inputFilePath));
161  } else {
162  fileAttr = LLVM::DIFileAttr::get(context, "<unknown>", "");
163  }
164 
165  compileUnitAttr = LLVM::DICompileUnitAttr::get(
166  DistinctAttr::create(UnitAttr::get(context)), llvm::dwarf::DW_LANG_C,
167  fileAttr, StringAttr::get(context, "MLIR"),
168  /*isOptimized=*/true, emissionKind);
169  }
170 
171  module.walk<WalkOrder::PreOrder>([&](Operation *op) -> void {
172  if (auto funcOp = dyn_cast<LLVM::LLVMFuncOp>(op)) {
173  // Create subprograms for each function with the same distinct compile
174  // unit.
175  addScopeToFunction(funcOp, compileUnitAttr);
176  } else {
178  }
179  });
180  }
181 };
182 
183 } // end anonymous namespace
static Location getNestedLoc(Operation *op, LLVM::DIScopeAttr scopeAttr, Location calleeLoc)
static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc, LLVM::DICompileUnitAttr compileUnitAttr)
Creates a DISubprogramAttr with the provided compile unit and attaches it to the function.
static FileLineColLoc extractFileLoc(Location loc)
Attempt to extract a filename for the given loc.
static void setLexicalBlockFileAttr(Operation *op)
static MLIRContext * getContext(OpFoldResult val)
An attribute that associates a referenced attribute with a unique identifier.
static DistinctAttr create(Attribute referencedAttr)
Creates a distinct attribute that associates a referenced attribute with a unique identifier.
An instance of this location represents a tuple of file, line number, and column number.
Definition: Location.h:174
StringAttr getFilename() const
Definition: Location.cpp:173
This class represents a fused location whose metadata is known to be an instance of the given type.
Definition: Location.h:149
This class represents a LLVM attribute that describes a debug info scope.
Definition: LLVMAttrs.h:36
T findInstanceOf()
Return an instance of the given location type if one is nested under the current location.
Definition: Location.h:45
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:76
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
void setLoc(Location loc)
Set the source location the operation was defined or derived from.
Definition: Operation.h:226
MLIRContext * getContext()
Return the context this operation is associated with.
Definition: Operation.h:216
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:223
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
Definition: Operation.h:238
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...