MLIR  22.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 "llvm/BinaryFormat/Dwarf.h"
13 #include "llvm/Support/Path.h"
14 
15 namespace mlir {
16 namespace LLVM {
17 #define GEN_PASS_DEF_DISCOPEFORLLVMFUNCOPPASS
18 #include "mlir/Dialect/LLVMIR/Transforms/Passes.h.inc"
19 } // namespace LLVM
20 } // namespace mlir
21 
22 using namespace mlir;
23 
24 /// Attempt to extract a filename for the given loc.
26  if (auto fileLoc = dyn_cast<FileLineColLoc>(loc))
27  return fileLoc;
28  if (auto nameLoc = dyn_cast<NameLoc>(loc))
29  return extractFileLoc(nameLoc.getChildLoc());
30  if (auto opaqueLoc = dyn_cast<OpaqueLoc>(loc))
31  return extractFileLoc(opaqueLoc.getFallbackLocation());
32  if (auto fusedLoc = dyn_cast<FusedLoc>(loc)) {
33  for (auto loc : fusedLoc.getLocations()) {
34  if (auto fileLoc = extractFileLoc(loc))
35  return fileLoc;
36  }
37  }
38  if (auto callerLoc = dyn_cast<CallSiteLoc>(loc))
39  return extractFileLoc(callerLoc.getCaller());
40  return FileLineColLoc();
41 }
42 
43 /// Creates a DISubprogramAttr with the provided compile unit and attaches it
44 /// to the function. Does nothing when the function already has an attached
45 /// subprogram.
46 static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc,
47  LLVM::DICompileUnitAttr compileUnitAttr) {
48 
49  Location loc = llvmFunc.getLoc();
51  return;
52 
53  MLIRContext *context = llvmFunc->getContext();
54 
55  // Filename and line associate to the function.
56  LLVM::DIFileAttr fileAttr;
57  int64_t line = 1;
58  if (FileLineColLoc fileLoc = extractFileLoc(loc)) {
59  line = fileLoc.getLine();
60  StringRef inputFilePath = fileLoc.getFilename().getValue();
61  fileAttr =
62  LLVM::DIFileAttr::get(context, llvm::sys::path::filename(inputFilePath),
63  llvm::sys::path::parent_path(inputFilePath));
64  } else {
65  fileAttr = compileUnitAttr
66  ? compileUnitAttr.getFile()
67  : LLVM::DIFileAttr::get(context, "<unknown>", "");
68  }
69  auto subroutineTypeAttr =
70  LLVM::DISubroutineTypeAttr::get(context, llvm::dwarf::DW_CC_normal, {});
71 
72  // Figure out debug information (`subprogramFlags` and `compileUnitAttr`) to
73  // attach to the function definition / declaration. External functions are
74  // declarations only and are defined in a different compile unit, so mark
75  // them appropriately in `subprogramFlags` and set an empty `compileUnitAttr`.
76  DistinctAttr id;
77  auto subprogramFlags = LLVM::DISubprogramFlags::Optimized;
78  if (!llvmFunc.isExternal()) {
79  id = DistinctAttr::create(UnitAttr::get(context));
80  subprogramFlags = subprogramFlags | LLVM::DISubprogramFlags::Definition;
81  } else {
82  compileUnitAttr = {};
83  }
84  auto funcNameAttr = llvmFunc.getNameAttr();
85  auto subprogramAttr = LLVM::DISubprogramAttr::get(
86  context, id, compileUnitAttr, fileAttr, funcNameAttr, funcNameAttr,
87  fileAttr,
88  /*line=*/line, /*scopeLine=*/line, subprogramFlags, subroutineTypeAttr,
89  /*retainedNodes=*/{}, /*annotations=*/{});
90  llvmFunc->setLoc(FusedLoc::get(context, {loc}, subprogramAttr));
91 }
92 
93 // Get a nested loc for inlined functions.
94 static Location getNestedLoc(Operation *op, LLVM::DIScopeAttr scopeAttr,
95  Location calleeLoc) {
96  auto calleeFileName = extractFileLoc(calleeLoc).getFilename();
97  auto *context = op->getContext();
98  LLVM::DIFileAttr calleeFileAttr =
99  LLVM::DIFileAttr::get(context, llvm::sys::path::filename(calleeFileName),
100  llvm::sys::path::parent_path(calleeFileName));
101  auto lexicalBlockFileAttr = LLVM::DILexicalBlockFileAttr::get(
102  context, scopeAttr, calleeFileAttr, /*discriminator=*/0);
103  Location loc = calleeLoc;
104  // Recurse if the callee location is again a call site.
105  if (auto callSiteLoc = dyn_cast<CallSiteLoc>(calleeLoc)) {
106  auto nestedLoc = callSiteLoc.getCallee();
107  loc = getNestedLoc(op, lexicalBlockFileAttr, nestedLoc);
108  }
109  return FusedLoc::get(context, {loc}, lexicalBlockFileAttr);
110 }
111 
113  if (auto callSiteLoc = dyn_cast<CallSiteLoc>(op->getLoc())) {
114  auto callerLoc = callSiteLoc.getCaller();
115  auto calleeLoc = callSiteLoc.getCallee();
116  LLVM::DIScopeAttr scopeAttr;
117  // We assemble the full inline stack so the parent of this loc must be a
118  // function
119  auto funcOp = op->getParentOfType<LLVM::LLVMFuncOp>();
120  if (auto funcOpLoc = llvm::dyn_cast_if_present<FusedLoc>(funcOp.getLoc())) {
121  scopeAttr = cast<LLVM::DISubprogramAttr>(funcOpLoc.getMetadata());
122  op->setLoc(
123  CallSiteLoc::get(getNestedLoc(op, scopeAttr, calleeLoc), callerLoc));
124  }
125  }
126 }
127 
128 namespace {
129 /// Add a debug info scope to LLVMFuncOp that are missing it.
130 struct DIScopeForLLVMFuncOpPass
131  : public LLVM::impl::DIScopeForLLVMFuncOpPassBase<
132  DIScopeForLLVMFuncOpPass> {
133  using Base::Base;
134 
135  void runOnOperation() override {
136  ModuleOp module = getOperation();
137  Location loc = module.getLoc();
138 
139  MLIRContext *context = &getContext();
140  if (!context->getLoadedDialect<LLVM::LLVMDialect>()) {
141  emitError(loc, "LLVM dialect is not loaded.");
142  return signalPassFailure();
143  }
144 
145  // Find a DICompileUnitAttr attached to a parent (the module for example),
146  // otherwise create a default one.
147  LLVM::DICompileUnitAttr compileUnitAttr;
148  if (auto fusedCompileUnitAttr =
149  module->getLoc()
150  ->findInstanceOf<FusedLocWith<LLVM::DICompileUnitAttr>>()) {
151  compileUnitAttr = fusedCompileUnitAttr.getMetadata();
152  } else {
153  LLVM::DIFileAttr fileAttr;
154  if (FileLineColLoc fileLoc = extractFileLoc(loc)) {
155  StringRef inputFilePath = fileLoc.getFilename().getValue();
156  fileAttr = LLVM::DIFileAttr::get(
157  context, llvm::sys::path::filename(inputFilePath),
158  llvm::sys::path::parent_path(inputFilePath));
159  } else {
160  fileAttr = LLVM::DIFileAttr::get(context, "<unknown>", "");
161  }
162 
163  compileUnitAttr = LLVM::DICompileUnitAttr::get(
164  DistinctAttr::create(UnitAttr::get(context)), llvm::dwarf::DW_LANG_C,
165  fileAttr, StringAttr::get(context, "MLIR"),
166  /*isOptimized=*/true, emissionKind);
167  }
168 
169  module.walk<WalkOrder::PreOrder>([&](Operation *op) -> void {
170  if (auto funcOp = dyn_cast<LLVM::LLVMFuncOp>(op)) {
171  // Create subprograms for each function with the same distinct compile
172  // unit.
173  addScopeToFunction(funcOp, compileUnitAttr);
174  } else {
176  }
177  });
178  }
179 };
180 
181 } // 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:169
This class represents a fused location whose metadata is known to be an instance of the given type.
Definition: Location.h:149
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:63
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...