xref: /llvm-project/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp (revision d124b98eb6d492ce306dd28ecace326fb38457c5)
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