We need to emit complete debug information for YUL sources, including the generation of relevant debug records such as #dbg_declare for local variables. Below is a hackery attempt to enable #dbg_declare:
libsolidity/codegen/mlir/YulToMLIR.cpp
@@ -562,6 +562,7 @@ void YulToMLIRPass::operator()(VariableDeclaration const &decl) {
getLoc(var.debugData),
/*resTy=*/mlir::LLVM::LLVMPointerType::get(b.getContext()),
/*eltTy=*/getDefIntTy(), bExt.genI256Const(1), getDefAlign());
+ addr->setAttr("var_name", b.getStringAttr(var.name.str()));
trackLocalVarAddr(var.name, addr);
b.create<mlir::LLVM::StoreOp>(loc, rhsExpr, addr, getDefAlign());
}
--- a/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
+++ b/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
@@ -34,6 +34,46 @@ static FileLineColLoc extractFileLoc(Location loc) {
return FileLineColLoc();
}
+static uint32_t getLineFromLoc(mlir::Location loc) {
+ uint32_t line = 1;
+ if (auto fileLoc = mlir::dyn_cast<mlir::FileLineColLoc>(loc))
+ line = fileLoc.getLine();
+ return line;
+}
+
+static void handleDeclareOp(mlir::LLVM::AllocaOp declOp,
+ mlir::LLVM::DIFileAttr fileAttr,
+ mlir::LLVM::DIScopeAttr scopeAttr) {
+ mlir::StringAttr varName = declOp->getAttrOfType<StringAttr>("var_name");
+ /*
+ if (auto fusedLoc =
+ mlir::dyn_cast_if_present<mlir::FusedLoc>(declOp.getLoc()))
+ varName = mlir::dyn_cast_if_present<mlir::StringAttr>(
+ fusedLoc.getMetadata());
+ */
+ if (!varName)
+ return;
+
+ mlir::MLIRContext *context = declOp->getContext();
+ mlir::OpBuilder builder(context);
+ builder.setInsertionPointAfter(declOp);
+
+ auto tyAttr =
+ mlir::LLVM::DIBasicTypeAttr::get(context, llvm::dwarf::DW_TAG_base_type,
+ mlir::StringAttr::get(context,
+ "integer"),
+ 256, llvm::dwarf::DW_ATE_unsigned);
+
+ Location loc = declOp->getLoc();
+ auto localVarAttr = mlir::LLVM::DILocalVariableAttr::get(
+ context, scopeAttr, varName,
+ fileAttr, getLineFromLoc(loc), 0, /* alignInBits*/ 0,
+ tyAttr);
+ declOp->setLoc(builder.getFusedLoc({loc}, localVarAttr));
+ builder.create<mlir::LLVM::DbgDeclareOp>(loc, declOp, localVarAttr);
+}
+
+
/// Creates a DISubprogramAttr with the provided compile unit and attaches it
/// to the function. Does nothing when the function already has an attached
/// subprogram.
@@ -81,6 +121,10 @@ static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc,
/*line=*/line,
/*scopeline=*/col, subprogramFlags, subroutineTypeAttr);
llvmFunc->setLoc(FusedLoc::get(context, {loc}, subprogramAttr));
+
+ llvmFunc.walk([&](mlir::LLVM::AllocaOp declOp) {
+ handleDeclareOp(declOp, fileAttr, subprogramAttr);
+ });
}
namespace {
@@ -117,7 +161,7 @@ struct DIScopeForLLVMFuncOp
compileUnitAttr = LLVM::DICompileUnitAttr::get(
DistinctAttr::create(UnitAttr::get(context)), llvm::dwarf::DW_LANG_C,
fileAttr, StringAttr::get(context, "MLIR"),
- /*isOptimized=*/true, LLVM::DIEmissionKind::LineTablesOnly);
+ /*isOptimized=*/true, LLVM::DIEmissionKind::Full);
}
// Create subprograms for each function with the same distinct compile unit.
We need to emit complete debug information for YUL sources, including the generation of relevant debug records such as
#dbg_declarefor local variables. Below is a hackery attempt to enable#dbg_declare:The full solution can be based on the flang approach:
We may need to introduce additional YUL dialect operations that are not involved in code generation, but exist solely for emitting debug records