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());
41}
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();
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 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
112/// Adds DILexicalBlockFileAttr for operations with CallSiteLoc and operations
113/// from different files than their containing function.
115 Location opLoc = op->getLoc();
116
117 if (auto callSiteLoc = dyn_cast<CallSiteLoc>(opLoc)) {
118 auto callerLoc = callSiteLoc.getCaller();
119 auto calleeLoc = callSiteLoc.getCallee();
120 LLVM::DIScopeAttr scopeAttr;
121 // We assemble the full inline stack so the parent of this loc must be a
122 // function
123 if (auto funcOp = op->getParentOfType<LLVM::LLVMFuncOp>()) {
124 if (auto funcOpLoc =
125 llvm::dyn_cast_if_present<FusedLoc>(funcOp.getLoc())) {
126 scopeAttr = cast<LLVM::DISubprogramAttr>(funcOpLoc.getMetadata());
127 op->setLoc(CallSiteLoc::get(getNestedLoc(op, scopeAttr, calleeLoc),
128 callerLoc));
129 }
130 }
131
132 return;
133 }
134
135 auto funcOp = op->getParentOfType<LLVM::LLVMFuncOp>();
136 if (!funcOp)
137 return;
138
139 FileLineColLoc opFileLoc = extractFileLoc(opLoc);
140 if (!opFileLoc)
141 return;
142
143 FileLineColLoc funcFileLoc = extractFileLoc(funcOp.getLoc());
144 if (!funcFileLoc)
145 return;
146
147 StringRef opFile = opFileLoc.getFilename().getValue();
148 StringRef funcFile = funcFileLoc.getFilename().getValue();
149
150 // Handle cross-file operations: add DILexicalBlockFileAttr when the
151 // operation's source file differs from its containing function.
152 if (opFile != funcFile) {
153 auto funcOpLoc = llvm::dyn_cast_if_present<FusedLoc>(funcOp.getLoc());
154 if (!funcOpLoc)
155 return;
156 auto scopeAttr = dyn_cast<LLVM::DISubprogramAttr>(funcOpLoc.getMetadata());
157 if (!scopeAttr)
158 return;
159
160 auto *context = op->getContext();
161 LLVM::DIFileAttr opFileAttr =
162 LLVM::DIFileAttr::get(context, llvm::sys::path::filename(opFile),
163 llvm::sys::path::parent_path(opFile));
164
165 LLVM::DILexicalBlockFileAttr lexicalBlockFileAttr =
166 LLVM::DILexicalBlockFileAttr::get(context, scopeAttr, opFileAttr, 0);
167
168 Location newLoc = FusedLoc::get(context, {opLoc}, lexicalBlockFileAttr);
169 op->setLoc(newLoc);
170 }
171}
172
173namespace {
174/// Add a debug info scope to LLVMFuncOp that are missing it.
175struct DIScopeForLLVMFuncOpPass
177 DIScopeForLLVMFuncOpPass> {
178 using Base::Base;
179
180 void runOnOperation() override {
181 ModuleOp module = getOperation();
182 Location loc = module.getLoc();
183
184 MLIRContext *context = &getContext();
185 if (!context->getLoadedDialect<LLVM::LLVMDialect>()) {
186 emitError(loc, "LLVM dialect is not loaded.");
187 return signalPassFailure();
188 }
189
190 // Find a DICompileUnitAttr attached to a parent (the module for example),
191 // otherwise create a default one.
192 LLVM::DICompileUnitAttr compileUnitAttr;
193 if (auto fusedCompileUnitAttr =
194 module->getLoc()
195 ->findInstanceOf<FusedLocWith<LLVM::DICompileUnitAttr>>()) {
196 compileUnitAttr = fusedCompileUnitAttr.getMetadata();
197 } else {
198 LLVM::DIFileAttr fileAttr;
199 if (FileLineColLoc fileLoc = extractFileLoc(loc)) {
200 StringRef inputFilePath = fileLoc.getFilename().getValue();
201 fileAttr = LLVM::DIFileAttr::get(
202 context, llvm::sys::path::filename(inputFilePath),
203 llvm::sys::path::parent_path(inputFilePath));
204 } else {
205 fileAttr = LLVM::DIFileAttr::get(context, "<unknown>", "");
206 }
207
208 compileUnitAttr = LLVM::DICompileUnitAttr::get(
209 DistinctAttr::create(UnitAttr::get(context)), llvm::dwarf::DW_LANG_C,
210 fileAttr, StringAttr::get(context, "MLIR"),
211 /*isOptimized=*/true, emissionKind);
212 }
213
214 module.walk<WalkOrder::PreOrder>([&](Operation *op) -> void {
215 if (auto funcOp = dyn_cast<LLVM::LLVMFuncOp>(op)) {
216 // Create subprograms for each function with the same distinct compile
217 // unit.
218 addScopeToFunction(funcOp, compileUnitAttr);
219 } else {
221 }
222 });
223 }
224};
225
226} // 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:226
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
MLIRContext * getContext()
Return the context this operation is associated with.
Definition Operation.h:216
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.