From 36c34ec967c28c77406fe85ef3237a167a243763 Mon Sep 17 00:00:00 2001 From: Abid Qadeer Date: Thu, 10 Oct 2024 18:07:06 +0100 Subject: [PATCH] [mlir][debug] Support DICommonBlock. (#111706) A COMMON block is a named area of memory that holds a collection of variables. Fortran subprograms may map the COMMON block memory area to a list of variables. A common block is represented in LLVM debug by DICommonBlock. This PR adds support for this in MLIR. The changes are mostly mechanical apart from small change to access the DICompileUnit when the scope of the variable is DICommonBlock. --------- Co-authored-by: Tobias Gysi --- .../mlir/Dialect/LLVMIR/LLVMAttrDefs.td | 16 ++++++++++ mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp | 20 +++++++------ mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 11 +++---- mlir/lib/Target/LLVMIR/DebugImporter.cpp | 9 ++++++ mlir/lib/Target/LLVMIR/DebugImporter.h | 1 + mlir/lib/Target/LLVMIR/DebugTranslation.cpp | 20 +++++++++---- mlir/lib/Target/LLVMIR/DebugTranslation.h | 1 + mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 28 ++++++++++------- mlir/test/Dialect/LLVMIR/debuginfo.mlir | 8 +++++ mlir/test/Target/LLVMIR/Import/debug-info.ll | 24 +++++++++++++++ mlir/test/Target/LLVMIR/llvmir-debug.mlir | 30 +++++++++++++++++++ 11 files changed, 138 insertions(+), 30 deletions(-) diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td index c298c8277eb0c..0d904f13037c6 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td @@ -701,6 +701,22 @@ def LLVM_DISubrangeAttr : LLVM_Attr<"DISubrange", "di_subrange", /*traits=*/[], let assemblyFormat = "`<` struct(params) `>`"; } +//===----------------------------------------------------------------------===// +// DICommonBlockAttr +//===----------------------------------------------------------------------===// + +def LLVM_DICommonBlockAttr : LLVM_Attr<"DICommonBlock", "di_common_block", + /*traits=*/[], "DIScopeAttr"> { + let parameters = (ins + "DIScopeAttr":$scope, + OptionalParameter<"DIGlobalVariableAttr">:$decl, + "StringAttr":$name, + OptionalParameter<"DIFileAttr">:$file, + OptionalParameter<"unsigned">:$line + ); + let assemblyFormat = "`<` struct(params) `>`"; +} + //===----------------------------------------------------------------------===// // DISubroutineTypeAttr //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp index 99871dac81d32..9640bbdf28df4 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp @@ -56,13 +56,14 @@ void LLVMDialect::registerAttributes() { //===----------------------------------------------------------------------===// bool DINodeAttr::classof(Attribute attr) { - return llvm::isa(attr); + return llvm::isa( + attr); } //===----------------------------------------------------------------------===// @@ -70,8 +71,9 @@ bool DINodeAttr::classof(Attribute attr) { //===----------------------------------------------------------------------===// bool DIScopeAttr::classof(Attribute attr) { - return llvm::isa(attr); + return llvm::isa( + attr); } //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp index 2c7af8712d420..006d412936a33 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -3369,11 +3369,12 @@ struct LLVMOpAsmDialectInterface : public OpAsmDialectInterface { AliasResult getAlias(Attribute attr, raw_ostream &os) const override { return TypeSwitch(attr) .CasegetStride())); } +DICommonBlockAttr DebugImporter::translateImpl(llvm::DICommonBlock *node) { + return DICommonBlockAttr::get(context, translate(node->getScope()), + translate(node->getDecl()), + getStringAttrOrNull(node->getRawName()), + translate(node->getFile()), node->getLineNo()); +} + DISubroutineTypeAttr DebugImporter::translateImpl(llvm::DISubroutineType *node) { SmallVector types; @@ -339,6 +346,8 @@ DINodeAttr DebugImporter::translate(llvm::DINode *node) { auto translateNode = [this](llvm::DINode *node) -> DINodeAttr { if (auto *casted = dyn_cast(node)) return translateImpl(casted); + if (auto *casted = dyn_cast(node)) + return translateImpl(casted); if (auto *casted = dyn_cast(node)) return translateImpl(casted); if (auto *casted = dyn_cast(node)) diff --git a/mlir/lib/Target/LLVMIR/DebugImporter.h b/mlir/lib/Target/LLVMIR/DebugImporter.h index cb796676759c3..a452e01a9f604 100644 --- a/mlir/lib/Target/LLVMIR/DebugImporter.h +++ b/mlir/lib/Target/LLVMIR/DebugImporter.h @@ -79,6 +79,7 @@ class DebugImporter { DIScopeAttr translateImpl(llvm::DIScope *node); DISubprogramAttr translateImpl(llvm::DISubprogram *node); DISubrangeAttr translateImpl(llvm::DISubrange *node); + DICommonBlockAttr translateImpl(llvm::DICommonBlock *node); DISubroutineTypeAttr translateImpl(llvm::DISubroutineType *node); DITypeAttr translateImpl(llvm::DIType *node); diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp index 92ff079a10c8a..2491db299af31 100644 --- a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp @@ -397,6 +397,13 @@ llvm::DISubrange *DebugTranslation::translateImpl(DISubrangeAttr attr) { getMetadataOrNull(attr.getStride())); } +llvm::DICommonBlock *DebugTranslation::translateImpl(DICommonBlockAttr attr) { + return llvm::DICommonBlock::get(llvmCtx, translate(attr.getScope()), + translate(attr.getDecl()), + getMDStringOrNull(attr.getName()), + translate(attr.getFile()), attr.getLine()); +} + llvm::DISubroutineType * DebugTranslation::translateImpl(DISubroutineTypeAttr attr) { // Concatenate the result and argument types into a single array. @@ -428,12 +435,13 @@ llvm::DINode *DebugTranslation::translate(DINodeAttr attr) { if (!node) node = TypeSwitch(attr) - .Case( + .Case( [&](auto attr) { return translateImpl(attr); }); if (node && !node->isTemporary()) diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.h b/mlir/lib/Target/LLVMIR/DebugTranslation.h index 422aa34e28f3c..ff4eaa46c564e 100644 --- a/mlir/lib/Target/LLVMIR/DebugTranslation.h +++ b/mlir/lib/Target/LLVMIR/DebugTranslation.h @@ -88,6 +88,7 @@ class DebugTranslation { llvm::DIScope *translateImpl(DIScopeAttr attr); llvm::DISubprogram *translateImpl(DISubprogramAttr attr); llvm::DISubrange *translateImpl(DISubrangeAttr attr); + llvm::DICommonBlock *translateImpl(DICommonBlockAttr attr); llvm::DISubroutineType *translateImpl(DISubroutineTypeAttr attr); llvm::DIType *translateImpl(DITypeAttr attr); diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp index cc0de5bc838c9..a5de90160c414 100644 --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -1064,19 +1064,27 @@ LogicalResult ModuleTranslation::convertGlobals() { // There is no `globals` field in DICompileUnitAttr which can be directly // assigned to DICompileUnit. We have to build the list by looking at the // dbgExpr of all the GlobalOps. The scope of the variable is used to get - // the DICompileUnit in which to add it. But for the languages that - // support modules, the scope hierarchy can be - // variable -> module -> compile unit - // If a variable scope points to the module then we use the scope of the - // module to get the compile unit. - // Global variables are also used for things like static local variables - // in C and local variables with the save attribute in Fortran. The scope - // of the variable is the parent function. We use the compile unit of the - // parent function in this case. + // the DICompileUnit in which to add it. + // But there are cases where the scope of a global does not + // directly point to the DICompileUnit and we have to do a bit more work + // to get to it. Some of those cases are: + // + // 1. For the languages that support modules, the scope hierarchy can be + // variable -> DIModule -> DICompileUnit + // + // 2. For the Fortran common block variable, the scope hierarchy can be + // variable -> DICommonBlock -> DISubprogram -> DICompileUnit + // + // 3. For entities like static local variables in C or variable with + // SAVE attribute in Fortran, the scope hierarchy can be + // variable -> DISubprogram -> DICompileUnit llvm::DIScope *scope = diGlobalVar->getScope(); if (auto *mod = dyn_cast_if_present(scope)) scope = mod->getScope(); - else if (auto *sp = dyn_cast_if_present(scope)) + else if (auto *cb = dyn_cast_if_present(scope)) { + if (auto *sp = dyn_cast_if_present(cb->getScope())) + scope = sp->getUnit(); + } else if (auto *sp = dyn_cast_if_present(scope)) scope = sp->getUnit(); // Get the compile unit (scope) of the the global variable. diff --git a/mlir/test/Dialect/LLVMIR/debuginfo.mlir b/mlir/test/Dialect/LLVMIR/debuginfo.mlir index af95ec97833a1..8475ec6c3510d 100644 --- a/mlir/test/Dialect/LLVMIR/debuginfo.mlir +++ b/mlir/test/Dialect/LLVMIR/debuginfo.mlir @@ -156,6 +156,14 @@ // CHECK-DAG: #[[LABEL2:.*]] = #llvm.di_label #label2 = #llvm.di_label +// CHECK-DAG: #llvm.di_common_block +#di_common_block = #llvm.di_common_block +#global_var = #llvm.di_global_variable +#var_expression = #llvm.di_global_variable_expression> +llvm.mlir.global common @block_() {dbg_expr = #var_expression} : i64 + // CHECK: llvm.func @addr(%[[ARG:.*]]: i64) llvm.func @addr(%arg: i64) { // CHECK: %[[ALLOC:.*]] = llvm.alloca diff --git a/mlir/test/Target/LLVMIR/Import/debug-info.ll b/mlir/test/Target/LLVMIR/Import/debug-info.ll index 6267990b0bf80..09909d7d63b2a 100644 --- a/mlir/test/Target/LLVMIR/Import/debug-info.ll +++ b/mlir/test/Target/LLVMIR/Import/debug-info.ll @@ -843,3 +843,27 @@ define void @fn_with_annotations() !dbg !12 { ; CHECK-DAG: #llvm.di_subprogram<{{.*}}name = "fn_with_annotations"{{.*}}annotations = #llvm.di_annotation> + +; // ----- + +@block = common global [4 x i8] zeroinitializer, !dbg !0 + +define void @test() !dbg !3 { + ret void +} + +!llvm.module.flags = !{!10} +!llvm.dbg.cu = !{!7} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "alpha", scope: !2, file: !4, type: !9) +!2 = !DICommonBlock(scope: !3, declaration: null, name: "block", file: !4, line: 3) +!3 = distinct !DISubprogram(name: "test", scope: !4, file: !4, spFlags: DISPFlagDefinition, unit: !7) +!4 = !DIFile(filename: "test.f90", directory: "") +!7 = distinct !DICompileUnit(language: DW_LANG_Fortran95, file: !4) +!9 = !DIBasicType(name: "integer", size: 32, encoding: DW_ATE_signed) +!10 = !{i32 2, !"Debug Info Version", i32 3} + +; CHECK: #[[FILE:.+]] = #llvm.di_file<"test.f90" in ""> +; CHECK: #[[SP:.+]] = #llvm.di_subprogram<{{.*}}name = "test"{{.*}}> +; CHECK: #llvm.di_common_block diff --git a/mlir/test/Target/LLVMIR/llvmir-debug.mlir b/mlir/test/Target/LLVMIR/llvmir-debug.mlir index b09a60b8dcac9..826fda60c5efe 100644 --- a/mlir/test/Target/LLVMIR/llvmir-debug.mlir +++ b/mlir/test/Target/LLVMIR/llvmir-debug.mlir @@ -660,3 +660,33 @@ llvm.func @string_ty(%arg0: !llvm.ptr) { // CHECK-DAG: !DIStringType(name: "character(*)", stringLength: ![[VAR:[0-9]+]], stringLengthExpression: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8), stringLocationExpression: !DIExpression(DW_OP_push_object_address, DW_OP_deref), size: 32, align: 8) // CHECK-DAG: ![[VAR]] = !DILocalVariable(name: "string_size"{{.*}} flags: DIFlagArtificial) + +// ----- + +// Test translation of DICommonBlockAttr. +#bt = #llvm.di_basic_type +#file = #llvm.di_file<"test.f90" in ""> +#cu = #llvm.di_compile_unit, sourceLanguage = DW_LANG_C, + file = #file, isOptimized = false, emissionKind = Full> +#sp = #llvm.di_subprogram +#di_common_block = #llvm.di_common_block +#global_var = #llvm.di_global_variable +#var_expression = #llvm.di_global_variable_expression> + +llvm.mlir.global common @block_(dense<0> : tensor<8xi8>) + {dbg_expr = #var_expression} : !llvm.array<8 x i8> + +llvm.func @test() { + llvm.return +} loc(#loc2) + +#loc1 = loc("test.f90":1:0) +#loc2 = loc(fused<#sp>[#loc1]) + +// CHECK: !DICommonBlock(scope: ![[SCOPE:[0-9]+]], declaration: null, name: "block", file: ![[FILE:[0-9]+]], line: 3) +// CHECK: ![[SCOPE]] = {{.*}}!DISubprogram(name: "test"{{.*}}) +// CHECK: ![[FILE]] = !DIFile(filename: "test.f90"{{.*}})