This PR adds following options to the AddDebugInfo pass. 1. IsOptimized flag. 2. Level of debug info to generate. 3. Name of the source file This enables us to remove the hard coded values from the code. It also allows us to test the pass with different options. The tests have been modified to take advantage of that. The calling convention flag and producer name have also been improved.
146 lines
5.8 KiB
C++
146 lines
5.8 KiB
C++
//===-------------- AddDebugInfo.cpp -- add debug info -------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
/// \file
|
|
/// This pass populates some debug information for the module and functions.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "flang/Common/Version.h"
|
|
#include "flang/Optimizer/Builder/FIRBuilder.h"
|
|
#include "flang/Optimizer/Builder/Todo.h"
|
|
#include "flang/Optimizer/Dialect/FIRDialect.h"
|
|
#include "flang/Optimizer/Dialect/FIROps.h"
|
|
#include "flang/Optimizer/Dialect/FIRType.h"
|
|
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
|
|
#include "flang/Optimizer/Support/InternalNames.h"
|
|
#include "flang/Optimizer/Transforms/Passes.h"
|
|
#include "mlir/Dialect/Func/IR/FuncOps.h"
|
|
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
|
|
#include "mlir/IR/Matchers.h"
|
|
#include "mlir/IR/TypeUtilities.h"
|
|
#include "mlir/Pass/Pass.h"
|
|
#include "mlir/Transforms/DialectConversion.h"
|
|
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
|
|
#include "mlir/Transforms/RegionUtils.h"
|
|
#include "llvm/BinaryFormat/Dwarf.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/Path.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
namespace fir {
|
|
#define GEN_PASS_DEF_ADDDEBUGINFO
|
|
#include "flang/Optimizer/Transforms/Passes.h.inc"
|
|
} // namespace fir
|
|
|
|
#define DEBUG_TYPE "flang-add-debug-info"
|
|
|
|
namespace {
|
|
|
|
class AddDebugInfoPass : public fir::impl::AddDebugInfoBase<AddDebugInfoPass> {
|
|
public:
|
|
AddDebugInfoPass(fir::AddDebugInfoOptions options) : Base(options) {}
|
|
void runOnOperation() override;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
void AddDebugInfoPass::runOnOperation() {
|
|
mlir::ModuleOp module = getOperation();
|
|
mlir::MLIRContext *context = &getContext();
|
|
mlir::OpBuilder builder(context);
|
|
llvm::StringRef fileName;
|
|
std::string filePath;
|
|
// We need 2 type of file paths here.
|
|
// 1. Name of the file as was presented to compiler. This can be absolute
|
|
// or relative to 2.
|
|
// 2. Current working directory
|
|
//
|
|
// We are also dealing with 2 different situations below. One is normal
|
|
// compilation where we will have a value in 'inputFilename' and we can
|
|
// obtain the current directory using 'current_path'.
|
|
// The 2nd case is when this pass is invoked directly from 'fir-opt' tool.
|
|
// In that case, 'inputFilename' may be empty. Location embedded in the
|
|
// module will be used to get file name and its directory.
|
|
if (inputFilename.empty()) {
|
|
if (auto fileLoc = module.getLoc().dyn_cast<mlir::FileLineColLoc>()) {
|
|
fileName = llvm::sys::path::filename(fileLoc.getFilename().getValue());
|
|
filePath = llvm::sys::path::parent_path(fileLoc.getFilename().getValue());
|
|
} else
|
|
fileName = "-";
|
|
} else {
|
|
fileName = inputFilename;
|
|
llvm::SmallString<256> cwd;
|
|
if (!llvm::sys::fs::current_path(cwd))
|
|
filePath = cwd.str();
|
|
}
|
|
|
|
mlir::LLVM::DIFileAttr fileAttr =
|
|
mlir::LLVM::DIFileAttr::get(context, fileName, filePath);
|
|
mlir::StringAttr producer =
|
|
mlir::StringAttr::get(context, Fortran::common::getFlangFullVersion());
|
|
mlir::LLVM::DICompileUnitAttr cuAttr = mlir::LLVM::DICompileUnitAttr::get(
|
|
mlir::DistinctAttr::create(mlir::UnitAttr::get(context)),
|
|
llvm::dwarf::getLanguage("DW_LANG_Fortran95"), fileAttr, producer,
|
|
isOptimized, debugLevel);
|
|
|
|
module.walk([&](mlir::func::FuncOp funcOp) {
|
|
mlir::Location l = funcOp->getLoc();
|
|
// If fused location has already been created then nothing to do
|
|
// Otherwise, create a fused location.
|
|
if (l.dyn_cast<mlir::FusedLoc>())
|
|
return;
|
|
|
|
unsigned int CC = (funcOp.getName() == fir::NameUniquer::doProgramEntry())
|
|
? llvm::dwarf::getCallingConvention("DW_CC_program")
|
|
: llvm::dwarf::getCallingConvention("DW_CC_normal");
|
|
|
|
if (auto funcLoc = l.dyn_cast<mlir::FileLineColLoc>()) {
|
|
fileName = llvm::sys::path::filename(funcLoc.getFilename().getValue());
|
|
filePath = llvm::sys::path::parent_path(funcLoc.getFilename().getValue());
|
|
}
|
|
|
|
mlir::StringAttr funcName =
|
|
mlir::StringAttr::get(context, funcOp.getName());
|
|
mlir::LLVM::DIBasicTypeAttr bT = mlir::LLVM::DIBasicTypeAttr::get(
|
|
context, llvm::dwarf::DW_TAG_base_type, "void", /*sizeInBits=*/0,
|
|
/*encoding=*/1);
|
|
// FIXME: Provide proper type for subroutine
|
|
mlir::LLVM::DISubroutineTypeAttr subTypeAttr =
|
|
mlir::LLVM::DISubroutineTypeAttr::get(context, CC, {bT, bT});
|
|
mlir::LLVM::DIFileAttr funcFileAttr =
|
|
mlir::LLVM::DIFileAttr::get(context, fileName, filePath);
|
|
|
|
// Only definitions need a distinct identifier and a compilation unit.
|
|
mlir::DistinctAttr id;
|
|
mlir::LLVM::DICompileUnitAttr compilationUnit;
|
|
mlir::LLVM::DISubprogramFlags subprogramFlags =
|
|
mlir::LLVM::DISubprogramFlags{};
|
|
if (isOptimized)
|
|
subprogramFlags = mlir::LLVM::DISubprogramFlags::Optimized;
|
|
if (!funcOp.isExternal()) {
|
|
id = mlir::DistinctAttr::create(mlir::UnitAttr::get(context));
|
|
compilationUnit = cuAttr;
|
|
subprogramFlags =
|
|
subprogramFlags | mlir::LLVM::DISubprogramFlags::Definition;
|
|
}
|
|
// FIXME: Provide proper line and scopeline.
|
|
auto spAttr = mlir::LLVM::DISubprogramAttr::get(
|
|
context, id, compilationUnit, fileAttr, funcName, funcName,
|
|
funcFileAttr, /*line=*/1, /*scopeline=*/1, subprogramFlags,
|
|
subTypeAttr);
|
|
funcOp->setLoc(builder.getFusedLoc({funcOp->getLoc()}, spAttr));
|
|
});
|
|
}
|
|
|
|
std::unique_ptr<mlir::Pass>
|
|
fir::createAddDebugInfoPass(fir::AddDebugInfoOptions options) {
|
|
return std::make_unique<AddDebugInfoPass>(options);
|
|
}
|