From ac1b69b9db5ceaba1d168de47509ab4cf190a93c Mon Sep 17 00:00:00 2001 From: Tobias Gysi Date: Thu, 29 Jun 2023 06:31:03 +0000 Subject: [PATCH] [mlir][llvm] Add debug label intrinsic This revision adds support for the llvm.dbg.label.intrinsic and the corresponding DILabel metadata. Reviewed By: Dinistro Differential Revision: https://reviews.llvm.org/D153975 --- .../mlir/Dialect/LLVMIR/LLVMAttrDefs.td | 25 ++++++++++++++++++ .../mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td | 26 ++++++++++++++++--- .../include/mlir/Dialect/LLVMIR/LLVMOpBase.td | 5 ++-- .../include/mlir/Target/LLVMIR/ModuleImport.h | 3 +++ mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp | 9 ++++--- mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 2 +- mlir/lib/Target/LLVMIR/DebugImporter.cpp | 8 ++++++ mlir/lib/Target/LLVMIR/DebugImporter.h | 1 + mlir/lib/Target/LLVMIR/DebugTranslation.cpp | 8 +++++- mlir/lib/Target/LLVMIR/DebugTranslation.h | 1 + mlir/lib/Target/LLVMIR/ModuleImport.cpp | 6 +++++ mlir/test/Dialect/LLVMIR/debuginfo.mlir | 10 +++++++ mlir/test/Target/LLVMIR/Import/debug-info.ll | 8 +++++- mlir/test/Target/LLVMIR/llvmir-debug.mlir | 4 +++ .../tools/mlir-tblgen/LLVMIRConversionGen.cpp | 2 ++ 15 files changed, 105 insertions(+), 13 deletions(-) diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td index 62eca517c828..95dbdcd42af1 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td @@ -518,6 +518,31 @@ def LLVM_DISubroutineTypeAttr : LLVM_Attr<"DISubroutineType", "di_subroutine_typ let assemblyFormat = "`<` struct(params) `>`"; } +//===----------------------------------------------------------------------===// +// DILabelAttr +//===----------------------------------------------------------------------===// + +def LLVM_DILabelAttr : LLVM_Attr<"DILabel", "di_label", + /*traits=*/[], "DINodeAttr"> { + let parameters = (ins + "DIScopeAttr":$scope, + OptionalParameter<"StringAttr">:$name, + OptionalParameter<"DIFileAttr">:$file, + OptionalParameter<"unsigned">:$line + ); + let builders = [ + AttrBuilderWithInferredContext<(ins + "DIScopeAttr":$scope, "StringRef":$name, "DIFileAttr":$file, + "unsigned":$line + ), [{ + MLIRContext *ctx = scope.getContext(); + return $_get(ctx, scope, StringAttr::get(ctx, name), file, line); + }]> + ]; + + let assemblyFormat = "`<` struct(params) `>`"; +} + //===----------------------------------------------------------------------===// // MemoryEffectsAttr //===----------------------------------------------------------------------===// diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td index af2b6357d4a2..d673ec1cd971 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td @@ -287,7 +287,7 @@ def LLVM_MemcpyInlineOp : # setAliasAnalysisMetadataCode; } -def LLVM_MemsetOp : LLVM_ZeroResultIntrOp<"memset", [0, 2], +def LLVM_MemsetOp : LLVM_ZeroResultIntrOp<"memset", [0, 2], [DeclareOpInterfaceMethods, DeclareOpInterfaceMethods, DeclareOpInterfaceMethods], @@ -557,17 +557,35 @@ class LLVM_DbgIntrOp traits = []> }]; } -def LLVM_DbgDeclareOp : LLVM_DbgIntrOp< "dbg.declare", "addr", +def LLVM_DbgDeclareOp : LLVM_DbgIntrOp<"dbg.declare", "addr", [DeclareOpInterfaceMethods]> { - let summary = "Declare the address of a local debug info variable."; + let summary = "Describes how the address relates to a source language variable."; let arguments = (ins LLVM_AnyPointer:$addr, LLVM_DILocalVariableAttr:$varInfo); } def LLVM_DbgValueOp : LLVM_DbgIntrOp<"dbg.value", "value"> { - let summary = "Describe the current value of a local debug info variable."; + let summary = "Describes how the value relates to a source language variable."; let arguments = (ins LLVM_Type:$value, LLVM_DILocalVariableAttr:$varInfo); } +def LLVM_DbgLabelOp : LLVM_IntrOp<"dbg.label", [], [], [], 0> { + let summary = "Relates the program to a debug information label."; + let arguments = (ins LLVM_DILabelAttr:$label); + let llvmBuilder = [{ + llvm::Module *module = builder.GetInsertBlock()->getModule(); + llvm::LLVMContext &ctx = module->getContext(); + llvm::Function *fn = + llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::dbg_label); + builder.CreateCall(fn, { + llvm::MetadataAsValue::get(ctx, moduleTranslation.translateDebugInfo($label)) + }); + }]; + let mlirBuilder = [{ + $_op = $_builder.create<$_qualCppClassName>($_location, $_label_attr($label)); + }]; + let assemblyFormat = "$label attr-dict"; +} + // // Variadic function intrinsics. // diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td index 5634964364d8..3d6357298218 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td @@ -91,12 +91,12 @@ def LLVM_AnyTargetExt : Type // Type constraint accepting LLVM target extension types with no support for // memory operations such as alloca, load and store. def LLVM_NonLoadableTargetExtType : Type< - And<[LLVM_AnyTargetExt.predicate, + And<[LLVM_AnyTargetExt.predicate, CPred<"!::llvm::cast<::mlir::LLVM::LLVMTargetExtType>($_self).supportsMemOps()">] >>; // Type constraint accepting any LLVM type that can be loaded or stored, i.e. a -// type that has size (not void, function, opaque struct type or target +// type that has size (not void, function, opaque struct type or target // extension type which does not support memory operations). def LLVM_LoadableType : Type< Or<[And<[LLVM_PrimitiveType.predicate, Neg, @@ -174,6 +174,7 @@ class LLVM_OpBase traits = []> : // - $_int_attr - substituted by a call to an integer attribute matcher; // - $_float_attr - substituted by a call to a float attribute matcher; // - $_var_attr - substituted by a call to a variable attribute matcher; + // - $_label_attr - substituted by a call to a label attribute matcher; // - $_resultType - substituted with the MLIR result type; // - $_location - substituted with the MLIR location; // - $_builder - substituted with the MLIR builder; diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h index 2278ffd8e10d..b2206e98c1e1 100644 --- a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h +++ b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h @@ -148,6 +148,9 @@ public: /// fails. DILocalVariableAttr matchLocalVariableAttr(llvm::Value *value); + /// Converts `value` to a label attribute. Asserts if the matching fails. + DILabelAttr matchLabelAttr(llvm::Value *value); + /// Converts `value` to an array of symbol references pointing to alias scope /// operations, or returns failure if the conversion fails. FailureOr> diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp index 1dda1a0d7e79..0e0c310a00b4 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp @@ -43,10 +43,11 @@ void LLVMDialect::registerAttributes() { bool DINodeAttr::classof(Attribute attr) { return llvm::isa(attr); + DIDerivedTypeAttr, DIFileAttr, DILabelAttr, + DILexicalBlockAttr, DILexicalBlockFileAttr, + DILocalVariableAttr, DINamespaceAttr, DINullTypeAttr, + DISubprogramAttr, DISubrangeAttr, DISubroutineTypeAttr>( + attr); } //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp index 186af5fbf5fa..31a2b93c9521 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -3063,7 +3063,7 @@ struct LLVMOpAsmDialectInterface : public OpAsmDialectInterface { AliasResult getAlias(Attribute attr, raw_ostream &os) const override { return TypeSwitch(attr) .CasegetFilename(), node->getDirectory()); } +DILabelAttr DebugImporter::translateImpl(llvm::DILabel *node) { + return DILabelAttr::get(context, translate(node->getScope()), + getStringAttrOrNull(node->getRawName()), + translate(node->getFile()), node->getLine()); +} + DILexicalBlockAttr DebugImporter::translateImpl(llvm::DILexicalBlock *node) { return DILexicalBlockAttr::get(context, translate(node->getScope()), translate(node->getFile()), node->getLine(), @@ -200,6 +206,8 @@ DINodeAttr DebugImporter::translate(llvm::DINode *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)) 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 6f7e59eb6011..5028e22694a7 100644 --- a/mlir/lib/Target/LLVMIR/DebugImporter.h +++ b/mlir/lib/Target/LLVMIR/DebugImporter.h @@ -57,6 +57,7 @@ private: DICompositeTypeAttr translateImpl(llvm::DICompositeType *node); DIDerivedTypeAttr translateImpl(llvm::DIDerivedType *node); DIFileAttr translateImpl(llvm::DIFile *node); + DILabelAttr translateImpl(llvm::DILabel *node); DILexicalBlockAttr translateImpl(llvm::DILexicalBlock *node); DILexicalBlockFileAttr translateImpl(llvm::DILexicalBlockFile *node); DILocalVariableAttr translateImpl(llvm::DILocalVariable *node); diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp index 3730ddfed238..e421a117691e 100644 --- a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp @@ -149,6 +149,12 @@ llvm::DIFile *DebugTranslation::translateImpl(DIFileAttr attr) { getMDStringOrNull(attr.getDirectory())); } +llvm::DILabel *DebugTranslation::translateImpl(DILabelAttr attr) { + return llvm::DILabel::get(llvmCtx, translate(attr.getScope()), + getMDStringOrNull(attr.getName()), + translate(attr.getFile()), attr.getLine()); +} + llvm::DILexicalBlock *DebugTranslation::translateImpl(DILexicalBlockAttr attr) { return llvm::DILexicalBlock::getDistinct(llvmCtx, translate(attr.getScope()), translate(attr.getFile()), @@ -247,7 +253,7 @@ llvm::DINode *DebugTranslation::translate(DINodeAttr attr) { llvm::DINode *node = TypeSwitch(attr) .Case( diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.h b/mlir/lib/Target/LLVMIR/DebugTranslation.h index f654a4307cfb..5f93882c65d4 100644 --- a/mlir/lib/Target/LLVMIR/DebugTranslation.h +++ b/mlir/lib/Target/LLVMIR/DebugTranslation.h @@ -67,6 +67,7 @@ private: llvm::DICompositeType *translateImpl(DICompositeTypeAttr attr); llvm::DIDerivedType *translateImpl(DIDerivedTypeAttr attr); llvm::DIFile *translateImpl(DIFileAttr attr); + llvm::DILabel *translateImpl(DILabelAttr attr); llvm::DILexicalBlock *translateImpl(DILexicalBlockAttr attr); llvm::DILexicalBlockFile *translateImpl(DILexicalBlockFileAttr attr); llvm::DILocalScope *translateImpl(DILocalScopeAttr attr); diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp index 381560a43874..e098d1427037 100644 --- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp @@ -1255,6 +1255,12 @@ DILocalVariableAttr ModuleImport::matchLocalVariableAttr(llvm::Value *value) { return debugImporter->translate(node); } +DILabelAttr ModuleImport::matchLabelAttr(llvm::Value *value) { + auto *nodeAsVal = cast(value); + auto *node = cast(nodeAsVal->getMetadata()); + return debugImporter->translate(node); +} + FailureOr> ModuleImport::matchAliasScopeAttrs(llvm::Value *value) { auto *nodeAsVal = cast(value); diff --git a/mlir/test/Dialect/LLVMIR/debuginfo.mlir b/mlir/test/Dialect/LLVMIR/debuginfo.mlir index aec40ad50e92..dde22bc57171 100644 --- a/mlir/test/Dialect/LLVMIR/debuginfo.mlir +++ b/mlir/test/Dialect/LLVMIR/debuginfo.mlir @@ -136,6 +136,12 @@ scope = #block2, name = "arg2" > +// CHECK-DAG: #[[LABEL1:.*]] = #llvm.di_label +#label1 = #llvm.di_label + +// CHECK-DAG: #[[LABEL2:.*]] = #llvm.di_label +#label2 = #llvm.di_label + // CHECK: llvm.func @addr(%[[ARG:.*]]: i64) llvm.func @addr(%arg: i64) { // CHECK: %[[ALLOC:.*]] = llvm.alloca @@ -153,5 +159,9 @@ llvm.func @value(%arg1: i32, %arg2: i32) { llvm.intr.dbg.value #var1 = %arg1 : i32 // CHECK: llvm.intr.dbg.value #[[VAR2]] = %[[ARG2]] llvm.intr.dbg.value #var2 = %arg2 : i32 + // CHECK: llvm.intr.dbg.label #[[LABEL1]] + llvm.intr.dbg.label #label1 + // CHECK: llvm.intr.dbg.label #[[LABEL2]] + llvm.intr.dbg.label #label2 llvm.return } diff --git a/mlir/test/Target/LLVMIR/Import/debug-info.ll b/mlir/test/Target/LLVMIR/Import/debug-info.ll index 3bef6b096002..01eb7638c23f 100644 --- a/mlir/test/Target/LLVMIR/Import/debug-info.ll +++ b/mlir/test/Target/LLVMIR/Import/debug-info.ll @@ -233,8 +233,10 @@ source_filename = "debug-info.ll" ; // ----- +; CHECK: #[[FILE:.+]] = #llvm.di_file< ; CHECK: #[[$SP:.+]] = #llvm.di_subprogram< -; CHECK: #[[$VAR0:.+]] = #llvm.di_local_variable +; CHECK: #[[$LABEL:.+]] = #llvm.di_label +; CHECK: #[[$VAR0:.+]] = #llvm.di_local_variable ; CHECK: #[[$VAR1:.+]] = #llvm.di_local_variable ; CHECK-LABEL: @intrinsic @@ -245,6 +247,8 @@ define void @intrinsic(i64 %0, ptr %1) { call void @llvm.dbg.value(metadata i64 %0, metadata !5, metadata !DIExpression()), !dbg !7 ; CHECK: llvm.intr.dbg.declare #[[$VAR1]] = %[[ARG1]] : !llvm.ptr loc(#[[LOC1:.+]]) call void @llvm.dbg.declare(metadata ptr %1, metadata !6, metadata !DIExpression()), !dbg !9 + ; CHECK: llvm.intr.dbg.label #[[$LABEL]] loc(#[[LOC1:.+]]) + call void @llvm.dbg.label(metadata !10), !dbg !9 ret void } @@ -253,6 +257,7 @@ define void @intrinsic(i64 %0, ptr %1) { declare void @llvm.dbg.value(metadata, metadata, metadata) declare void @llvm.dbg.declare(metadata, metadata, metadata) +declare void @llvm.dbg.label(metadata) !llvm.dbg.cu = !{!1} !llvm.module.flags = !{!0} @@ -266,6 +271,7 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) !7 = !DILocation(line: 1, column: 2, scope: !3) !8 = !DILocation(line: 2, column: 2, scope: !3) !9 = !DILocation(line: 3, column: 2, scope: !3) +!10 = !DILabel(scope: !3, name: "label", file: !2, line: 42) ; // ----- diff --git a/mlir/test/Target/LLVMIR/llvmir-debug.mlir b/mlir/test/Target/LLVMIR/llvmir-debug.mlir index dd9ada6569cd..8fbe5cc73ad1 100644 --- a/mlir/test/Target/LLVMIR/llvmir-debug.mlir +++ b/mlir/test/Target/LLVMIR/llvmir-debug.mlir @@ -176,6 +176,7 @@ llvm.func @empty_types() { #di_local_variable0 = #llvm.di_local_variable #di_lexical_block_file = #llvm.di_lexical_block_file #di_local_variable1 = #llvm.di_local_variable +#di_label = #llvm.di_label #loc0 = loc("foo.mlir":0:0) #loc1 = loc(callsite(#loc0 at fused<#di_subprogram>["foo.mlir":4:2])) @@ -187,6 +188,8 @@ llvm.func @func_with_inlined_dbg_value(%arg0: i32) -> (i32) { llvm.intr.dbg.value #di_local_variable0 = %arg0 : i32 loc(fused<#di_subprogram>[#loc0]) // CHECK: call void @llvm.dbg.value(metadata i32 %[[ARG]], metadata ![[VAR_LOC1:[0-9]+]], metadata !DIExpression()), !dbg ![[DBG_LOC1:.*]] llvm.intr.dbg.value #di_local_variable1 = %arg0 : i32 loc(fused<#di_lexical_block_file>[#loc1]) + // CHECK: call void @llvm.dbg.label(metadata ![[LABEL:[0-9]+]]), !dbg ![[DBG_LOC1:.*]] + llvm.intr.dbg.label #di_label loc(fused<#di_lexical_block_file>[#loc1]) llvm.return %arg0 : i32 } loc(fused<#di_subprogram>["caller"]) @@ -196,3 +199,4 @@ llvm.func @func_with_inlined_dbg_value(%arg0: i32) -> (i32) { // CHECK-DAG: ![[LEXICAL_BLOCK_FILE:.*]] = distinct !DILexicalBlockFile(scope: ![[INNER_FUNC]], file: ![[FILE]], discriminator: 0) // CHECK-DAG: ![[VAR_LOC0]] = !DILocalVariable(name: "a", scope: ![[OUTER_FUNC]], file: ![[FILE]] // CHECK-DAG: ![[VAR_LOC1]] = !DILocalVariable(name: "b", scope: ![[LEXICAL_BLOCK_FILE]], file: ![[FILE]] +// CHECK-DAG ![[LABEL]] = !DILabel(scope: ![[LEXICAL_BLOCK_FILE]], name: "label", file: ![[FILE]], line: 42) diff --git a/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp b/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp index f10f3cd8f9a1..23bc9b00dc90 100644 --- a/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp +++ b/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp @@ -270,6 +270,8 @@ static LogicalResult emitOneMLIRBuilder(const Record &record, raw_ostream &os, bs << "moduleImport.matchFloatAttr"; } else if (name == "_var_attr") { bs << "moduleImport.matchLocalVariableAttr"; + } else if (name == "_label_attr") { + bs << "moduleImport.matchLabelAttr"; } else if (name == "_resultType") { bs << "moduleImport.convertType(inst->getType())"; } else if (name == "_location") {