35
35
#include " llvm/Support/FileSystem.h"
36
36
#include " llvm/Support/Path.h"
37
37
#include " llvm/Support/raw_ostream.h"
38
+ #include < map>
38
39
39
40
namespace fir {
40
41
#define GEN_PASS_DEF_ADDDEBUGINFO
@@ -54,6 +55,16 @@ class AddDebugInfoPass : public fir::impl::AddDebugInfoBase<AddDebugInfoPass> {
54
55
public:
55
56
AddDebugInfoPass (fir::AddDebugInfoOptions options) : Base(options) {}
56
57
void runOnOperation () override ;
58
+
59
+ private:
60
+ std::map<std::string, mlir::LLVM::DIModuleAttr> moduleMap;
61
+
62
+ mlir::LLVM::DIModuleAttr getOrCreateModuleAttr (
63
+ const std::string &name, mlir::LLVM::DIFileAttr fileAttr,
64
+ mlir::LLVM::DIScopeAttr scope, unsigned line, bool decl);
65
+
66
+ void handleGlobalOp (fir::GlobalOp glocalOp, mlir::LLVM::DIFileAttr fileAttr,
67
+ mlir::LLVM::DIScopeAttr scope);
57
68
};
58
69
59
70
static uint32_t getLineFromLoc (mlir::Location loc) {
@@ -99,6 +110,66 @@ void AddDebugInfoPass::handleDeclareOp(fir::cg::XDeclareOp declOp,
99
110
declOp->setLoc (builder.getFusedLoc ({declOp->getLoc ()}, localVarAttr));
100
111
}
101
112
113
+ // The `module` does not have a first class representation in the `FIR`. We
114
+ // extract information about it from the name of the identifiers and keep a
115
+ // map to avoid duplication.
116
+ mlir::LLVM::DIModuleAttr AddDebugInfoPass::getOrCreateModuleAttr (
117
+ const std::string &name, mlir::LLVM::DIFileAttr fileAttr,
118
+ mlir::LLVM::DIScopeAttr scope, unsigned line, bool decl) {
119
+ mlir::MLIRContext *context = &getContext ();
120
+ mlir::LLVM::DIModuleAttr modAttr;
121
+ if (auto iter{moduleMap.find (name)}; iter != moduleMap.end ())
122
+ modAttr = iter->second ;
123
+ else {
124
+ modAttr = mlir::LLVM::DIModuleAttr::get (
125
+ context, fileAttr, scope, mlir::StringAttr::get (context, name),
126
+ mlir::StringAttr (), mlir::StringAttr (), mlir::StringAttr (), line, decl);
127
+ moduleMap[name] = modAttr;
128
+ }
129
+ return modAttr;
130
+ }
131
+
132
+ void AddDebugInfoPass::handleGlobalOp (fir::GlobalOp globalOp,
133
+ mlir::LLVM::DIFileAttr fileAttr,
134
+ mlir::LLVM::DIScopeAttr scope) {
135
+ mlir::ModuleOp module = getOperation ();
136
+ mlir::MLIRContext *context = &getContext ();
137
+ fir::DebugTypeGenerator typeGen (module );
138
+ mlir::OpBuilder builder (context);
139
+
140
+ auto result = fir::NameUniquer::deconstruct (globalOp.getSymName ());
141
+ if (result.first != fir::NameUniquer::NameKind::VARIABLE)
142
+ return ;
143
+
144
+ unsigned line = getLineFromLoc (globalOp.getLoc ());
145
+
146
+ // DWARF5 says following about the fortran modules:
147
+ // A Fortran 90 module may also be represented by a module entry
148
+ // (but no declaration attribute is warranted because Fortran has no concept
149
+ // of a corresponding module body).
150
+ // But in practice, compilers use declaration attribute with a module in cases
151
+ // where module was defined in another source file (only being used in this
152
+ // one). The hasInitializationBody() seems to provide the right information
153
+ // but inverted. It is true where module is actually defined but false where
154
+ // it is used.
155
+ // FIXME: Currently we don't have the line number on which a module was
156
+ // declared. We are using a best guess of line - 1 where line is the source
157
+ // line of the first member of the module that we encounter.
158
+
159
+ if (!result.second .modules .empty ())
160
+ scope = getOrCreateModuleAttr (result.second .modules [0 ], fileAttr, scope,
161
+ line - 1 , !globalOp.hasInitializationBody ());
162
+
163
+ auto diType = typeGen.convertType (globalOp.getType (), fileAttr, scope,
164
+ globalOp.getLoc ());
165
+ auto gvAttr = mlir::LLVM::DIGlobalVariableAttr::get (
166
+ context, scope, mlir::StringAttr::get (context, result.second .name ),
167
+ mlir::StringAttr::get (context, globalOp.getName ()), fileAttr, line,
168
+ diType, /* isLocalToUnit*/ false ,
169
+ /* isDefinition*/ globalOp.hasInitializationBody (), /* alignInBits*/ 0 );
170
+ globalOp->setLoc (builder.getFusedLoc ({globalOp->getLoc ()}, gvAttr));
171
+ }
172
+
102
173
void AddDebugInfoPass::runOnOperation () {
103
174
mlir::ModuleOp module = getOperation ();
104
175
mlir::MLIRContext *context = &getContext ();
@@ -138,6 +209,10 @@ void AddDebugInfoPass::runOnOperation() {
138
209
llvm::dwarf::getLanguage (" DW_LANG_Fortran95" ), fileAttr, producer,
139
210
isOptimized, debugLevel);
140
211
212
+ module .walk ([&](fir::GlobalOp globalOp) {
213
+ handleGlobalOp (globalOp, fileAttr, cuAttr);
214
+ });
215
+
141
216
module .walk ([&](mlir::func::FuncOp funcOp) {
142
217
mlir::Location l = funcOp->getLoc ();
143
218
// If fused location has already been created then nothing to do
@@ -180,6 +255,7 @@ void AddDebugInfoPass::runOnOperation() {
180
255
181
256
// Only definitions need a distinct identifier and a compilation unit.
182
257
mlir::DistinctAttr id;
258
+ mlir::LLVM::DIScopeAttr Scope = fileAttr;
183
259
mlir::LLVM::DICompileUnitAttr compilationUnit;
184
260
mlir::LLVM::DISubprogramFlags subprogramFlags =
185
261
mlir::LLVM::DISubprogramFlags{};
@@ -192,9 +268,13 @@ void AddDebugInfoPass::runOnOperation() {
192
268
subprogramFlags | mlir::LLVM::DISubprogramFlags::Definition;
193
269
}
194
270
unsigned line = getLineFromLoc (l);
271
+ if (!result.second .modules .empty ())
272
+ Scope = getOrCreateModuleAttr (result.second .modules [0 ], fileAttr, cuAttr,
273
+ line - 1 , false );
274
+
195
275
auto spAttr = mlir::LLVM::DISubprogramAttr::get (
196
- context, id, compilationUnit, fileAttr , funcName, fullName,
197
- funcFileAttr, line, line, subprogramFlags, subTypeAttr);
276
+ context, id, compilationUnit, Scope , funcName, fullName, funcFileAttr ,
277
+ line, line, subprogramFlags, subTypeAttr);
198
278
funcOp->setLoc (builder.getFusedLoc ({funcOp->getLoc ()}, spAttr));
199
279
200
280
funcOp.walk ([&](fir::cg::XDeclareOp declOp) {
0 commit comments