1 //===- DILineTableFromLocations.cpp - -------------------------------------===// 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 #include "mlir/Dialect/LLVMIR/Transforms/Passes.h" 10 11 #include "mlir/Dialect/LLVMIR/LLVMDialect.h" 12 #include "mlir/Pass/Pass.h" 13 #include "llvm/BinaryFormat/Dwarf.h" 14 #include "llvm/Support/Debug.h" 15 #include "llvm/Support/Path.h" 16 17 namespace mlir { 18 namespace LLVM { 19 #define GEN_PASS_DEF_DISCOPEFORLLVMFUNCOPPASS 20 #include "mlir/Dialect/LLVMIR/Transforms/Passes.h.inc" 21 } // namespace LLVM 22 } // namespace mlir 23 24 using namespace mlir; 25 26 /// Attempt to extract a filename for the given loc. 27 static FileLineColLoc extractFileLoc(Location loc) { 28 if (auto fileLoc = dyn_cast<FileLineColLoc>(loc)) 29 return fileLoc; 30 if (auto nameLoc = dyn_cast<NameLoc>(loc)) 31 return extractFileLoc(nameLoc.getChildLoc()); 32 if (auto opaqueLoc = dyn_cast<OpaqueLoc>(loc)) 33 return extractFileLoc(opaqueLoc.getFallbackLocation()); 34 return FileLineColLoc(); 35 } 36 37 /// Creates a DISubprogramAttr with the provided compile unit and attaches it 38 /// to the function. Does nothing when the function already has an attached 39 /// subprogram. 40 static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc, 41 LLVM::DICompileUnitAttr compileUnitAttr) { 42 43 Location loc = llvmFunc.getLoc(); 44 if (loc->findInstanceOf<mlir::FusedLocWith<LLVM::DISubprogramAttr>>()) 45 return; 46 47 MLIRContext *context = llvmFunc->getContext(); 48 49 // Filename, line and colmun to associate to the function. 50 LLVM::DIFileAttr fileAttr; 51 int64_t line = 1, col = 1; 52 FileLineColLoc fileLoc = extractFileLoc(loc); 53 if (!fileLoc && compileUnitAttr) { 54 fileAttr = compileUnitAttr.getFile(); 55 } else if (!fileLoc) { 56 fileAttr = LLVM::DIFileAttr::get(context, "<unknown>", ""); 57 } else { 58 line = fileLoc.getLine(); 59 col = fileLoc.getColumn(); 60 StringRef inputFilePath = fileLoc.getFilename().getValue(); 61 fileAttr = 62 LLVM::DIFileAttr::get(context, llvm::sys::path::filename(inputFilePath), 63 llvm::sys::path::parent_path(inputFilePath)); 64 } 65 auto subroutineTypeAttr = 66 LLVM::DISubroutineTypeAttr::get(context, llvm::dwarf::DW_CC_normal, {}); 67 68 // Only definitions need a distinct identifier and a compilation unit. 69 DistinctAttr id; 70 auto subprogramFlags = LLVM::DISubprogramFlags::Optimized; 71 if (!llvmFunc.isExternal()) { 72 id = mlir::DistinctAttr::create(mlir::UnitAttr::get(context)); 73 subprogramFlags = subprogramFlags | LLVM::DISubprogramFlags::Definition; 74 } else { 75 compileUnitAttr = {}; 76 } 77 auto funcName = StringAttr::get(context, llvmFunc.getName()); 78 auto subprogramAttr = LLVM::DISubprogramAttr::get( 79 context, id, compileUnitAttr, fileAttr, funcName, funcName, fileAttr, 80 /*line=*/line, /*scopeline=*/col, subprogramFlags, subroutineTypeAttr, 81 /*retainedNodes=*/{}, /*annotations=*/{}); 82 llvmFunc->setLoc(FusedLoc::get(context, {loc}, subprogramAttr)); 83 } 84 85 namespace { 86 /// Add a debug info scope to LLVMFuncOp that are missing it. 87 struct DIScopeForLLVMFuncOpPass 88 : public LLVM::impl::DIScopeForLLVMFuncOpPassBase< 89 DIScopeForLLVMFuncOpPass> { 90 using Base::Base; 91 92 void runOnOperation() override { 93 ModuleOp module = getOperation(); 94 Location loc = module.getLoc(); 95 96 MLIRContext *context = &getContext(); 97 if (!context->getLoadedDialect<LLVM::LLVMDialect>()) { 98 emitError(loc, "LLVM dialect is not loaded."); 99 return signalPassFailure(); 100 } 101 102 // To find a DICompileUnitAttr attached to a parent (the module for 103 // example), otherwise create a default one. 104 // Find a DICompileUnitAttr attached to the module, otherwise create a 105 // default one. 106 LLVM::DICompileUnitAttr compileUnitAttr; 107 auto fusedCompileUnitAttr = 108 module->getLoc() 109 ->findInstanceOf<mlir::FusedLocWith<LLVM::DICompileUnitAttr>>(); 110 if (fusedCompileUnitAttr) { 111 compileUnitAttr = fusedCompileUnitAttr.getMetadata(); 112 } else { 113 LLVM::DIFileAttr fileAttr; 114 if (FileLineColLoc fileLoc = extractFileLoc(loc)) { 115 StringRef inputFilePath = fileLoc.getFilename().getValue(); 116 fileAttr = LLVM::DIFileAttr::get( 117 context, llvm::sys::path::filename(inputFilePath), 118 llvm::sys::path::parent_path(inputFilePath)); 119 } else { 120 fileAttr = LLVM::DIFileAttr::get(context, "<unknown>", ""); 121 } 122 123 compileUnitAttr = LLVM::DICompileUnitAttr::get( 124 DistinctAttr::create(UnitAttr::get(context)), llvm::dwarf::DW_LANG_C, 125 fileAttr, StringAttr::get(context, "MLIR"), 126 /*isOptimized=*/true, emissionKind); 127 } 128 129 // Create subprograms for each function with the same distinct compile unit. 130 module.walk([&](LLVM::LLVMFuncOp func) { 131 addScopeToFunction(func, compileUnitAttr); 132 }); 133 } 134 }; 135 136 } // end anonymous namespace 137