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