xref: /llvm-project/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp (revision afa4681ce443e88a5f196b808300fe3c133e96fd)
1 //===-------------- AddDebugInfo.cpp -- add debug info -------------------===//
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 
9 //===----------------------------------------------------------------------===//
10 /// \file
11 /// This pass populates some debug information for the module and functions.
12 //===----------------------------------------------------------------------===//
13 
14 #include "DebugTypeGenerator.h"
15 #include "flang/Common/Version.h"
16 #include "flang/Optimizer/Builder/FIRBuilder.h"
17 #include "flang/Optimizer/Builder/Todo.h"
18 #include "flang/Optimizer/CodeGen/CGOps.h"
19 #include "flang/Optimizer/Dialect/FIRDialect.h"
20 #include "flang/Optimizer/Dialect/FIROps.h"
21 #include "flang/Optimizer/Dialect/FIROpsSupport.h"
22 #include "flang/Optimizer/Dialect/FIRType.h"
23 #include "flang/Optimizer/Dialect/Support/FIRContext.h"
24 #include "flang/Optimizer/Support/InternalNames.h"
25 #include "flang/Optimizer/Transforms/Passes.h"
26 #include "mlir/Dialect/Func/IR/FuncOps.h"
27 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
28 #include "mlir/IR/Matchers.h"
29 #include "mlir/IR/TypeUtilities.h"
30 #include "mlir/Pass/Pass.h"
31 #include "mlir/Transforms/DialectConversion.h"
32 #include "mlir/Transforms/GreedyPatternRewriteDriver.h"
33 #include "mlir/Transforms/RegionUtils.h"
34 #include "llvm/BinaryFormat/Dwarf.h"
35 #include "llvm/Support/Debug.h"
36 #include "llvm/Support/FileSystem.h"
37 #include "llvm/Support/Path.h"
38 #include "llvm/Support/raw_ostream.h"
39 
40 namespace fir {
41 #define GEN_PASS_DEF_ADDDEBUGINFO
42 #include "flang/Optimizer/Transforms/Passes.h.inc"
43 } // namespace fir
44 
45 #define DEBUG_TYPE "flang-add-debug-info"
46 
47 namespace {
48 
49 class AddDebugInfoPass : public fir::impl::AddDebugInfoBase<AddDebugInfoPass> {
50   void handleDeclareOp(fir::cg::XDeclareOp declOp,
51                        mlir::LLVM::DIFileAttr fileAttr,
52                        mlir::LLVM::DIScopeAttr scopeAttr,
53                        fir::DebugTypeGenerator &typeGen,
54                        mlir::SymbolTable *symbolTable);
55 
56 public:
57   AddDebugInfoPass(fir::AddDebugInfoOptions options) : Base(options) {}
58   void runOnOperation() override;
59 
60 private:
61   llvm::StringMap<mlir::LLVM::DIModuleAttr> moduleMap;
62   llvm::StringMap<mlir::LLVM::DICommonBlockAttr> commonBlockMap;
63   // List of GlobalVariableExpressionAttr that are attached to a given global
64   // that represents the storage for common block.
65   llvm::DenseMap<fir::GlobalOp, llvm::SmallVector<mlir::Attribute>>
66       globalToGlobalExprsMap;
67 
68   mlir::LLVM::DIModuleAttr getOrCreateModuleAttr(
69       const std::string &name, mlir::LLVM::DIFileAttr fileAttr,
70       mlir::LLVM::DIScopeAttr scope, unsigned line, bool decl);
71   mlir::LLVM::DICommonBlockAttr
72   getOrCreateCommonBlockAttr(llvm::StringRef name,
73                              mlir::LLVM::DIFileAttr fileAttr,
74                              mlir::LLVM::DIScopeAttr scope, unsigned line);
75 
76   void handleGlobalOp(fir::GlobalOp glocalOp, mlir::LLVM::DIFileAttr fileAttr,
77                       mlir::LLVM::DIScopeAttr scope,
78                       fir::DebugTypeGenerator &typeGen,
79                       mlir::SymbolTable *symbolTable,
80                       fir::cg::XDeclareOp declOp);
81   void handleFuncOp(mlir::func::FuncOp funcOp, mlir::LLVM::DIFileAttr fileAttr,
82                     mlir::LLVM::DICompileUnitAttr cuAttr,
83                     fir::DebugTypeGenerator &typeGen,
84                     mlir::SymbolTable *symbolTable);
85   bool createCommonBlockGlobal(fir::cg::XDeclareOp declOp,
86                                const std::string &name,
87                                mlir::LLVM::DIFileAttr fileAttr,
88                                mlir::LLVM::DIScopeAttr scopeAttr,
89                                fir::DebugTypeGenerator &typeGen,
90                                mlir::SymbolTable *symbolTable);
91   std::optional<mlir::LLVM::DIModuleAttr>
92   getModuleAttrFromGlobalOp(fir::GlobalOp globalOp,
93                             mlir::LLVM::DIFileAttr fileAttr,
94                             mlir::LLVM::DIScopeAttr scope);
95 };
96 
97 bool debugInfoIsAlreadySet(mlir::Location loc) {
98   if (mlir::isa<mlir::FusedLoc>(loc)) {
99     if (loc->findInstanceOf<mlir::FusedLocWith<fir::LocationKindAttr>>())
100       return false;
101     return true;
102   }
103   return false;
104 }
105 
106 } // namespace
107 
108 bool AddDebugInfoPass::createCommonBlockGlobal(
109     fir::cg::XDeclareOp declOp, const std::string &name,
110     mlir::LLVM::DIFileAttr fileAttr, mlir::LLVM::DIScopeAttr scopeAttr,
111     fir::DebugTypeGenerator &typeGen, mlir::SymbolTable *symbolTable) {
112   mlir::MLIRContext *context = &getContext();
113   mlir::OpBuilder builder(context);
114   std::optional<std::int64_t> optint;
115   mlir::Operation *op = declOp.getMemref().getDefiningOp();
116 
117   if (auto conOp = mlir::dyn_cast_if_present<fir::ConvertOp>(op))
118     op = conOp.getValue().getDefiningOp();
119 
120   if (auto cordOp = mlir::dyn_cast_if_present<fir::CoordinateOp>(op)) {
121     optint = fir::getIntIfConstant(cordOp.getOperand(1));
122     if (!optint)
123       return false;
124     op = cordOp.getRef().getDefiningOp();
125     if (auto conOp2 = mlir::dyn_cast_if_present<fir::ConvertOp>(op))
126       op = conOp2.getValue().getDefiningOp();
127 
128     if (auto addrOfOp = mlir::dyn_cast_if_present<fir::AddrOfOp>(op)) {
129       mlir::SymbolRefAttr sym = addrOfOp.getSymbol();
130       if (auto global =
131               symbolTable->lookup<fir::GlobalOp>(sym.getRootReference())) {
132 
133         unsigned line = getLineFromLoc(global.getLoc());
134         llvm::StringRef commonName(sym.getRootReference());
135         // FIXME: We are trying to extract the name of the common block from the
136         // name of the global. As part of mangling, GetCommonBlockObjectName can
137         // add a trailing _ in the name of that global. The demangle function
138         // does not seem to handle such cases. So the following hack is used to
139         // remove the trailing '_'.
140         if (commonName != Fortran::common::blankCommonObjectName &&
141             commonName.back() == '_')
142           commonName = commonName.drop_back();
143         mlir::LLVM::DICommonBlockAttr commonBlock =
144             getOrCreateCommonBlockAttr(commonName, fileAttr, scopeAttr, line);
145         mlir::LLVM::DITypeAttr diType = typeGen.convertType(
146             fir::unwrapRefType(declOp.getType()), fileAttr, scopeAttr, declOp);
147         line = getLineFromLoc(declOp.getLoc());
148         auto gvAttr = mlir::LLVM::DIGlobalVariableAttr::get(
149             context, commonBlock, mlir::StringAttr::get(context, name),
150             declOp.getUniqName(), fileAttr, line, diType,
151             /*isLocalToUnit*/ false, /*isDefinition*/ true, /* alignInBits*/ 0);
152         mlir::LLVM::DIExpressionAttr expr;
153         if (*optint != 0) {
154           llvm::SmallVector<mlir::LLVM::DIExpressionElemAttr> ops;
155           ops.push_back(mlir::LLVM::DIExpressionElemAttr::get(
156               context, llvm::dwarf::DW_OP_plus_uconst, *optint));
157           expr = mlir::LLVM::DIExpressionAttr::get(context, ops);
158         }
159         auto dbgExpr = mlir::LLVM::DIGlobalVariableExpressionAttr::get(
160             global.getContext(), gvAttr, expr);
161         globalToGlobalExprsMap[global].push_back(dbgExpr);
162         return true;
163       }
164     }
165   }
166   return false;
167 }
168 
169 void AddDebugInfoPass::handleDeclareOp(fir::cg::XDeclareOp declOp,
170                                        mlir::LLVM::DIFileAttr fileAttr,
171                                        mlir::LLVM::DIScopeAttr scopeAttr,
172                                        fir::DebugTypeGenerator &typeGen,
173                                        mlir::SymbolTable *symbolTable) {
174   mlir::MLIRContext *context = &getContext();
175   mlir::OpBuilder builder(context);
176   auto result = fir::NameUniquer::deconstruct(declOp.getUniqName());
177 
178   if (result.first != fir::NameUniquer::NameKind::VARIABLE)
179     return;
180 
181   if (createCommonBlockGlobal(declOp, result.second.name, fileAttr, scopeAttr,
182                               typeGen, symbolTable))
183     return;
184 
185   // If this DeclareOp actually represents a global then treat it as such.
186   if (auto global = symbolTable->lookup<fir::GlobalOp>(declOp.getUniqName())) {
187     handleGlobalOp(global, fileAttr, scopeAttr, typeGen, symbolTable, declOp);
188     return;
189   }
190 
191   // Only accept local variables.
192   if (result.second.procs.empty())
193     return;
194 
195   // FIXME: There may be cases where an argument is processed a bit before
196   // DeclareOp is generated. In that case, DeclareOp may point to an
197   // intermediate op and not to BlockArgument.
198   // Moreover, with MLIR inlining we cannot use the BlockArgument
199   // position to identify the original number of the dummy argument.
200   // If we want to keep running AddDebugInfoPass late, the dummy argument
201   // position in the argument list has to be expressed in FIR (e.g. as a
202   // constant attribute of [hl]fir.declare/fircg.ext_declare operation that has
203   // a dummy_scope operand).
204   unsigned argNo = 0;
205   if (declOp.getDummyScope()) {
206     if (auto arg = llvm::dyn_cast<mlir::BlockArgument>(declOp.getMemref()))
207       argNo = arg.getArgNumber() + 1;
208   }
209 
210   auto tyAttr = typeGen.convertType(fir::unwrapRefType(declOp.getType()),
211                                     fileAttr, scopeAttr, declOp);
212 
213   auto localVarAttr = mlir::LLVM::DILocalVariableAttr::get(
214       context, scopeAttr, mlir::StringAttr::get(context, result.second.name),
215       fileAttr, getLineFromLoc(declOp.getLoc()), argNo, /* alignInBits*/ 0,
216       tyAttr, mlir::LLVM::DIFlags::Zero);
217   declOp->setLoc(builder.getFusedLoc({declOp->getLoc()}, localVarAttr));
218 }
219 
220 mlir::LLVM::DICommonBlockAttr AddDebugInfoPass::getOrCreateCommonBlockAttr(
221     llvm::StringRef name, mlir::LLVM::DIFileAttr fileAttr,
222     mlir::LLVM::DIScopeAttr scope, unsigned line) {
223   mlir::MLIRContext *context = &getContext();
224   mlir::LLVM::DICommonBlockAttr cbAttr;
225   if (auto iter{commonBlockMap.find(name)}; iter != commonBlockMap.end()) {
226     cbAttr = iter->getValue();
227   } else {
228     cbAttr = mlir::LLVM::DICommonBlockAttr::get(
229         context, scope, nullptr, mlir::StringAttr::get(context, name), fileAttr,
230         line);
231     commonBlockMap[name] = cbAttr;
232   }
233   return cbAttr;
234 }
235 
236 // The `module` does not have a first class representation in the `FIR`. We
237 // extract information about it from the name of the identifiers and keep a
238 // map to avoid duplication.
239 mlir::LLVM::DIModuleAttr AddDebugInfoPass::getOrCreateModuleAttr(
240     const std::string &name, mlir::LLVM::DIFileAttr fileAttr,
241     mlir::LLVM::DIScopeAttr scope, unsigned line, bool decl) {
242   mlir::MLIRContext *context = &getContext();
243   mlir::LLVM::DIModuleAttr modAttr;
244   if (auto iter{moduleMap.find(name)}; iter != moduleMap.end()) {
245     modAttr = iter->getValue();
246   } else {
247     modAttr = mlir::LLVM::DIModuleAttr::get(
248         context, fileAttr, scope, mlir::StringAttr::get(context, name),
249         /* configMacros */ mlir::StringAttr(),
250         /* includePath */ mlir::StringAttr(),
251         /* apinotes */ mlir::StringAttr(), line, decl);
252     moduleMap[name] = modAttr;
253   }
254   return modAttr;
255 }
256 
257 /// If globalOp represents a module variable, return a ModuleAttr that
258 /// represents that module.
259 std::optional<mlir::LLVM::DIModuleAttr>
260 AddDebugInfoPass::getModuleAttrFromGlobalOp(fir::GlobalOp globalOp,
261                                             mlir::LLVM::DIFileAttr fileAttr,
262                                             mlir::LLVM::DIScopeAttr scope) {
263   mlir::MLIRContext *context = &getContext();
264   mlir::OpBuilder builder(context);
265 
266   std::pair result = fir::NameUniquer::deconstruct(globalOp.getSymName());
267   // Only look for module if this variable is not part of a function.
268   if (!result.second.procs.empty() || result.second.modules.empty())
269     return std::nullopt;
270 
271   // DWARF5 says following about the fortran modules:
272   // A Fortran 90 module may also be represented by a module entry
273   // (but no declaration attribute is warranted because Fortran has no concept
274   // of a corresponding module body).
275   // But in practice, compilers use declaration attribute with a module in cases
276   // where module was defined in another source file (only being used in this
277   // one). The isInitialized() seems to provide the right information
278   // but inverted. It is true where module is actually defined but false where
279   // it is used.
280   // FIXME: Currently we don't have the line number on which a module was
281   // declared. We are using a best guess of line - 1 where line is the source
282   // line of the first member of the module that we encounter.
283   unsigned line = getLineFromLoc(globalOp.getLoc());
284 
285   mlir::LLVM::DISubprogramAttr sp =
286       mlir::dyn_cast_if_present<mlir::LLVM::DISubprogramAttr>(scope);
287   // Modules are generated at compile unit scope
288   if (sp)
289     scope = sp.getCompileUnit();
290 
291   return getOrCreateModuleAttr(result.second.modules[0], fileAttr, scope,
292                                std::max(line - 1, (unsigned)1),
293                                !globalOp.isInitialized());
294 }
295 
296 void AddDebugInfoPass::handleGlobalOp(fir::GlobalOp globalOp,
297                                       mlir::LLVM::DIFileAttr fileAttr,
298                                       mlir::LLVM::DIScopeAttr scope,
299                                       fir::DebugTypeGenerator &typeGen,
300                                       mlir::SymbolTable *symbolTable,
301                                       fir::cg::XDeclareOp declOp) {
302   if (debugInfoIsAlreadySet(globalOp.getLoc()))
303     return;
304   mlir::MLIRContext *context = &getContext();
305   mlir::OpBuilder builder(context);
306 
307   std::pair result = fir::NameUniquer::deconstruct(globalOp.getSymName());
308   if (result.first != fir::NameUniquer::NameKind::VARIABLE)
309     return;
310 
311   if (fir::NameUniquer::isSpecialSymbol(result.second.name))
312     return;
313 
314   unsigned line = getLineFromLoc(globalOp.getLoc());
315   std::optional<mlir::LLVM::DIModuleAttr> modOpt =
316       getModuleAttrFromGlobalOp(globalOp, fileAttr, scope);
317   if (modOpt)
318     scope = *modOpt;
319 
320   mlir::LLVM::DITypeAttr diType =
321       typeGen.convertType(globalOp.getType(), fileAttr, scope, declOp);
322   auto gvAttr = mlir::LLVM::DIGlobalVariableAttr::get(
323       context, scope, mlir::StringAttr::get(context, result.second.name),
324       mlir::StringAttr::get(context, globalOp.getName()), fileAttr, line,
325       diType, /*isLocalToUnit*/ false,
326       /*isDefinition*/ globalOp.isInitialized(), /* alignInBits*/ 0);
327   auto dbgExpr = mlir::LLVM::DIGlobalVariableExpressionAttr::get(
328       globalOp.getContext(), gvAttr, nullptr);
329   auto arrayAttr = mlir::ArrayAttr::get(context, {dbgExpr});
330   globalOp->setLoc(builder.getFusedLoc({globalOp.getLoc()}, arrayAttr));
331 }
332 
333 void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
334                                     mlir::LLVM::DIFileAttr fileAttr,
335                                     mlir::LLVM::DICompileUnitAttr cuAttr,
336                                     fir::DebugTypeGenerator &typeGen,
337                                     mlir::SymbolTable *symbolTable) {
338   mlir::Location l = funcOp->getLoc();
339   // If fused location has already been created then nothing to do
340   // Otherwise, create a fused location.
341   if (debugInfoIsAlreadySet(l))
342     return;
343 
344   mlir::MLIRContext *context = &getContext();
345   mlir::OpBuilder builder(context);
346   llvm::StringRef fileName(fileAttr.getName());
347   llvm::StringRef filePath(fileAttr.getDirectory());
348   unsigned int CC = (funcOp.getName() == fir::NameUniquer::doProgramEntry())
349                         ? llvm::dwarf::getCallingConvention("DW_CC_program")
350                         : llvm::dwarf::getCallingConvention("DW_CC_normal");
351 
352   if (auto funcLoc = mlir::dyn_cast<mlir::FileLineColLoc>(l)) {
353     fileName = llvm::sys::path::filename(funcLoc.getFilename().getValue());
354     filePath = llvm::sys::path::parent_path(funcLoc.getFilename().getValue());
355   }
356 
357   mlir::StringAttr fullName = mlir::StringAttr::get(context, funcOp.getName());
358   mlir::Attribute attr = funcOp->getAttr(fir::getInternalFuncNameAttrName());
359   mlir::StringAttr funcName =
360       (attr) ? mlir::cast<mlir::StringAttr>(attr)
361              : mlir::StringAttr::get(context, funcOp.getName());
362 
363   auto result = fir::NameUniquer::deconstruct(funcName);
364   funcName = mlir::StringAttr::get(context, result.second.name);
365 
366   // try to use a better function name than _QQmain for the program statement
367   bool isMain = false;
368   if (funcName == fir::NameUniquer::doProgramEntry()) {
369     isMain = true;
370     mlir::StringAttr bindcName =
371         funcOp->getAttrOfType<mlir::StringAttr>(fir::getSymbolAttrName());
372     if (bindcName)
373       funcName = bindcName;
374   }
375 
376   llvm::SmallVector<mlir::LLVM::DITypeAttr> types;
377   for (auto resTy : funcOp.getResultTypes()) {
378     auto tyAttr =
379         typeGen.convertType(resTy, fileAttr, cuAttr, /*declOp=*/nullptr);
380     types.push_back(tyAttr);
381   }
382   // If no return type then add a null type as a place holder for that.
383   if (types.empty())
384     types.push_back(mlir::LLVM::DINullTypeAttr::get(context));
385   for (auto inTy : funcOp.getArgumentTypes()) {
386     auto tyAttr = typeGen.convertType(fir::unwrapRefType(inTy), fileAttr,
387                                       cuAttr, /*declOp=*/nullptr);
388     types.push_back(tyAttr);
389   }
390 
391   mlir::LLVM::DISubroutineTypeAttr subTypeAttr =
392       mlir::LLVM::DISubroutineTypeAttr::get(context, CC, types);
393   mlir::LLVM::DIFileAttr funcFileAttr =
394       mlir::LLVM::DIFileAttr::get(context, fileName, filePath);
395 
396   // Only definitions need a distinct identifier and a compilation unit.
397   mlir::DistinctAttr id, id2;
398   mlir::LLVM::DIScopeAttr Scope = fileAttr;
399   mlir::LLVM::DICompileUnitAttr compilationUnit;
400   mlir::LLVM::DISubprogramFlags subprogramFlags =
401       mlir::LLVM::DISubprogramFlags{};
402   if (isOptimized)
403     subprogramFlags = mlir::LLVM::DISubprogramFlags::Optimized;
404   if (isMain)
405     subprogramFlags =
406         subprogramFlags | mlir::LLVM::DISubprogramFlags::MainSubprogram;
407   if (!funcOp.isExternal()) {
408     // Place holder and final function have to have different IDs, otherwise
409     // translation code will reject one of them.
410     id = mlir::DistinctAttr::create(mlir::UnitAttr::get(context));
411     id2 = mlir::DistinctAttr::create(mlir::UnitAttr::get(context));
412     compilationUnit = cuAttr;
413     subprogramFlags =
414         subprogramFlags | mlir::LLVM::DISubprogramFlags::Definition;
415   }
416   unsigned line = getLineFromLoc(l);
417   if (fir::isInternalProcedure(funcOp)) {
418     // For contained functions, the scope is the parent subroutine.
419     mlir::SymbolRefAttr sym = mlir::cast<mlir::SymbolRefAttr>(
420         funcOp->getAttr(fir::getHostSymbolAttrName()));
421     if (sym) {
422       if (auto func =
423               symbolTable->lookup<mlir::func::FuncOp>(sym.getLeafReference())) {
424         // Make sure that parent is processed.
425         handleFuncOp(func, fileAttr, cuAttr, typeGen, symbolTable);
426         if (auto fusedLoc =
427                 mlir::dyn_cast_if_present<mlir::FusedLoc>(func.getLoc())) {
428           if (auto spAttr =
429                   mlir::dyn_cast_if_present<mlir::LLVM::DISubprogramAttr>(
430                       fusedLoc.getMetadata()))
431             Scope = spAttr;
432         }
433       }
434     }
435   } else if (!result.second.modules.empty()) {
436     Scope = getOrCreateModuleAttr(result.second.modules[0], fileAttr, cuAttr,
437                                   line - 1, false);
438   }
439 
440   // Don't process variables if user asked for line tables only.
441   if (debugLevel == mlir::LLVM::DIEmissionKind::LineTablesOnly) {
442     auto spAttr = mlir::LLVM::DISubprogramAttr::get(
443         context, id, compilationUnit, Scope, funcName, fullName, funcFileAttr,
444         line, line, subprogramFlags, subTypeAttr, /*retainedNodes=*/{},
445         /*annotations=*/{});
446     funcOp->setLoc(builder.getFusedLoc({l}, spAttr));
447     return;
448   }
449 
450   mlir::DistinctAttr recId =
451       mlir::DistinctAttr::create(mlir::UnitAttr::get(context));
452 
453   // The debug attribute in MLIR are readonly once created. But in case of
454   // imported entities, we have a circular dependency. The
455   // DIImportedEntityAttr requires scope information (DISubprogramAttr in this
456   // case) and DISubprogramAttr requires the list of imported entities. The
457   // MLIR provides a way where a DISubprogramAttr an be created with a certain
458   // recID and be used in places like DIImportedEntityAttr. After that another
459   // DISubprogramAttr can be created with same recID but with list of entities
460   // now available. The MLIR translation code takes care of updating the
461   // references. Note that references will be updated only in the things that
462   // are part of DISubprogramAttr (like DIImportedEntityAttr) so we have to
463   // create the final DISubprogramAttr before we process local variables.
464   // Look at DIRecursiveTypeAttrInterface for more details.
465 
466   auto spAttr = mlir::LLVM::DISubprogramAttr::get(
467       context, recId, /*isRecSelf=*/true, id, compilationUnit, Scope, funcName,
468       fullName, funcFileAttr, line, line, subprogramFlags, subTypeAttr,
469       /*retainedNodes=*/{}, /*annotations=*/{});
470 
471   // There is no direct information in the IR for any 'use' statement in the
472   // function. We have to extract that information from the DeclareOp. We do
473   // a pass on the DeclareOp and generate ModuleAttr and corresponding
474   // DIImportedEntityAttr for that module.
475   // FIXME: As we are depending on the variables to see which module is being
476   // 'used' in the function, there are certain limitations.
477   // For things like 'use mod1, only: v1', whole module will be brought into the
478   // namespace in the debug info. It is not a problem as such unless there is a
479   // clash of names.
480   // There is no information about module variable renaming
481   llvm::DenseSet<mlir::LLVM::DIImportedEntityAttr> importedModules;
482   funcOp.walk([&](fir::cg::XDeclareOp declOp) {
483     if (&funcOp.front() == declOp->getBlock())
484       if (auto global =
485               symbolTable->lookup<fir::GlobalOp>(declOp.getUniqName())) {
486         std::optional<mlir::LLVM::DIModuleAttr> modOpt =
487             getModuleAttrFromGlobalOp(global, fileAttr, cuAttr);
488         if (modOpt) {
489           auto importedEntity = mlir::LLVM::DIImportedEntityAttr::get(
490               context, llvm::dwarf::DW_TAG_imported_module, spAttr, *modOpt,
491               fileAttr, /*line=*/1, /*name=*/nullptr, /*elements*/ {});
492           importedModules.insert(importedEntity);
493         }
494       }
495   });
496   llvm::SmallVector<mlir::LLVM::DINodeAttr> entities(importedModules.begin(),
497                                                      importedModules.end());
498   // We have the imported entities now. Generate the final DISubprogramAttr.
499   spAttr = mlir::LLVM::DISubprogramAttr::get(
500       context, recId, /*isRecSelf=*/false, id2, compilationUnit, Scope,
501       funcName, fullName, funcFileAttr, line, line, subprogramFlags,
502       subTypeAttr, entities, /*annotations=*/{});
503   funcOp->setLoc(builder.getFusedLoc({l}, spAttr));
504 
505   funcOp.walk([&](fir::cg::XDeclareOp declOp) {
506     // FIXME: We currently dont handle variables that are not in the entry
507     // blocks of the fuctions. These may be variable or arguments used in the
508     // OpenMP target regions.
509     if (&funcOp.front() == declOp->getBlock())
510       handleDeclareOp(declOp, fileAttr, spAttr, typeGen, symbolTable);
511   });
512   // commonBlockMap ensures that we don't create multiple DICommonBlockAttr of
513   // the same name in one function. But it is ok (rather required) to create
514   // them in different functions if common block of the same name has been used
515   // there.
516   commonBlockMap.clear();
517 }
518 
519 void AddDebugInfoPass::runOnOperation() {
520   mlir::ModuleOp module = getOperation();
521   mlir::MLIRContext *context = &getContext();
522   mlir::SymbolTable symbolTable(module);
523   llvm::StringRef fileName;
524   std::string filePath;
525   std::optional<mlir::DataLayout> dl =
526       fir::support::getOrSetDataLayout(module, /*allowDefaultLayout=*/true);
527   if (!dl) {
528     mlir::emitError(module.getLoc(), "Missing data layout attribute in module");
529     signalPassFailure();
530     return;
531   }
532   fir::DebugTypeGenerator typeGen(module, &symbolTable, *dl);
533   // We need 2 type of file paths here.
534   // 1. Name of the file as was presented to compiler. This can be absolute
535   // or relative to 2.
536   // 2. Current working directory
537   //
538   // We are also dealing with 2 different situations below. One is normal
539   // compilation where we will have a value in 'inputFilename' and we can
540   // obtain the current directory using 'current_path'.
541   // The 2nd case is when this pass is invoked directly from 'fir-opt' tool.
542   // In that case, 'inputFilename' may be empty. Location embedded in the
543   // module will be used to get file name and its directory.
544   if (inputFilename.empty()) {
545     if (auto fileLoc = mlir::dyn_cast<mlir::FileLineColLoc>(module.getLoc())) {
546       fileName = llvm::sys::path::filename(fileLoc.getFilename().getValue());
547       filePath = llvm::sys::path::parent_path(fileLoc.getFilename().getValue());
548     } else
549       fileName = "-";
550   } else {
551     fileName = inputFilename;
552     llvm::SmallString<256> cwd;
553     if (!llvm::sys::fs::current_path(cwd))
554       filePath = cwd.str();
555   }
556 
557   mlir::LLVM::DIFileAttr fileAttr =
558       mlir::LLVM::DIFileAttr::get(context, fileName, filePath);
559   mlir::StringAttr producer =
560       mlir::StringAttr::get(context, Fortran::common::getFlangFullVersion());
561   mlir::LLVM::DICompileUnitAttr cuAttr = mlir::LLVM::DICompileUnitAttr::get(
562       mlir::DistinctAttr::create(mlir::UnitAttr::get(context)),
563       llvm::dwarf::getLanguage("DW_LANG_Fortran95"), fileAttr, producer,
564       isOptimized, debugLevel);
565 
566   module.walk([&](mlir::func::FuncOp funcOp) {
567     handleFuncOp(funcOp, fileAttr, cuAttr, typeGen, &symbolTable);
568   });
569   mlir::OpBuilder builder(context);
570   // We have processed all function. Attach common block variables to the
571   // global that represent the storage.
572   for (auto [global, exprs] : globalToGlobalExprsMap) {
573     auto arrayAttr = mlir::ArrayAttr::get(context, exprs);
574     global->setLoc(builder.getFusedLoc({global.getLoc()}, arrayAttr));
575   }
576   // Process any global which was not processed through DeclareOp.
577   if (debugLevel == mlir::LLVM::DIEmissionKind::Full) {
578     // Process 'GlobalOp' only if full debug info is requested.
579     for (auto globalOp : module.getOps<fir::GlobalOp>())
580       handleGlobalOp(globalOp, fileAttr, cuAttr, typeGen, &symbolTable,
581                      /*declOp=*/nullptr);
582   }
583 }
584 
585 std::unique_ptr<mlir::Pass>
586 fir::createAddDebugInfoPass(fir::AddDebugInfoOptions options) {
587   return std::make_unique<AddDebugInfoPass>(options);
588 }
589