MLIR 23.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
15namespace mlir {
16namespace LLVM {
17#define GEN_PASS_DEF_DISCOPEFORLLVMFUNCOPPASS
18#include "mlir/Dialect/LLVMIR/Transforms/Passes.h.inc"
19} // namespace LLVM
20} // namespace mlir
21
22using 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.
46static 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 |= 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.
95 Location calleeLoc) {
96 auto *context = op->getContext();
97 LLVM::DIFileAttr calleeFileAttr;
98 if (auto calleeFileLoc = extractFileLoc(calleeLoc)) {
99 auto calleeFileName = calleeFileLoc.getFilename();
100 calleeFileAttr = LLVM::DIFileAttr::get(
101 context, llvm::sys::path::filename(calleeFileName),
102 llvm::sys::path::parent_path(calleeFileName));
103 } else {
104 calleeFileAttr = LLVM::DIFileAttr::get(context, "<unknown>", "");
105 }
106 auto lexicalBlockFileAttr = LLVM::DILexicalBlockFileAttr::get(
107 context, scopeAttr, calleeFileAttr, /*discriminator=*/0);
108 Location loc = calleeLoc;
109 // Recurse if the callee location is again a call site.
110 if (auto callSiteLoc = dyn_cast<CallSiteLoc>(calleeLoc)) {
111 auto nestedLoc = callSiteLoc.getCallee();
112 loc = getNestedLoc(op, lexicalBlockFileAttr, nestedLoc);
113 }
114 return FusedLoc::get(context, {loc}, lexicalBlockFileAttr);
115}
116
117/// Adds DILexicalBlockFileAttr for operations with CallSiteLoc and operations
118/// from different files than their containing function.
120 Location opLoc = op->getLoc();
121
122 if (auto callSiteLoc = dyn_cast<CallSiteLoc>(opLoc)) {
123 auto callerLoc = callSiteLoc.getCaller();
124 auto calleeLoc = callSiteLoc.getCallee();
125 LLVM::DIScopeAttr scopeAttr;
126 // We assemble the full inline stack so the parent of this loc must be a
127 // function
128 if (auto funcOp = op->getParentOfType<LLVM::LLVMFuncOp>()) {
129 if (auto funcOpLoc =
130 llvm::dyn_cast_if_present<FusedLoc>(funcOp.getLoc())) {
131 scopeAttr = cast<LLVM::DISubprogramAttr>(funcOpLoc.getMetadata());
132 op->setLoc(CallSiteLoc::get(getNestedLoc(op, scopeAttr, calleeLoc),
133 callerLoc));
134 }
135 }
136
137 return;
138 }
139
140 auto funcOp = op->getParentOfType<LLVM::LLVMFuncOp>();
141 if (!funcOp)
142 return;
143
144 FileLineColLoc opFileLoc = extractFileLoc(opLoc);
145 if (!opFileLoc)
146 return;
147
148 FileLineColLoc funcFileLoc = extractFileLoc(funcOp.getLoc());
149 if (!funcFileLoc)
150 return;
151
152 StringRef opFile = opFileLoc.getFilename().getValue();
153 StringRef funcFile = funcFileLoc.getFilename().getValue();
154
155 // Handle cross-file operations: add DILexicalBlockFileAttr when the
156 // operation's source file differs from its containing function.
157 if (opFile != funcFile) {
158 auto funcOpLoc = llvm::dyn_cast_if_present<FusedLoc>(funcOp.getLoc());
159 if (!funcOpLoc)
160 return;
161 auto scopeAttr = dyn_cast<LLVM::DISubprogramAttr>(funcOpLoc.getMetadata());
162 if (!scopeAttr)
163 return;
164
165 auto *context = op->getContext();
166 LLVM::DIFileAttr opFileAttr =
167 LLVM::DIFileAttr::get(context, llvm::sys::path::filename(opFile),
168 llvm::sys::path::parent_path(opFile));
169
170 LLVM::DILexicalBlockFileAttr lexicalBlockFileAttr =
171 LLVM::DILexicalBlockFileAttr::get(context, scopeAttr, opFileAttr, 0);
172
173 Location newLoc = FusedLoc::get(context, {opLoc}, lexicalBlockFileAttr);
174 op->setLoc(newLoc);
175 }
176}
177
178namespace {
179/// Add a debug info scope to LLVMFuncOp that are missing it.
180struct DIScopeForLLVMFuncOpPass
181 : public LLVM::impl::DIScopeForLLVMFuncOpPassBase<
182 DIScopeForLLVMFuncOpPass> {
183 using Base::Base;
184
185 void runOnOperation() override {
186 ModuleOp module = getOperation();
187 Location loc = module.getLoc();
188
189 MLIRContext *context = &getContext();
190 if (!context->getLoadedDialect<LLVM::LLVMDialect>()) {
191 emitError(loc, "LLVM dialect is not loaded.");
192 return signalPassFailure();
193 }
194
195 // Find a DICompileUnitAttr attached to a parent (the module for example),
196 // otherwise create a default one.
197 LLVM::DICompileUnitAttr compileUnitAttr;
198 if (auto fusedCompileUnitAttr =
199 module->getLoc()
200 ->findInstanceOf<FusedLocWith<LLVM::DICompileUnitAttr>>()) {
201 compileUnitAttr = fusedCompileUnitAttr.getMetadata();
202 } else {
203 LLVM::DIFileAttr fileAttr;
204 if (FileLineColLoc fileLoc = extractFileLoc(loc)) {
205 StringRef inputFilePath = fileLoc.getFilename().getValue();
206 fileAttr = LLVM::DIFileAttr::get(
207 context, llvm::sys::path::filename(inputFilePath),
208 llvm::sys::path::parent_path(inputFilePath));
209 } else {
210 fileAttr = LLVM::DIFileAttr::get(context, "<unknown>", "");
211 }
212
213 compileUnitAttr = LLVM::DICompileUnitAttr::get(
214 DistinctAttr::create(UnitAttr::get(context)), llvm::dwarf::DW_LANG_C,
215 fileAttr, StringAttr::get(context, "MLIR"),
216 /*isOptimized=*/true, emissionKind);
217 }
218
219 module.walk<WalkOrder::PreOrder>([&](Operation *op) -> void {
220 if (auto funcOp = dyn_cast<LLVM::LLVMFuncOp>(op)) {
221 // Create subprograms for each function with the same distinct compile
222 // unit.
223 addScopeToFunction(funcOp, compileUnitAttr);
224 } else {
226 }
227 });
228 }
229};
230
231} // 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)
Adds DILexicalBlockFileAttr for operations with CallSiteLoc and operations from different files than ...
b getContext())
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
This class represents a LLVM attribute that describes a debug info scope.
Definition LLVMAttrs.h:38
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:244
Location getLoc()
The source location the operation was defined or derived from.
Definition Operation.h:241
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
Definition Operation.h:256
MLIRContext * getContext()
Return the context this operation is associated with.
Definition Operation.h:234
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.