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