diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td @@ -274,11 +274,11 @@ let parameters = (ins "DIScopeAttr":$scope, "StringAttr":$name, - "DIFileAttr":$file, - "unsigned":$line, - "unsigned":$arg, - "unsigned":$alignInBits, - "DITypeAttr":$type + OptionalParameter<"DIFileAttr">:$file, + OptionalParameter<"unsigned">:$line, + OptionalParameter<"unsigned">:$arg, + OptionalParameter<"unsigned">:$alignInBits, + OptionalParameter<"DITypeAttr">:$type ); let builders = [ AttrBuilderWithInferredContext<(ins diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td @@ -262,7 +262,7 @@ // Debug function intrinsics. // -class LLVM_DbgIntrOp : LLVM_Op { +class LLVM_DbgIntrOp : LLVM_IntrOp { let llvmBuilder = [{ llvm::Module *module = builder.GetInsertBlock()->getModule(); llvm::LLVMContext &ctx = module->getContext(); @@ -276,27 +276,34 @@ llvm::MetadataAsValue::get(ctx, llvm::DIExpression::get(ctx, llvm::None)), }); }]; + let mlirBuilder = [{ + // Drop all debug intrinsics with a non-empty debug expression. + // TODO: Stop dropping debug intrinsics once debug expressions are + // convertible to MLIR. + auto *dbgIntr = cast(inst); + if (dbgIntr->getExpression()->getNumElements() == 0) + $_builder.create<$_qualCppClassName>($_location, + $}] # argName # [{, $_var_attr($varInfo)); + }]; + let assemblyFormat = [{ + qualified($varInfo) `=` $}] # argName # + [{ `:` qualified(type($}] # argName # [{)) attr-dict + }]; } -def LLVM_DbgAddrOp : LLVM_DbgIntrOp<"dbg.addr"> { +def LLVM_DbgAddrOp : LLVM_DbgIntrOp<"dbg.addr", "addr"> { let summary = "Describe the current address of a local debug info variable."; let arguments = (ins LLVM_AnyPointer:$addr, LLVM_DILocalVariableAttr:$varInfo); - - let assemblyFormat = "qualified($varInfo) `=` $addr `:` type($addr) attr-dict"; } -def LLVM_DbgDeclareOp : LLVM_DbgIntrOp<"dbg.declare"> { +def LLVM_DbgDeclareOp : LLVM_DbgIntrOp<"dbg.declare", "addr"> { let summary = "Declare the address of a local debug info variable."; let arguments = (ins LLVM_AnyPointer:$addr, LLVM_DILocalVariableAttr:$varInfo); - - let assemblyFormat = "qualified($varInfo) `=` $addr `:` type($addr) attr-dict"; } -def LLVM_DbgValueOp : LLVM_DbgIntrOp<"dbg.value"> { +def LLVM_DbgValueOp : LLVM_DbgIntrOp<"dbg.value", "value"> { let summary = "Describe the current value of a local debug info variable."; let arguments = (ins LLVM_Type:$value, LLVM_DILocalVariableAttr:$varInfo); - - let assemblyFormat = "qualified($varInfo) `=` $value `:` type($value) attr-dict"; } // diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td @@ -234,6 +234,7 @@ // name matches the result name, by a reference to store the // result of the newly created MLIR operation to; // - $_int_attr - substituted by a call to an integer attribute matcher; + // - $_var_attr - substituted by a call to a variable 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/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp --- a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp +++ b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp @@ -372,7 +372,10 @@ SmallVector convertValues(ArrayRef values); /// Converts `value` to an integer attribute. Asserts if the conversion fails. - IntegerAttr matchIntegerAttr(Value value); + IntegerAttr matchIntegerAttr(llvm::Value *value); + + /// Converts `value` to a local variable attribute. + DILocalVariableAttr matchLocalVariableAttr(llvm::Value *value); /// Translates the debug location. Location translateLoc(llvm::DILocation *loc) { @@ -852,6 +855,12 @@ } Value Importer::convertValue(llvm::Value *value) { + // A value may be wrapped as metadata, for example, when passed to a debug + // intrinsic. Unwrap these values before the conversion. + if (auto *nodeAsVal = dyn_cast(value)) + if (auto *node = dyn_cast(nodeAsVal->getMetadata())) + value = node->getValue(); + // Return the mapped value if it has been converted before. if (valueMapping.count(value)) return lookupValue(value); @@ -872,14 +881,20 @@ return remapped; } -IntegerAttr Importer::matchIntegerAttr(Value value) { +IntegerAttr Importer::matchIntegerAttr(llvm::Value *value) { IntegerAttr integerAttr; - bool success = matchPattern(value, m_Constant(&integerAttr)); + bool success = matchPattern(convertValue(value), m_Constant(&integerAttr)); assert(success && "expected a constant value"); (void)success; return integerAttr; } +DILocalVariableAttr Importer::matchLocalVariableAttr(llvm::Value *value) { + auto *nodeAsVal = cast(value); + auto *node = cast(nodeAsVal->getMetadata()); + return debugImporter.translate(node); +} + LogicalResult Importer::convertBranchArgs(llvm::Instruction *branch, llvm::BasicBlock *target, SmallVectorImpl &blockArguments) { diff --git a/mlir/test/Dialect/LLVMIR/debuginfo.mlir b/mlir/test/Dialect/LLVMIR/debuginfo.mlir --- a/mlir/test/Dialect/LLVMIR/debuginfo.mlir +++ b/mlir/test/Dialect/LLVMIR/debuginfo.mlir @@ -81,16 +81,16 @@ file = #file, line = 4, scopeLine = 4, subprogramFlags = "Definition", type = #spType1 > -// CHECK-DAG: #[[VAR0:.*]] = #llvm.di_local_variable +// CHECK-DAG: #[[VAR0:.*]] = #llvm.di_local_variable #var0 = #llvm.di_local_variable< - scope = #sp0, name = "arg", file = #file, - line = 6, arg = 1, alignInBits = 0, type = #int0 + scope = #sp0, name = "alloc", file = #file, + line = 6, arg = 1, alignInBits = 32, type = #int0 > -// CHECK-DAG: #[[VAR1:.*]] = #llvm.di_local_variable +// CHECK-DAG: #[[VAR1:.*]] = #llvm.di_local_variable #var1 = #llvm.di_local_variable< - scope = #sp1, name = "arg", file = #file, - line = 7, arg = 2, alignInBits = 0, type = #int1 + // Omit the optional parameters. + scope = #sp1, name = "arg" > // CHECK: llvm.func @addr(%[[ARG:.*]]: i64) @@ -99,16 +99,16 @@ %allocCount = llvm.mlir.constant(1 : i32) : i32 %alloc = llvm.alloca %allocCount x i64 : (i32) -> !llvm.ptr - // CHECK: llvm.dbg.addr #[[VAR0]] = %[[ALLOC]] - // CHECK: llvm.dbg.declare #[[VAR0]] = %[[ALLOC]] - llvm.dbg.addr #var0 = %alloc : !llvm.ptr - llvm.dbg.declare #var0 = %alloc : !llvm.ptr + // CHECK: llvm.intr.dbg.addr #[[VAR0]] = %[[ALLOC]] + // CHECK: llvm.intr.dbg.declare #[[VAR0]] = %[[ALLOC]] + llvm.intr.dbg.addr #var0 = %alloc : !llvm.ptr + llvm.intr.dbg.declare #var0 = %alloc : !llvm.ptr llvm.return } // CHECK: llvm.func @value(%[[ARG:.*]]: i32) llvm.func @value(%arg: i32) -> i32 { - // CHECK: llvm.dbg.value #[[VAR1]] = %[[ARG]] - llvm.dbg.value #var1 = %arg : i32 + // CHECK: llvm.intr.dbg.value #[[VAR1]] = %[[ARG]] + llvm.intr.dbg.value #var1 = %arg : i32 llvm.return %arg : i32 } diff --git a/mlir/test/Target/LLVMIR/Import/debug-info.ll b/mlir/test/Target/LLVMIR/Import/debug-info.ll --- a/mlir/test/Target/LLVMIR/Import/debug-info.ll +++ b/mlir/test/Target/LLVMIR/Import/debug-info.ll @@ -226,3 +226,43 @@ ; Verify the module location is set to the source filename. ; CHECK: loc("debug-info.ll":0:0) source_filename = "debug-info.ll" + +; // ----- + +; CHECK: #[[$SP:.+]] = #llvm.di_subprogram< +; CHECK: #[[$VAR0:.+]] = #llvm.di_local_variable +; CHECK: #[[$VAR1:.+]] = #llvm.di_local_variable + +; CHECK-LABEL: @intrinsic +; CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]] +; CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]] +define void @intrinsic(i64 %0, ptr %1) { + ; CHECK: llvm.intr.dbg.value #[[$VAR0]] = %[[ARG0]] : i64 loc(#[[LOC0:.+]]) + call void @llvm.dbg.value(metadata i64 %0, metadata !5, metadata !DIExpression()), !dbg !7 + ; CHECK: llvm.intr.dbg.addr #[[$VAR1]] = %[[ARG1]] : !llvm.ptr loc(#[[LOC1:.+]]) + call void @llvm.dbg.addr(metadata ptr %1, metadata !6, metadata !DIExpression()), !dbg !8 + ; CHECK: llvm.intr.dbg.declare #[[$VAR1]] = %[[ARG1]] : !llvm.ptr loc(#[[LOC2:.+]]) + call void @llvm.dbg.declare(metadata ptr %1, metadata !6, metadata !DIExpression()), !dbg !9 + ret void +} + +; CHECK: #[[LOC0]] = loc(fused<#[[$SP]]>["debug-info.ll":1:2]) +; CHECK: #[[LOC1]] = loc(fused<#[[$SP]]>["debug-info.ll":2:2]) +; CHECK: #[[LOC2]] = loc(fused<#[[$SP]]>["debug-info.ll":3:2]) + +declare void @llvm.dbg.value(metadata, metadata, metadata) +declare void @llvm.dbg.addr(metadata, metadata, metadata) +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!1} +!llvm.module.flags = !{!0} +!0 = !{i32 2, !"Debug Info Version", i32 3} +!1 = distinct !DICompileUnit(language: DW_LANG_C, file: !2) +!2 = !DIFile(filename: "debug-info.ll", directory: "/") +!3 = distinct !DISubprogram(name: "intrinsic", scope: !2, file: !2, line: 42, scopeLine: 42, spFlags: DISPFlagDefinition, unit: !1) +!4 = !DIBasicType(name: "int") +!5 = !DILocalVariable(scope: !3, name: "arg", file: !2, line: 1, arg: 1, align: 32, type: !4); +!6 = !DILocalVariable(scope: !3, name: "arg") +!7 = !DILocation(line: 1, column: 2, scope: !3) +!8 = !DILocation(line: 2, column: 2, scope: !3) +!9 = !DILocation(line: 3, column: 2, scope: !3) diff --git a/mlir/test/Target/LLVMIR/llvmir-debug.mlir b/mlir/test/Target/LLVMIR/llvmir-debug.mlir --- a/mlir/test/Target/LLVMIR/llvmir-debug.mlir +++ b/mlir/test/Target/LLVMIR/llvmir-debug.mlir @@ -64,6 +64,7 @@ > #fileScope = #llvm.di_lexical_block_file #variable = #llvm.di_local_variable +#variableAddr = #llvm.di_local_variable // CHECK-LABEL: define void @func_with_debug( // CHECK-SAME: i64 %[[ARG:.*]]) !dbg ![[FUNC_LOC:[0-9]+]] @@ -73,11 +74,11 @@ %alloc = llvm.alloca %allocCount x i64 : (i32) -> !llvm.ptr // CHECK: call void @llvm.dbg.value(metadata i64 %[[ARG]], metadata ![[VAR_LOC:[0-9]+]], metadata !DIExpression()) - // CHECK: call void @llvm.dbg.addr(metadata ptr %[[ALLOC]], metadata ![[VAR_LOC]], metadata !DIExpression()) - // CHECK: call void @llvm.dbg.declare(metadata ptr %[[ALLOC]], metadata ![[VAR_LOC]], metadata !DIExpression()) - llvm.dbg.value #variable = %arg : i64 - llvm.dbg.addr #variable = %alloc : !llvm.ptr - llvm.dbg.declare #variable = %alloc : !llvm.ptr + // CHECK: call void @llvm.dbg.addr(metadata ptr %[[ALLOC]], metadata ![[ADDR_LOC:[0-9]+]], metadata !DIExpression()) + // CHECK: call void @llvm.dbg.declare(metadata ptr %[[ALLOC]], metadata ![[ADDR_LOC]], metadata !DIExpression()) + llvm.intr.dbg.value #variable = %arg : i64 + llvm.intr.dbg.addr #variableAddr = %alloc : !llvm.ptr + llvm.intr.dbg.declare #variableAddr = %alloc : !llvm.ptr // CHECK: call void @func_no_debug(), !dbg ![[CALLSITE_LOC:[0-9]+]] llvm.call @func_no_debug() : () -> () loc(callsite("mysource.cc":3:4 at "mysource.cc":5:6)) @@ -116,6 +117,7 @@ // CHECK: ![[VAR_LOC]] = !DILocalVariable(name: "arg", arg: 1, scope: ![[VAR_SCOPE:.*]], file: ![[CU_FILE_LOC]], line: 6, type: ![[ARG_TYPE]]) // CHECK: ![[VAR_SCOPE]] = distinct !DILexicalBlockFile(scope: ![[FUNC_LOC]], file: ![[CU_FILE_LOC]], discriminator: 0) +// CHECK: ![[ADDR_LOC]] = !DILocalVariable(name: "alloc", scope: ![[VAR_SCOPE:.*]]) // CHECK-DAG: ![[CALLSITE_LOC]] = !DILocation(line: 3, column: 4, // CHECK-DAG: ![[FILE_LOC]] = !DILocation(line: 1, column: 2, diff --git a/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp b/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp --- a/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp +++ b/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp @@ -237,18 +237,24 @@ return emitError( record, "expected non-negative operand index for argument " + name); } - bool isVariadicOperand = isVariadicOperandName(op, name); - auto result = - isVariadicOperand - ? formatv("convertValues(llvmOperands.drop_front({0}))", idx) - : formatv("convertValue(llvmOperands[{0}])", idx); - bs << result; + if (isAttributeName(op, name)) { + bs << formatv("llvmOperands[{0}]", idx); + } else { + bool isVariadicOperand = isVariadicOperandName(op, name); + auto result = + isVariadicOperand + ? formatv("convertValues(llvmOperands.drop_front({0}))", idx) + : formatv("convertValue(llvmOperands[{0}])", idx); + bs << result; + } } else if (isResultName(op, name)) { if (op.getNumResults() != 1) return emitError(record, "expected op to have one result"); bs << formatv("mapValue(inst)"); } else if (name == "_int_attr") { bs << "matchIntegerAttr"; + } else if (name == "_var_attr") { + bs << "matchLocalVariableAttr"; } else if (name == "_resultType") { bs << "convertType(inst->getType())"; } else if (name == "_location") {