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
37namespace 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
44namespace {
45
46class AddDebugInfoPass : public fir::impl::AddDebugInfoBase<AddDebugInfoPass> {
47public:
48 AddDebugInfoPass(fir::AddDebugInfoOptions options) : Base(options) {}
49 void runOnOperation() override;
50};
51
52} // namespace
53
54void 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
142std::unique_ptr<mlir::Pass>
143fir::createAddDebugInfoPass(fir::AddDebugInfoOptions options) {
144 return std::make_unique<AddDebugInfoPass>(options);
145}
146

source code of flang/lib/Optimizer/Transforms/AddDebugInfo.cpp