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