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 = module.getLoc().dyn_cast<mlir::FileLineColLoc>()) { |
73 | fileName = llvm::sys::path::filename(path: fileLoc.getFilename().getValue()); |
74 | filePath = llvm::sys::path::parent_path(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(result&: 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 (l.dyn_cast<mlir::FusedLoc>()) |
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 = l.dyn_cast<mlir::FileLineColLoc>()) { |
105 | fileName = llvm::sys::path::filename(path: funcLoc.getFilename().getValue()); |
106 | filePath = llvm::sys::path::parent_path(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 | |