llvm-project/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
Mehdi Amini 72429a42ac Add a pass that builds a debug info scope for LLVMFuncOp (adding a DISubprogramAttr)
This may be seen as a hack, but it allows for any piece of MLIR to be able
to end up with DWARF debug info through LLVM.
Assuming the operations in the function have location such as FileLineCol,
this provides backtraces with line tables and allows to step in a debugger.
That makes this pass a perfect companion to -snapshot-op-locations

It was also the default behavior of MLIR to LLVM IR translation until MLIR
got support for proper debug info attributes.

Differential Revision: https://reviews.llvm.org/D144069
2023-02-14 22:43:26 -08:00

102 lines
3.8 KiB
C++

//===- DILineTableFromLocations.cpp - -------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "mlir/Dialect/LLVMIR/Transforms/Passes.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/Pass/Pass.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Path.h"
namespace mlir {
namespace LLVM {
#define GEN_PASS_DEF_DISCOPEFORLLVMFUNCOP
#include "mlir/Dialect/LLVMIR/Transforms/Passes.h.inc"
} // namespace LLVM
} // namespace mlir
using namespace mlir;
/// Attempt to extract a filename for the given loc.
static FileLineColLoc extractFileLoc(Location loc) {
if (auto fileLoc = loc.dyn_cast<FileLineColLoc>())
return fileLoc;
if (auto nameLoc = loc.dyn_cast<NameLoc>())
return extractFileLoc(nameLoc.getChildLoc());
if (auto opaqueLoc = loc.dyn_cast<OpaqueLoc>())
return extractFileLoc(opaqueLoc.getFallbackLocation());
return FileLineColLoc();
}
namespace {
/// Add a debug info scope to LLVMFuncOp that are missing it.
struct DIScopeForLLVMFuncOp
: public LLVM::impl::DIScopeForLLVMFuncOpBase<DIScopeForLLVMFuncOp> {
void runOnOperation() override {
LLVM::LLVMFuncOp llvmFunc = getOperation();
Location loc = llvmFunc.getLoc();
if (loc->findInstanceOf<mlir::FusedLocWith<LLVM::DISubprogramAttr>>())
return;
MLIRContext *context = &getContext();
// To find a DICompileUnitAttr attached to a parent (the module for
// example), otherwise create a default one.
LLVM::DICompileUnitAttr compileUnitAttr;
if (ModuleOp module = llvmFunc->getParentOfType<ModuleOp>()) {
auto fusedCompileUnitAttr =
module->getLoc()
->findInstanceOf<mlir::FusedLocWith<LLVM::DICompileUnitAttr>>();
if (fusedCompileUnitAttr)
compileUnitAttr = fusedCompileUnitAttr.getMetadata();
}
// Filename, line and colmun to associate to the function.
LLVM::DIFileAttr fileAttr;
int64_t line = 1, col = 1;
FileLineColLoc fileLoc = extractFileLoc(loc);
if (!fileLoc && compileUnitAttr) {
fileAttr = compileUnitAttr.getFile();
} else if (!fileLoc) {
fileAttr = LLVM::DIFileAttr::get(context, "<unknown>", "");
} else {
line = fileLoc.getLine();
col = fileLoc.getColumn();
StringRef inputFilePath = fileLoc.getFilename().getValue();
fileAttr = LLVM::DIFileAttr::get(
context, llvm::sys::path::filename(inputFilePath),
llvm::sys::path::parent_path(inputFilePath));
}
if (!compileUnitAttr) {
compileUnitAttr = LLVM::DICompileUnitAttr::get(
context, llvm::dwarf::DW_LANG_C, fileAttr,
StringAttr::get(context, "MLIR"), /*isOptimized=*/true,
LLVM::DIEmissionKind::LineTablesOnly);
}
auto subroutineTypeAttr =
LLVM::DISubroutineTypeAttr::get(context, llvm::dwarf::DW_CC_normal, {});
StringAttr funcNameAttr = llvmFunc.getNameAttr();
auto subprogramAttr =
LLVM::DISubprogramAttr::get(context, compileUnitAttr, fileAttr,
funcNameAttr, funcNameAttr, fileAttr,
/*line=*/line,
/*scopeline=*/col,
LLVM::DISubprogramFlags::Definition |
LLVM::DISubprogramFlags::Optimized,
subroutineTypeAttr);
llvmFunc->setLoc(FusedLoc::get(context, {loc}, subprogramAttr));
}
};
} // end anonymous namespace
std::unique_ptr<Pass> mlir::LLVM::createDIScopeForLLVMFuncOpPass() {
return std::make_unique<DIScopeForLLVMFuncOp>();
}