xref: /llvm-project/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp (revision fac349a169976f822fb27f03e623fa0d28aec1f3)
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