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/Dialect/FIRDialect.h" 19 #include "flang/Optimizer/Dialect/FIROps.h" 20 #include "flang/Optimizer/Dialect/FIRType.h" 21 #include "flang/Optimizer/Dialect/Support/FIRContext.h" 22 #include "flang/Optimizer/Support/InternalNames.h" 23 #include "flang/Optimizer/Transforms/Passes.h" 24 #include "mlir/Dialect/Func/IR/FuncOps.h" 25 #include "mlir/Dialect/LLVMIR/LLVMDialect.h" 26 #include "mlir/IR/Matchers.h" 27 #include "mlir/IR/TypeUtilities.h" 28 #include "mlir/Pass/Pass.h" 29 #include "mlir/Transforms/DialectConversion.h" 30 #include "mlir/Transforms/GreedyPatternRewriteDriver.h" 31 #include "mlir/Transforms/RegionUtils.h" 32 #include "llvm/BinaryFormat/Dwarf.h" 33 #include "llvm/Support/Debug.h" 34 #include "llvm/Support/FileSystem.h" 35 #include "llvm/Support/Path.h" 36 #include "llvm/Support/raw_ostream.h" 37 38 namespace fir { 39 #define GEN_PASS_DEF_ADDDEBUGINFO 40 #include "flang/Optimizer/Transforms/Passes.h.inc" 41 } // namespace fir 42 43 #define DEBUG_TYPE "flang-add-debug-info" 44 45 namespace { 46 47 class AddDebugInfoPass : public fir::impl::AddDebugInfoBase<AddDebugInfoPass> { 48 public: 49 AddDebugInfoPass(fir::AddDebugInfoOptions options) : Base(options) {} 50 void runOnOperation() override; 51 }; 52 53 } // namespace 54 55 void AddDebugInfoPass::runOnOperation() { 56 mlir::ModuleOp module = getOperation(); 57 mlir::MLIRContext *context = &getContext(); 58 mlir::OpBuilder builder(context); 59 llvm::StringRef fileName; 60 std::string filePath; 61 // We need 2 type of file paths here. 62 // 1. Name of the file as was presented to compiler. This can be absolute 63 // or relative to 2. 64 // 2. Current working directory 65 // 66 // We are also dealing with 2 different situations below. One is normal 67 // compilation where we will have a value in 'inputFilename' and we can 68 // obtain the current directory using 'current_path'. 69 // The 2nd case is when this pass is invoked directly from 'fir-opt' tool. 70 // In that case, 'inputFilename' may be empty. Location embedded in the 71 // module will be used to get file name and its directory. 72 if (inputFilename.empty()) { 73 if (auto fileLoc = mlir::dyn_cast<mlir::FileLineColLoc>(module.getLoc())) { 74 fileName = llvm::sys::path::filename(fileLoc.getFilename().getValue()); 75 filePath = llvm::sys::path::parent_path(fileLoc.getFilename().getValue()); 76 } else 77 fileName = "-"; 78 } else { 79 fileName = inputFilename; 80 llvm::SmallString<256> cwd; 81 if (!llvm::sys::fs::current_path(cwd)) 82 filePath = cwd.str(); 83 } 84 85 mlir::LLVM::DIFileAttr fileAttr = 86 mlir::LLVM::DIFileAttr::get(context, fileName, filePath); 87 mlir::StringAttr producer = 88 mlir::StringAttr::get(context, Fortran::common::getFlangFullVersion()); 89 mlir::LLVM::DICompileUnitAttr cuAttr = mlir::LLVM::DICompileUnitAttr::get( 90 mlir::DistinctAttr::create(mlir::UnitAttr::get(context)), 91 llvm::dwarf::getLanguage("DW_LANG_Fortran95"), fileAttr, producer, 92 isOptimized, debugLevel); 93 94 module.walk([&](mlir::func::FuncOp funcOp) { 95 mlir::Location l = funcOp->getLoc(); 96 // If fused location has already been created then nothing to do 97 // Otherwise, create a fused location. 98 if (mlir::dyn_cast<mlir::FusedLoc>(l)) 99 return; 100 101 unsigned int CC = (funcOp.getName() == fir::NameUniquer::doProgramEntry()) 102 ? llvm::dwarf::getCallingConvention("DW_CC_program") 103 : llvm::dwarf::getCallingConvention("DW_CC_normal"); 104 105 if (auto funcLoc = mlir::dyn_cast<mlir::FileLineColLoc>(l)) { 106 fileName = llvm::sys::path::filename(funcLoc.getFilename().getValue()); 107 filePath = llvm::sys::path::parent_path(funcLoc.getFilename().getValue()); 108 } 109 110 mlir::StringAttr fullName = 111 mlir::StringAttr::get(context, funcOp.getName()); 112 auto result = fir::NameUniquer::deconstruct(funcOp.getName()); 113 mlir::StringAttr funcName = 114 mlir::StringAttr::get(context, result.second.name); 115 116 llvm::SmallVector<mlir::LLVM::DITypeAttr> types; 117 fir::DebugTypeGenerator typeGen(module); 118 for (auto resTy : funcOp.getResultTypes()) { 119 auto tyAttr = 120 typeGen.convertType(resTy, fileAttr, cuAttr, funcOp.getLoc()); 121 types.push_back(tyAttr); 122 } 123 for (auto inTy : funcOp.getArgumentTypes()) { 124 auto tyAttr = typeGen.convertType(fir::unwrapRefType(inTy), fileAttr, 125 cuAttr, funcOp.getLoc()); 126 types.push_back(tyAttr); 127 } 128 129 mlir::LLVM::DISubroutineTypeAttr subTypeAttr = 130 mlir::LLVM::DISubroutineTypeAttr::get(context, CC, types); 131 mlir::LLVM::DIFileAttr funcFileAttr = 132 mlir::LLVM::DIFileAttr::get(context, fileName, filePath); 133 134 // Only definitions need a distinct identifier and a compilation unit. 135 mlir::DistinctAttr id; 136 mlir::LLVM::DICompileUnitAttr compilationUnit; 137 mlir::LLVM::DISubprogramFlags subprogramFlags = 138 mlir::LLVM::DISubprogramFlags{}; 139 if (isOptimized) 140 subprogramFlags = mlir::LLVM::DISubprogramFlags::Optimized; 141 if (!funcOp.isExternal()) { 142 id = mlir::DistinctAttr::create(mlir::UnitAttr::get(context)); 143 compilationUnit = cuAttr; 144 subprogramFlags = 145 subprogramFlags | mlir::LLVM::DISubprogramFlags::Definition; 146 } 147 unsigned line = 1; 148 if (auto funcLoc = mlir::dyn_cast<mlir::FileLineColLoc>(l)) 149 line = funcLoc.getLine(); 150 151 auto spAttr = mlir::LLVM::DISubprogramAttr::get( 152 context, id, compilationUnit, fileAttr, funcName, fullName, 153 funcFileAttr, line, line, subprogramFlags, subTypeAttr); 154 funcOp->setLoc(builder.getFusedLoc({funcOp->getLoc()}, spAttr)); 155 }); 156 } 157 158 std::unique_ptr<mlir::Pass> 159 fir::createAddDebugInfoPass(fir::AddDebugInfoOptions options) { 160 return std::make_unique<AddDebugInfoPass>(options); 161 } 162