17740e933Sabidh //===-------------- AddDebugInfo.cpp -- add debug info -------------------===// 27740e933Sabidh // 37740e933Sabidh // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 47740e933Sabidh // See https://llvm.org/LICENSE.txt for license information. 57740e933Sabidh // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 67740e933Sabidh // 77740e933Sabidh //===----------------------------------------------------------------------===// 87740e933Sabidh 97740e933Sabidh //===----------------------------------------------------------------------===// 107740e933Sabidh /// \file 117740e933Sabidh /// This pass populates some debug information for the module and functions. 127740e933Sabidh //===----------------------------------------------------------------------===// 137740e933Sabidh 1491a8cb78SAbid Qadeer #include "DebugTypeGenerator.h" 155f3f9d1aSAbid Qadeer #include "flang/Common/Version.h" 167740e933Sabidh #include "flang/Optimizer/Builder/FIRBuilder.h" 177740e933Sabidh #include "flang/Optimizer/Builder/Todo.h" 18cd5ee271SAbid Qadeer #include "flang/Optimizer/CodeGen/CGOps.h" 197740e933Sabidh #include "flang/Optimizer/Dialect/FIRDialect.h" 207740e933Sabidh #include "flang/Optimizer/Dialect/FIROps.h" 21f6f4c177STom Eccles #include "flang/Optimizer/Dialect/FIROpsSupport.h" 227740e933Sabidh #include "flang/Optimizer/Dialect/FIRType.h" 237740e933Sabidh #include "flang/Optimizer/Dialect/Support/FIRContext.h" 245f3f9d1aSAbid Qadeer #include "flang/Optimizer/Support/InternalNames.h" 257740e933Sabidh #include "flang/Optimizer/Transforms/Passes.h" 267740e933Sabidh #include "mlir/Dialect/Func/IR/FuncOps.h" 277740e933Sabidh #include "mlir/Dialect/LLVMIR/LLVMDialect.h" 287740e933Sabidh #include "mlir/IR/Matchers.h" 297740e933Sabidh #include "mlir/IR/TypeUtilities.h" 307740e933Sabidh #include "mlir/Pass/Pass.h" 317740e933Sabidh #include "mlir/Transforms/DialectConversion.h" 327740e933Sabidh #include "mlir/Transforms/GreedyPatternRewriteDriver.h" 337740e933Sabidh #include "mlir/Transforms/RegionUtils.h" 347740e933Sabidh #include "llvm/BinaryFormat/Dwarf.h" 357740e933Sabidh #include "llvm/Support/Debug.h" 365f3f9d1aSAbid Qadeer #include "llvm/Support/FileSystem.h" 377740e933Sabidh #include "llvm/Support/Path.h" 387740e933Sabidh #include "llvm/Support/raw_ostream.h" 397740e933Sabidh 407740e933Sabidh namespace fir { 417740e933Sabidh #define GEN_PASS_DEF_ADDDEBUGINFO 427740e933Sabidh #include "flang/Optimizer/Transforms/Passes.h.inc" 437740e933Sabidh } // namespace fir 447740e933Sabidh 456d9ee885Sabidh #define DEBUG_TYPE "flang-add-debug-info" 467740e933Sabidh 477740e933Sabidh namespace { 487740e933Sabidh 497740e933Sabidh class AddDebugInfoPass : public fir::impl::AddDebugInfoBase<AddDebugInfoPass> { 50cd5ee271SAbid Qadeer void handleDeclareOp(fir::cg::XDeclareOp declOp, 51cd5ee271SAbid Qadeer mlir::LLVM::DIFileAttr fileAttr, 52cd5ee271SAbid Qadeer mlir::LLVM::DIScopeAttr scopeAttr, 5320c6b9fbSAbid Qadeer fir::DebugTypeGenerator &typeGen, 5420c6b9fbSAbid Qadeer mlir::SymbolTable *symbolTable); 55cd5ee271SAbid Qadeer 567740e933Sabidh public: 575f3f9d1aSAbid Qadeer AddDebugInfoPass(fir::AddDebugInfoOptions options) : Base(options) {} 587740e933Sabidh void runOnOperation() override; 59f156b9ceSAbid Qadeer 60f156b9ceSAbid Qadeer private: 61f156b9ceSAbid Qadeer llvm::StringMap<mlir::LLVM::DIModuleAttr> moduleMap; 62*afa4681cSAbid Qadeer llvm::StringMap<mlir::LLVM::DICommonBlockAttr> commonBlockMap; 63*afa4681cSAbid Qadeer // List of GlobalVariableExpressionAttr that are attached to a given global 64*afa4681cSAbid Qadeer // that represents the storage for common block. 65*afa4681cSAbid Qadeer llvm::DenseMap<fir::GlobalOp, llvm::SmallVector<mlir::Attribute>> 66*afa4681cSAbid Qadeer globalToGlobalExprsMap; 67f156b9ceSAbid Qadeer 68f156b9ceSAbid Qadeer mlir::LLVM::DIModuleAttr getOrCreateModuleAttr( 69f156b9ceSAbid Qadeer const std::string &name, mlir::LLVM::DIFileAttr fileAttr, 70f156b9ceSAbid Qadeer mlir::LLVM::DIScopeAttr scope, unsigned line, bool decl); 71*afa4681cSAbid Qadeer mlir::LLVM::DICommonBlockAttr 72*afa4681cSAbid Qadeer getOrCreateCommonBlockAttr(llvm::StringRef name, 73*afa4681cSAbid Qadeer mlir::LLVM::DIFileAttr fileAttr, 74*afa4681cSAbid Qadeer mlir::LLVM::DIScopeAttr scope, unsigned line); 75f156b9ceSAbid Qadeer 76f156b9ceSAbid Qadeer void handleGlobalOp(fir::GlobalOp glocalOp, mlir::LLVM::DIFileAttr fileAttr, 7720c6b9fbSAbid Qadeer mlir::LLVM::DIScopeAttr scope, 78d07dc73bSAbid Qadeer fir::DebugTypeGenerator &typeGen, 796fd46089SAbid Qadeer mlir::SymbolTable *symbolTable, 806fd46089SAbid Qadeer fir::cg::XDeclareOp declOp); 81bf76290dSAbid Qadeer void handleFuncOp(mlir::func::FuncOp funcOp, mlir::LLVM::DIFileAttr fileAttr, 82bf76290dSAbid Qadeer mlir::LLVM::DICompileUnitAttr cuAttr, 83d07dc73bSAbid Qadeer fir::DebugTypeGenerator &typeGen, 84bf76290dSAbid Qadeer mlir::SymbolTable *symbolTable); 85*afa4681cSAbid Qadeer bool createCommonBlockGlobal(fir::cg::XDeclareOp declOp, 86*afa4681cSAbid Qadeer const std::string &name, 87*afa4681cSAbid Qadeer mlir::LLVM::DIFileAttr fileAttr, 88*afa4681cSAbid Qadeer mlir::LLVM::DIScopeAttr scopeAttr, 89*afa4681cSAbid Qadeer fir::DebugTypeGenerator &typeGen, 90*afa4681cSAbid Qadeer mlir::SymbolTable *symbolTable); 91db64e69fSAbid Qadeer std::optional<mlir::LLVM::DIModuleAttr> 92db64e69fSAbid Qadeer getModuleAttrFromGlobalOp(fir::GlobalOp globalOp, 93db64e69fSAbid Qadeer mlir::LLVM::DIFileAttr fileAttr, 94db64e69fSAbid Qadeer mlir::LLVM::DIScopeAttr scope); 957740e933Sabidh }; 967740e933Sabidh 9720c6b9fbSAbid Qadeer bool debugInfoIsAlreadySet(mlir::Location loc) { 980ee0eeb4SValentin Clement (バレンタイン クレメン) if (mlir::isa<mlir::FusedLoc>(loc)) { 990ee0eeb4SValentin Clement (バレンタイン クレメン) if (loc->findInstanceOf<mlir::FusedLocWith<fir::LocationKindAttr>>()) 1000ee0eeb4SValentin Clement (バレンタイン クレメン) return false; 10120c6b9fbSAbid Qadeer return true; 1020ee0eeb4SValentin Clement (バレンタイン クレメン) } 10320c6b9fbSAbid Qadeer return false; 10420c6b9fbSAbid Qadeer } 10520c6b9fbSAbid Qadeer 1067740e933Sabidh } // namespace 1077740e933Sabidh 108*afa4681cSAbid Qadeer bool AddDebugInfoPass::createCommonBlockGlobal( 109*afa4681cSAbid Qadeer fir::cg::XDeclareOp declOp, const std::string &name, 110*afa4681cSAbid Qadeer mlir::LLVM::DIFileAttr fileAttr, mlir::LLVM::DIScopeAttr scopeAttr, 111*afa4681cSAbid Qadeer fir::DebugTypeGenerator &typeGen, mlir::SymbolTable *symbolTable) { 112*afa4681cSAbid Qadeer mlir::MLIRContext *context = &getContext(); 113*afa4681cSAbid Qadeer mlir::OpBuilder builder(context); 114*afa4681cSAbid Qadeer std::optional<std::int64_t> optint; 115*afa4681cSAbid Qadeer mlir::Operation *op = declOp.getMemref().getDefiningOp(); 116*afa4681cSAbid Qadeer 117*afa4681cSAbid Qadeer if (auto conOp = mlir::dyn_cast_if_present<fir::ConvertOp>(op)) 118*afa4681cSAbid Qadeer op = conOp.getValue().getDefiningOp(); 119*afa4681cSAbid Qadeer 120*afa4681cSAbid Qadeer if (auto cordOp = mlir::dyn_cast_if_present<fir::CoordinateOp>(op)) { 121*afa4681cSAbid Qadeer optint = fir::getIntIfConstant(cordOp.getOperand(1)); 122*afa4681cSAbid Qadeer if (!optint) 123*afa4681cSAbid Qadeer return false; 124*afa4681cSAbid Qadeer op = cordOp.getRef().getDefiningOp(); 125*afa4681cSAbid Qadeer if (auto conOp2 = mlir::dyn_cast_if_present<fir::ConvertOp>(op)) 126*afa4681cSAbid Qadeer op = conOp2.getValue().getDefiningOp(); 127*afa4681cSAbid Qadeer 128*afa4681cSAbid Qadeer if (auto addrOfOp = mlir::dyn_cast_if_present<fir::AddrOfOp>(op)) { 129*afa4681cSAbid Qadeer mlir::SymbolRefAttr sym = addrOfOp.getSymbol(); 130*afa4681cSAbid Qadeer if (auto global = 131*afa4681cSAbid Qadeer symbolTable->lookup<fir::GlobalOp>(sym.getRootReference())) { 132*afa4681cSAbid Qadeer 133*afa4681cSAbid Qadeer unsigned line = getLineFromLoc(global.getLoc()); 134*afa4681cSAbid Qadeer llvm::StringRef commonName(sym.getRootReference()); 135*afa4681cSAbid Qadeer // FIXME: We are trying to extract the name of the common block from the 136*afa4681cSAbid Qadeer // name of the global. As part of mangling, GetCommonBlockObjectName can 137*afa4681cSAbid Qadeer // add a trailing _ in the name of that global. The demangle function 138*afa4681cSAbid Qadeer // does not seem to handle such cases. So the following hack is used to 139*afa4681cSAbid Qadeer // remove the trailing '_'. 140*afa4681cSAbid Qadeer if (commonName != Fortran::common::blankCommonObjectName && 141*afa4681cSAbid Qadeer commonName.back() == '_') 142*afa4681cSAbid Qadeer commonName = commonName.drop_back(); 143*afa4681cSAbid Qadeer mlir::LLVM::DICommonBlockAttr commonBlock = 144*afa4681cSAbid Qadeer getOrCreateCommonBlockAttr(commonName, fileAttr, scopeAttr, line); 145*afa4681cSAbid Qadeer mlir::LLVM::DITypeAttr diType = typeGen.convertType( 146*afa4681cSAbid Qadeer fir::unwrapRefType(declOp.getType()), fileAttr, scopeAttr, declOp); 147*afa4681cSAbid Qadeer line = getLineFromLoc(declOp.getLoc()); 148*afa4681cSAbid Qadeer auto gvAttr = mlir::LLVM::DIGlobalVariableAttr::get( 149*afa4681cSAbid Qadeer context, commonBlock, mlir::StringAttr::get(context, name), 150*afa4681cSAbid Qadeer declOp.getUniqName(), fileAttr, line, diType, 151*afa4681cSAbid Qadeer /*isLocalToUnit*/ false, /*isDefinition*/ true, /* alignInBits*/ 0); 152*afa4681cSAbid Qadeer mlir::LLVM::DIExpressionAttr expr; 153*afa4681cSAbid Qadeer if (*optint != 0) { 154*afa4681cSAbid Qadeer llvm::SmallVector<mlir::LLVM::DIExpressionElemAttr> ops; 155*afa4681cSAbid Qadeer ops.push_back(mlir::LLVM::DIExpressionElemAttr::get( 156*afa4681cSAbid Qadeer context, llvm::dwarf::DW_OP_plus_uconst, *optint)); 157*afa4681cSAbid Qadeer expr = mlir::LLVM::DIExpressionAttr::get(context, ops); 158*afa4681cSAbid Qadeer } 159*afa4681cSAbid Qadeer auto dbgExpr = mlir::LLVM::DIGlobalVariableExpressionAttr::get( 160*afa4681cSAbid Qadeer global.getContext(), gvAttr, expr); 161*afa4681cSAbid Qadeer globalToGlobalExprsMap[global].push_back(dbgExpr); 162*afa4681cSAbid Qadeer return true; 163*afa4681cSAbid Qadeer } 164*afa4681cSAbid Qadeer } 165*afa4681cSAbid Qadeer } 166*afa4681cSAbid Qadeer return false; 167*afa4681cSAbid Qadeer } 168*afa4681cSAbid Qadeer 169cd5ee271SAbid Qadeer void AddDebugInfoPass::handleDeclareOp(fir::cg::XDeclareOp declOp, 170cd5ee271SAbid Qadeer mlir::LLVM::DIFileAttr fileAttr, 171cd5ee271SAbid Qadeer mlir::LLVM::DIScopeAttr scopeAttr, 17220c6b9fbSAbid Qadeer fir::DebugTypeGenerator &typeGen, 17320c6b9fbSAbid Qadeer mlir::SymbolTable *symbolTable) { 174cd5ee271SAbid Qadeer mlir::MLIRContext *context = &getContext(); 175cd5ee271SAbid Qadeer mlir::OpBuilder builder(context); 176cd5ee271SAbid Qadeer auto result = fir::NameUniquer::deconstruct(declOp.getUniqName()); 177cd5ee271SAbid Qadeer 178cd5ee271SAbid Qadeer if (result.first != fir::NameUniquer::NameKind::VARIABLE) 179cd5ee271SAbid Qadeer return; 180*afa4681cSAbid Qadeer 181*afa4681cSAbid Qadeer if (createCommonBlockGlobal(declOp, result.second.name, fileAttr, scopeAttr, 182*afa4681cSAbid Qadeer typeGen, symbolTable)) 183*afa4681cSAbid Qadeer return; 184*afa4681cSAbid Qadeer 18520c6b9fbSAbid Qadeer // If this DeclareOp actually represents a global then treat it as such. 18620c6b9fbSAbid Qadeer if (auto global = symbolTable->lookup<fir::GlobalOp>(declOp.getUniqName())) { 187d07dc73bSAbid Qadeer handleGlobalOp(global, fileAttr, scopeAttr, typeGen, symbolTable, declOp); 18820c6b9fbSAbid Qadeer return; 18920c6b9fbSAbid Qadeer } 19020c6b9fbSAbid Qadeer 191cd5ee271SAbid Qadeer // Only accept local variables. 192cd5ee271SAbid Qadeer if (result.second.procs.empty()) 193cd5ee271SAbid Qadeer return; 194cd5ee271SAbid Qadeer 195cd5ee271SAbid Qadeer // FIXME: There may be cases where an argument is processed a bit before 196cd5ee271SAbid Qadeer // DeclareOp is generated. In that case, DeclareOp may point to an 1976cd86d0fSSlava Zakharin // intermediate op and not to BlockArgument. 1986cd86d0fSSlava Zakharin // Moreover, with MLIR inlining we cannot use the BlockArgument 1996cd86d0fSSlava Zakharin // position to identify the original number of the dummy argument. 2006cd86d0fSSlava Zakharin // If we want to keep running AddDebugInfoPass late, the dummy argument 2016cd86d0fSSlava Zakharin // position in the argument list has to be expressed in FIR (e.g. as a 2026cd86d0fSSlava Zakharin // constant attribute of [hl]fir.declare/fircg.ext_declare operation that has 2036cd86d0fSSlava Zakharin // a dummy_scope operand). 204cd5ee271SAbid Qadeer unsigned argNo = 0; 205f7420a9dSAbid Qadeer if (declOp.getDummyScope()) { 206f7420a9dSAbid Qadeer if (auto arg = llvm::dyn_cast<mlir::BlockArgument>(declOp.getMemref())) 2075bfc4445SKareem Ergawy argNo = arg.getArgNumber() + 1; 2085bfc4445SKareem Ergawy } 209cd5ee271SAbid Qadeer 210cd5ee271SAbid Qadeer auto tyAttr = typeGen.convertType(fir::unwrapRefType(declOp.getType()), 2116fd46089SAbid Qadeer fileAttr, scopeAttr, declOp); 212cd5ee271SAbid Qadeer 213cd5ee271SAbid Qadeer auto localVarAttr = mlir::LLVM::DILocalVariableAttr::get( 214cd5ee271SAbid Qadeer context, scopeAttr, mlir::StringAttr::get(context, result.second.name), 215cd5ee271SAbid Qadeer fileAttr, getLineFromLoc(declOp.getLoc()), argNo, /* alignInBits*/ 0, 216ef8de68fSWalter Erquinigo tyAttr, mlir::LLVM::DIFlags::Zero); 217cd5ee271SAbid Qadeer declOp->setLoc(builder.getFusedLoc({declOp->getLoc()}, localVarAttr)); 218cd5ee271SAbid Qadeer } 219cd5ee271SAbid Qadeer 220*afa4681cSAbid Qadeer mlir::LLVM::DICommonBlockAttr AddDebugInfoPass::getOrCreateCommonBlockAttr( 221*afa4681cSAbid Qadeer llvm::StringRef name, mlir::LLVM::DIFileAttr fileAttr, 222*afa4681cSAbid Qadeer mlir::LLVM::DIScopeAttr scope, unsigned line) { 223*afa4681cSAbid Qadeer mlir::MLIRContext *context = &getContext(); 224*afa4681cSAbid Qadeer mlir::LLVM::DICommonBlockAttr cbAttr; 225*afa4681cSAbid Qadeer if (auto iter{commonBlockMap.find(name)}; iter != commonBlockMap.end()) { 226*afa4681cSAbid Qadeer cbAttr = iter->getValue(); 227*afa4681cSAbid Qadeer } else { 228*afa4681cSAbid Qadeer cbAttr = mlir::LLVM::DICommonBlockAttr::get( 229*afa4681cSAbid Qadeer context, scope, nullptr, mlir::StringAttr::get(context, name), fileAttr, 230*afa4681cSAbid Qadeer line); 231*afa4681cSAbid Qadeer commonBlockMap[name] = cbAttr; 232*afa4681cSAbid Qadeer } 233*afa4681cSAbid Qadeer return cbAttr; 234*afa4681cSAbid Qadeer } 235*afa4681cSAbid Qadeer 236f156b9ceSAbid Qadeer // The `module` does not have a first class representation in the `FIR`. We 237f156b9ceSAbid Qadeer // extract information about it from the name of the identifiers and keep a 238f156b9ceSAbid Qadeer // map to avoid duplication. 239f156b9ceSAbid Qadeer mlir::LLVM::DIModuleAttr AddDebugInfoPass::getOrCreateModuleAttr( 240f156b9ceSAbid Qadeer const std::string &name, mlir::LLVM::DIFileAttr fileAttr, 241f156b9ceSAbid Qadeer mlir::LLVM::DIScopeAttr scope, unsigned line, bool decl) { 242f156b9ceSAbid Qadeer mlir::MLIRContext *context = &getContext(); 243f156b9ceSAbid Qadeer mlir::LLVM::DIModuleAttr modAttr; 244f156b9ceSAbid Qadeer if (auto iter{moduleMap.find(name)}; iter != moduleMap.end()) { 245f156b9ceSAbid Qadeer modAttr = iter->getValue(); 246f156b9ceSAbid Qadeer } else { 247f156b9ceSAbid Qadeer modAttr = mlir::LLVM::DIModuleAttr::get( 248f156b9ceSAbid Qadeer context, fileAttr, scope, mlir::StringAttr::get(context, name), 249f156b9ceSAbid Qadeer /* configMacros */ mlir::StringAttr(), 250f156b9ceSAbid Qadeer /* includePath */ mlir::StringAttr(), 251f156b9ceSAbid Qadeer /* apinotes */ mlir::StringAttr(), line, decl); 252f156b9ceSAbid Qadeer moduleMap[name] = modAttr; 253f156b9ceSAbid Qadeer } 254f156b9ceSAbid Qadeer return modAttr; 255f156b9ceSAbid Qadeer } 256f156b9ceSAbid Qadeer 257db64e69fSAbid Qadeer /// If globalOp represents a module variable, return a ModuleAttr that 258db64e69fSAbid Qadeer /// represents that module. 259db64e69fSAbid Qadeer std::optional<mlir::LLVM::DIModuleAttr> 260db64e69fSAbid Qadeer AddDebugInfoPass::getModuleAttrFromGlobalOp(fir::GlobalOp globalOp, 261db64e69fSAbid Qadeer mlir::LLVM::DIFileAttr fileAttr, 262db64e69fSAbid Qadeer mlir::LLVM::DIScopeAttr scope) { 263db64e69fSAbid Qadeer mlir::MLIRContext *context = &getContext(); 264db64e69fSAbid Qadeer mlir::OpBuilder builder(context); 265db64e69fSAbid Qadeer 266db64e69fSAbid Qadeer std::pair result = fir::NameUniquer::deconstruct(globalOp.getSymName()); 267db64e69fSAbid Qadeer // Only look for module if this variable is not part of a function. 268db64e69fSAbid Qadeer if (!result.second.procs.empty() || result.second.modules.empty()) 269db64e69fSAbid Qadeer return std::nullopt; 270db64e69fSAbid Qadeer 271db64e69fSAbid Qadeer // DWARF5 says following about the fortran modules: 272db64e69fSAbid Qadeer // A Fortran 90 module may also be represented by a module entry 273db64e69fSAbid Qadeer // (but no declaration attribute is warranted because Fortran has no concept 274db64e69fSAbid Qadeer // of a corresponding module body). 275db64e69fSAbid Qadeer // But in practice, compilers use declaration attribute with a module in cases 276db64e69fSAbid Qadeer // where module was defined in another source file (only being used in this 277db64e69fSAbid Qadeer // one). The isInitialized() seems to provide the right information 278db64e69fSAbid Qadeer // but inverted. It is true where module is actually defined but false where 279db64e69fSAbid Qadeer // it is used. 280db64e69fSAbid Qadeer // FIXME: Currently we don't have the line number on which a module was 281db64e69fSAbid Qadeer // declared. We are using a best guess of line - 1 where line is the source 282db64e69fSAbid Qadeer // line of the first member of the module that we encounter. 283db64e69fSAbid Qadeer unsigned line = getLineFromLoc(globalOp.getLoc()); 284db64e69fSAbid Qadeer 285db64e69fSAbid Qadeer mlir::LLVM::DISubprogramAttr sp = 286db64e69fSAbid Qadeer mlir::dyn_cast_if_present<mlir::LLVM::DISubprogramAttr>(scope); 287db64e69fSAbid Qadeer // Modules are generated at compile unit scope 288db64e69fSAbid Qadeer if (sp) 289db64e69fSAbid Qadeer scope = sp.getCompileUnit(); 290db64e69fSAbid Qadeer 291db64e69fSAbid Qadeer return getOrCreateModuleAttr(result.second.modules[0], fileAttr, scope, 292db64e69fSAbid Qadeer std::max(line - 1, (unsigned)1), 293db64e69fSAbid Qadeer !globalOp.isInitialized()); 294db64e69fSAbid Qadeer } 295db64e69fSAbid Qadeer 296f156b9ceSAbid Qadeer void AddDebugInfoPass::handleGlobalOp(fir::GlobalOp globalOp, 297f156b9ceSAbid Qadeer mlir::LLVM::DIFileAttr fileAttr, 29820c6b9fbSAbid Qadeer mlir::LLVM::DIScopeAttr scope, 299d07dc73bSAbid Qadeer fir::DebugTypeGenerator &typeGen, 3006fd46089SAbid Qadeer mlir::SymbolTable *symbolTable, 3016fd46089SAbid Qadeer fir::cg::XDeclareOp declOp) { 30220c6b9fbSAbid Qadeer if (debugInfoIsAlreadySet(globalOp.getLoc())) 30320c6b9fbSAbid Qadeer return; 304f156b9ceSAbid Qadeer mlir::MLIRContext *context = &getContext(); 305f156b9ceSAbid Qadeer mlir::OpBuilder builder(context); 306f156b9ceSAbid Qadeer 307f156b9ceSAbid Qadeer std::pair result = fir::NameUniquer::deconstruct(globalOp.getSymName()); 308f156b9ceSAbid Qadeer if (result.first != fir::NameUniquer::NameKind::VARIABLE) 309f156b9ceSAbid Qadeer return; 310f156b9ceSAbid Qadeer 31195b4128cSAbid Qadeer if (fir::NameUniquer::isSpecialSymbol(result.second.name)) 312d07dc73bSAbid Qadeer return; 313d07dc73bSAbid Qadeer 314f156b9ceSAbid Qadeer unsigned line = getLineFromLoc(globalOp.getLoc()); 315db64e69fSAbid Qadeer std::optional<mlir::LLVM::DIModuleAttr> modOpt = 316db64e69fSAbid Qadeer getModuleAttrFromGlobalOp(globalOp, fileAttr, scope); 317db64e69fSAbid Qadeer if (modOpt) 318db64e69fSAbid Qadeer scope = *modOpt; 319f156b9ceSAbid Qadeer 3206fd46089SAbid Qadeer mlir::LLVM::DITypeAttr diType = 3216fd46089SAbid Qadeer typeGen.convertType(globalOp.getType(), fileAttr, scope, declOp); 322f156b9ceSAbid Qadeer auto gvAttr = mlir::LLVM::DIGlobalVariableAttr::get( 323f156b9ceSAbid Qadeer context, scope, mlir::StringAttr::get(context, result.second.name), 324f156b9ceSAbid Qadeer mlir::StringAttr::get(context, globalOp.getName()), fileAttr, line, 325f156b9ceSAbid Qadeer diType, /*isLocalToUnit*/ false, 326f156b9ceSAbid Qadeer /*isDefinition*/ globalOp.isInitialized(), /* alignInBits*/ 0); 327*afa4681cSAbid Qadeer auto dbgExpr = mlir::LLVM::DIGlobalVariableExpressionAttr::get( 328*afa4681cSAbid Qadeer globalOp.getContext(), gvAttr, nullptr); 329*afa4681cSAbid Qadeer auto arrayAttr = mlir::ArrayAttr::get(context, {dbgExpr}); 330*afa4681cSAbid Qadeer globalOp->setLoc(builder.getFusedLoc({globalOp.getLoc()}, arrayAttr)); 331f156b9ceSAbid Qadeer } 332f156b9ceSAbid Qadeer 333bf76290dSAbid Qadeer void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp, 334bf76290dSAbid Qadeer mlir::LLVM::DIFileAttr fileAttr, 335bf76290dSAbid Qadeer mlir::LLVM::DICompileUnitAttr cuAttr, 336d07dc73bSAbid Qadeer fir::DebugTypeGenerator &typeGen, 337bf76290dSAbid Qadeer mlir::SymbolTable *symbolTable) { 338bf76290dSAbid Qadeer mlir::Location l = funcOp->getLoc(); 339bf76290dSAbid Qadeer // If fused location has already been created then nothing to do 340bf76290dSAbid Qadeer // Otherwise, create a fused location. 341bf76290dSAbid Qadeer if (debugInfoIsAlreadySet(l)) 342bf76290dSAbid Qadeer return; 343bf76290dSAbid Qadeer 344bf76290dSAbid Qadeer mlir::MLIRContext *context = &getContext(); 345bf76290dSAbid Qadeer mlir::OpBuilder builder(context); 346bf76290dSAbid Qadeer llvm::StringRef fileName(fileAttr.getName()); 347bf76290dSAbid Qadeer llvm::StringRef filePath(fileAttr.getDirectory()); 348bf76290dSAbid Qadeer unsigned int CC = (funcOp.getName() == fir::NameUniquer::doProgramEntry()) 349bf76290dSAbid Qadeer ? llvm::dwarf::getCallingConvention("DW_CC_program") 350bf76290dSAbid Qadeer : llvm::dwarf::getCallingConvention("DW_CC_normal"); 351bf76290dSAbid Qadeer 352bf76290dSAbid Qadeer if (auto funcLoc = mlir::dyn_cast<mlir::FileLineColLoc>(l)) { 353bf76290dSAbid Qadeer fileName = llvm::sys::path::filename(funcLoc.getFilename().getValue()); 354bf76290dSAbid Qadeer filePath = llvm::sys::path::parent_path(funcLoc.getFilename().getValue()); 355bf76290dSAbid Qadeer } 356bf76290dSAbid Qadeer 357bf76290dSAbid Qadeer mlir::StringAttr fullName = mlir::StringAttr::get(context, funcOp.getName()); 358bf76290dSAbid Qadeer mlir::Attribute attr = funcOp->getAttr(fir::getInternalFuncNameAttrName()); 359bf76290dSAbid Qadeer mlir::StringAttr funcName = 360bf76290dSAbid Qadeer (attr) ? mlir::cast<mlir::StringAttr>(attr) 361bf76290dSAbid Qadeer : mlir::StringAttr::get(context, funcOp.getName()); 362bf76290dSAbid Qadeer 363bf76290dSAbid Qadeer auto result = fir::NameUniquer::deconstruct(funcName); 364bf76290dSAbid Qadeer funcName = mlir::StringAttr::get(context, result.second.name); 365bf76290dSAbid Qadeer 366f6f4c177STom Eccles // try to use a better function name than _QQmain for the program statement 36791d6e77dSTom Eccles bool isMain = false; 368f6f4c177STom Eccles if (funcName == fir::NameUniquer::doProgramEntry()) { 36991d6e77dSTom Eccles isMain = true; 370f6f4c177STom Eccles mlir::StringAttr bindcName = 371f6f4c177STom Eccles funcOp->getAttrOfType<mlir::StringAttr>(fir::getSymbolAttrName()); 372f6f4c177STom Eccles if (bindcName) 373f6f4c177STom Eccles funcName = bindcName; 374f6f4c177STom Eccles } 375f6f4c177STom Eccles 376bf76290dSAbid Qadeer llvm::SmallVector<mlir::LLVM::DITypeAttr> types; 377bf76290dSAbid Qadeer for (auto resTy : funcOp.getResultTypes()) { 3786fd46089SAbid Qadeer auto tyAttr = 3796fd46089SAbid Qadeer typeGen.convertType(resTy, fileAttr, cuAttr, /*declOp=*/nullptr); 380bf76290dSAbid Qadeer types.push_back(tyAttr); 381bf76290dSAbid Qadeer } 382b6f72fc1SAbid Qadeer // If no return type then add a null type as a place holder for that. 383b6f72fc1SAbid Qadeer if (types.empty()) 384b6f72fc1SAbid Qadeer types.push_back(mlir::LLVM::DINullTypeAttr::get(context)); 385bf76290dSAbid Qadeer for (auto inTy : funcOp.getArgumentTypes()) { 386bf76290dSAbid Qadeer auto tyAttr = typeGen.convertType(fir::unwrapRefType(inTy), fileAttr, 3876fd46089SAbid Qadeer cuAttr, /*declOp=*/nullptr); 388bf76290dSAbid Qadeer types.push_back(tyAttr); 389bf76290dSAbid Qadeer } 390bf76290dSAbid Qadeer 391bf76290dSAbid Qadeer mlir::LLVM::DISubroutineTypeAttr subTypeAttr = 392bf76290dSAbid Qadeer mlir::LLVM::DISubroutineTypeAttr::get(context, CC, types); 393bf76290dSAbid Qadeer mlir::LLVM::DIFileAttr funcFileAttr = 394bf76290dSAbid Qadeer mlir::LLVM::DIFileAttr::get(context, fileName, filePath); 395bf76290dSAbid Qadeer 396bf76290dSAbid Qadeer // Only definitions need a distinct identifier and a compilation unit. 397db64e69fSAbid Qadeer mlir::DistinctAttr id, id2; 398bf76290dSAbid Qadeer mlir::LLVM::DIScopeAttr Scope = fileAttr; 399bf76290dSAbid Qadeer mlir::LLVM::DICompileUnitAttr compilationUnit; 400bf76290dSAbid Qadeer mlir::LLVM::DISubprogramFlags subprogramFlags = 401bf76290dSAbid Qadeer mlir::LLVM::DISubprogramFlags{}; 402bf76290dSAbid Qadeer if (isOptimized) 403bf76290dSAbid Qadeer subprogramFlags = mlir::LLVM::DISubprogramFlags::Optimized; 40491d6e77dSTom Eccles if (isMain) 40591d6e77dSTom Eccles subprogramFlags = 40691d6e77dSTom Eccles subprogramFlags | mlir::LLVM::DISubprogramFlags::MainSubprogram; 407bf76290dSAbid Qadeer if (!funcOp.isExternal()) { 408db64e69fSAbid Qadeer // Place holder and final function have to have different IDs, otherwise 409db64e69fSAbid Qadeer // translation code will reject one of them. 410bf76290dSAbid Qadeer id = mlir::DistinctAttr::create(mlir::UnitAttr::get(context)); 411db64e69fSAbid Qadeer id2 = mlir::DistinctAttr::create(mlir::UnitAttr::get(context)); 412bf76290dSAbid Qadeer compilationUnit = cuAttr; 413bf76290dSAbid Qadeer subprogramFlags = 414bf76290dSAbid Qadeer subprogramFlags | mlir::LLVM::DISubprogramFlags::Definition; 415bf76290dSAbid Qadeer } 416bf76290dSAbid Qadeer unsigned line = getLineFromLoc(l); 417bf76290dSAbid Qadeer if (fir::isInternalProcedure(funcOp)) { 418bf76290dSAbid Qadeer // For contained functions, the scope is the parent subroutine. 419bf76290dSAbid Qadeer mlir::SymbolRefAttr sym = mlir::cast<mlir::SymbolRefAttr>( 420bf76290dSAbid Qadeer funcOp->getAttr(fir::getHostSymbolAttrName())); 421bf76290dSAbid Qadeer if (sym) { 422bf76290dSAbid Qadeer if (auto func = 423bf76290dSAbid Qadeer symbolTable->lookup<mlir::func::FuncOp>(sym.getLeafReference())) { 424bf76290dSAbid Qadeer // Make sure that parent is processed. 425d07dc73bSAbid Qadeer handleFuncOp(func, fileAttr, cuAttr, typeGen, symbolTable); 426bf76290dSAbid Qadeer if (auto fusedLoc = 427bf76290dSAbid Qadeer mlir::dyn_cast_if_present<mlir::FusedLoc>(func.getLoc())) { 428bf76290dSAbid Qadeer if (auto spAttr = 429bf76290dSAbid Qadeer mlir::dyn_cast_if_present<mlir::LLVM::DISubprogramAttr>( 430bf76290dSAbid Qadeer fusedLoc.getMetadata())) 431bf76290dSAbid Qadeer Scope = spAttr; 432bf76290dSAbid Qadeer } 433bf76290dSAbid Qadeer } 434bf76290dSAbid Qadeer } 435bf76290dSAbid Qadeer } else if (!result.second.modules.empty()) { 436bf76290dSAbid Qadeer Scope = getOrCreateModuleAttr(result.second.modules[0], fileAttr, cuAttr, 437bf76290dSAbid Qadeer line - 1, false); 438bf76290dSAbid Qadeer } 439bf76290dSAbid Qadeer 440db64e69fSAbid Qadeer // Don't process variables if user asked for line tables only. 441db64e69fSAbid Qadeer if (debugLevel == mlir::LLVM::DIEmissionKind::LineTablesOnly) { 442bf76290dSAbid Qadeer auto spAttr = mlir::LLVM::DISubprogramAttr::get( 443bf76290dSAbid Qadeer context, id, compilationUnit, Scope, funcName, fullName, funcFileAttr, 4442918e779SWalter Erquinigo line, line, subprogramFlags, subTypeAttr, /*retainedNodes=*/{}, 4452918e779SWalter Erquinigo /*annotations=*/{}); 446db64e69fSAbid Qadeer funcOp->setLoc(builder.getFusedLoc({l}, spAttr)); 447bf76290dSAbid Qadeer return; 448db64e69fSAbid Qadeer } 449db64e69fSAbid Qadeer 450db64e69fSAbid Qadeer mlir::DistinctAttr recId = 451db64e69fSAbid Qadeer mlir::DistinctAttr::create(mlir::UnitAttr::get(context)); 452db64e69fSAbid Qadeer 453db64e69fSAbid Qadeer // The debug attribute in MLIR are readonly once created. But in case of 454db64e69fSAbid Qadeer // imported entities, we have a circular dependency. The 455db64e69fSAbid Qadeer // DIImportedEntityAttr requires scope information (DISubprogramAttr in this 456db64e69fSAbid Qadeer // case) and DISubprogramAttr requires the list of imported entities. The 457db64e69fSAbid Qadeer // MLIR provides a way where a DISubprogramAttr an be created with a certain 458db64e69fSAbid Qadeer // recID and be used in places like DIImportedEntityAttr. After that another 459db64e69fSAbid Qadeer // DISubprogramAttr can be created with same recID but with list of entities 460db64e69fSAbid Qadeer // now available. The MLIR translation code takes care of updating the 461db64e69fSAbid Qadeer // references. Note that references will be updated only in the things that 462db64e69fSAbid Qadeer // are part of DISubprogramAttr (like DIImportedEntityAttr) so we have to 463db64e69fSAbid Qadeer // create the final DISubprogramAttr before we process local variables. 464db64e69fSAbid Qadeer // Look at DIRecursiveTypeAttrInterface for more details. 465db64e69fSAbid Qadeer 466db64e69fSAbid Qadeer auto spAttr = mlir::LLVM::DISubprogramAttr::get( 467db64e69fSAbid Qadeer context, recId, /*isRecSelf=*/true, id, compilationUnit, Scope, funcName, 468db64e69fSAbid Qadeer fullName, funcFileAttr, line, line, subprogramFlags, subTypeAttr, 4692918e779SWalter Erquinigo /*retainedNodes=*/{}, /*annotations=*/{}); 470db64e69fSAbid Qadeer 471db64e69fSAbid Qadeer // There is no direct information in the IR for any 'use' statement in the 472db64e69fSAbid Qadeer // function. We have to extract that information from the DeclareOp. We do 473db64e69fSAbid Qadeer // a pass on the DeclareOp and generate ModuleAttr and corresponding 474db64e69fSAbid Qadeer // DIImportedEntityAttr for that module. 475db64e69fSAbid Qadeer // FIXME: As we are depending on the variables to see which module is being 476db64e69fSAbid Qadeer // 'used' in the function, there are certain limitations. 477db64e69fSAbid Qadeer // For things like 'use mod1, only: v1', whole module will be brought into the 478db64e69fSAbid Qadeer // namespace in the debug info. It is not a problem as such unless there is a 479db64e69fSAbid Qadeer // clash of names. 480db64e69fSAbid Qadeer // There is no information about module variable renaming 481db64e69fSAbid Qadeer llvm::DenseSet<mlir::LLVM::DIImportedEntityAttr> importedModules; 482db64e69fSAbid Qadeer funcOp.walk([&](fir::cg::XDeclareOp declOp) { 483db64e69fSAbid Qadeer if (&funcOp.front() == declOp->getBlock()) 484db64e69fSAbid Qadeer if (auto global = 485db64e69fSAbid Qadeer symbolTable->lookup<fir::GlobalOp>(declOp.getUniqName())) { 486db64e69fSAbid Qadeer std::optional<mlir::LLVM::DIModuleAttr> modOpt = 487db64e69fSAbid Qadeer getModuleAttrFromGlobalOp(global, fileAttr, cuAttr); 488db64e69fSAbid Qadeer if (modOpt) { 489db64e69fSAbid Qadeer auto importedEntity = mlir::LLVM::DIImportedEntityAttr::get( 490db64e69fSAbid Qadeer context, llvm::dwarf::DW_TAG_imported_module, spAttr, *modOpt, 491db64e69fSAbid Qadeer fileAttr, /*line=*/1, /*name=*/nullptr, /*elements*/ {}); 492db64e69fSAbid Qadeer importedModules.insert(importedEntity); 493db64e69fSAbid Qadeer } 494db64e69fSAbid Qadeer } 495db64e69fSAbid Qadeer }); 496db64e69fSAbid Qadeer llvm::SmallVector<mlir::LLVM::DINodeAttr> entities(importedModules.begin(), 497db64e69fSAbid Qadeer importedModules.end()); 498db64e69fSAbid Qadeer // We have the imported entities now. Generate the final DISubprogramAttr. 499db64e69fSAbid Qadeer spAttr = mlir::LLVM::DISubprogramAttr::get( 500db64e69fSAbid Qadeer context, recId, /*isRecSelf=*/false, id2, compilationUnit, Scope, 501db64e69fSAbid Qadeer funcName, fullName, funcFileAttr, line, line, subprogramFlags, 5022918e779SWalter Erquinigo subTypeAttr, entities, /*annotations=*/{}); 503db64e69fSAbid Qadeer funcOp->setLoc(builder.getFusedLoc({l}, spAttr)); 504bf76290dSAbid Qadeer 505bf76290dSAbid Qadeer funcOp.walk([&](fir::cg::XDeclareOp declOp) { 5069e08db79SAbid Qadeer // FIXME: We currently dont handle variables that are not in the entry 5079e08db79SAbid Qadeer // blocks of the fuctions. These may be variable or arguments used in the 5089e08db79SAbid Qadeer // OpenMP target regions. 5099e08db79SAbid Qadeer if (&funcOp.front() == declOp->getBlock()) 510bf76290dSAbid Qadeer handleDeclareOp(declOp, fileAttr, spAttr, typeGen, symbolTable); 511bf76290dSAbid Qadeer }); 512*afa4681cSAbid Qadeer // commonBlockMap ensures that we don't create multiple DICommonBlockAttr of 513*afa4681cSAbid Qadeer // the same name in one function. But it is ok (rather required) to create 514*afa4681cSAbid Qadeer // them in different functions if common block of the same name has been used 515*afa4681cSAbid Qadeer // there. 516*afa4681cSAbid Qadeer commonBlockMap.clear(); 517bf76290dSAbid Qadeer } 518bf76290dSAbid Qadeer 5197740e933Sabidh void AddDebugInfoPass::runOnOperation() { 5207740e933Sabidh mlir::ModuleOp module = getOperation(); 5217740e933Sabidh mlir::MLIRContext *context = &getContext(); 52220c6b9fbSAbid Qadeer mlir::SymbolTable symbolTable(module); 5235f3f9d1aSAbid Qadeer llvm::StringRef fileName; 5245f3f9d1aSAbid Qadeer std::string filePath; 525d07dc73bSAbid Qadeer std::optional<mlir::DataLayout> dl = 526d07dc73bSAbid Qadeer fir::support::getOrSetDataLayout(module, /*allowDefaultLayout=*/true); 527d07dc73bSAbid Qadeer if (!dl) { 528d07dc73bSAbid Qadeer mlir::emitError(module.getLoc(), "Missing data layout attribute in module"); 529d07dc73bSAbid Qadeer signalPassFailure(); 530d07dc73bSAbid Qadeer return; 531d07dc73bSAbid Qadeer } 532d07dc73bSAbid Qadeer fir::DebugTypeGenerator typeGen(module, &symbolTable, *dl); 5335f3f9d1aSAbid Qadeer // We need 2 type of file paths here. 5345f3f9d1aSAbid Qadeer // 1. Name of the file as was presented to compiler. This can be absolute 5355f3f9d1aSAbid Qadeer // or relative to 2. 5365f3f9d1aSAbid Qadeer // 2. Current working directory 5375f3f9d1aSAbid Qadeer // 5385f3f9d1aSAbid Qadeer // We are also dealing with 2 different situations below. One is normal 5395f3f9d1aSAbid Qadeer // compilation where we will have a value in 'inputFilename' and we can 5405f3f9d1aSAbid Qadeer // obtain the current directory using 'current_path'. 5415f3f9d1aSAbid Qadeer // The 2nd case is when this pass is invoked directly from 'fir-opt' tool. 5425f3f9d1aSAbid Qadeer // In that case, 'inputFilename' may be empty. Location embedded in the 5435f3f9d1aSAbid Qadeer // module will be used to get file name and its directory. 5445f3f9d1aSAbid Qadeer if (inputFilename.empty()) { 545fac349a1SChristian Sigg if (auto fileLoc = mlir::dyn_cast<mlir::FileLineColLoc>(module.getLoc())) { 5465f3f9d1aSAbid Qadeer fileName = llvm::sys::path::filename(fileLoc.getFilename().getValue()); 5475f3f9d1aSAbid Qadeer filePath = llvm::sys::path::parent_path(fileLoc.getFilename().getValue()); 5485f3f9d1aSAbid Qadeer } else 5495f3f9d1aSAbid Qadeer fileName = "-"; 5505f3f9d1aSAbid Qadeer } else { 5515f3f9d1aSAbid Qadeer fileName = inputFilename; 5525f3f9d1aSAbid Qadeer llvm::SmallString<256> cwd; 5535f3f9d1aSAbid Qadeer if (!llvm::sys::fs::current_path(cwd)) 5545f3f9d1aSAbid Qadeer filePath = cwd.str(); 5555f3f9d1aSAbid Qadeer } 5567740e933Sabidh 5575f3f9d1aSAbid Qadeer mlir::LLVM::DIFileAttr fileAttr = 5585f3f9d1aSAbid Qadeer mlir::LLVM::DIFileAttr::get(context, fileName, filePath); 5595f3f9d1aSAbid Qadeer mlir::StringAttr producer = 5605f3f9d1aSAbid Qadeer mlir::StringAttr::get(context, Fortran::common::getFlangFullVersion()); 5617740e933Sabidh mlir::LLVM::DICompileUnitAttr cuAttr = mlir::LLVM::DICompileUnitAttr::get( 5627740e933Sabidh mlir::DistinctAttr::create(mlir::UnitAttr::get(context)), 5637740e933Sabidh llvm::dwarf::getLanguage("DW_LANG_Fortran95"), fileAttr, producer, 5645f3f9d1aSAbid Qadeer isOptimized, debugLevel); 5657740e933Sabidh 5667740e933Sabidh module.walk([&](mlir::func::FuncOp funcOp) { 567d07dc73bSAbid Qadeer handleFuncOp(funcOp, fileAttr, cuAttr, typeGen, &symbolTable); 5687740e933Sabidh }); 569*afa4681cSAbid Qadeer mlir::OpBuilder builder(context); 570*afa4681cSAbid Qadeer // We have processed all function. Attach common block variables to the 571*afa4681cSAbid Qadeer // global that represent the storage. 572*afa4681cSAbid Qadeer for (auto [global, exprs] : globalToGlobalExprsMap) { 573*afa4681cSAbid Qadeer auto arrayAttr = mlir::ArrayAttr::get(context, exprs); 574*afa4681cSAbid Qadeer global->setLoc(builder.getFusedLoc({global.getLoc()}, arrayAttr)); 575*afa4681cSAbid Qadeer } 57620c6b9fbSAbid Qadeer // Process any global which was not processed through DeclareOp. 57720c6b9fbSAbid Qadeer if (debugLevel == mlir::LLVM::DIEmissionKind::Full) { 57820c6b9fbSAbid Qadeer // Process 'GlobalOp' only if full debug info is requested. 57920c6b9fbSAbid Qadeer for (auto globalOp : module.getOps<fir::GlobalOp>()) 580d07dc73bSAbid Qadeer handleGlobalOp(globalOp, fileAttr, cuAttr, typeGen, &symbolTable, 5816fd46089SAbid Qadeer /*declOp=*/nullptr); 58220c6b9fbSAbid Qadeer } 5837740e933Sabidh } 5847740e933Sabidh 5855f3f9d1aSAbid Qadeer std::unique_ptr<mlir::Pass> 5865f3f9d1aSAbid Qadeer fir::createAddDebugInfoPass(fir::AddDebugInfoOptions options) { 5875f3f9d1aSAbid Qadeer return std::make_unique<AddDebugInfoPass>(options); 5887740e933Sabidh } 589