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
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();
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;
53 MLIRContext *context = llvmFunc->getContext();
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);
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
128namespace {
129/// Add a debug info scope to LLVMFuncOp that are missing it.
130struct DIScopeForLLVMFuncOpPass
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)
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.