diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -5183,6 +5183,10 @@ - ``DW_OP_push_object_address`` pushes the address of the object which can then serve as a descriptor in subsequent calculation. This opcode can be used to calculate bounds of fortran allocatable array which has array descriptors. +- ``DW_OP_LLVM_implicit_pointer, N`` can only appear at the + beginning of a ``DIExpression``, and it specifies the value of variable + represented by the ``DILocalVariable`` referred to by the instructions + value/address operand at offset N. DWARF specifies three kinds of simple location descriptions: Register, memory, and implicit location descriptions. Note that a location description is diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.h b/llvm/include/llvm/BinaryFormat/Dwarf.h --- a/llvm/include/llvm/BinaryFormat/Dwarf.h +++ b/llvm/include/llvm/BinaryFormat/Dwarf.h @@ -118,10 +118,11 @@ #include "llvm/BinaryFormat/Dwarf.def" DW_OP_lo_user = 0xe0, DW_OP_hi_user = 0xff, - DW_OP_LLVM_fragment = 0x1000, ///< Only used in LLVM metadata. - DW_OP_LLVM_convert = 0x1001, ///< Only used in LLVM metadata. - DW_OP_LLVM_tag_offset = 0x1002, ///< Only used in LLVM metadata. - DW_OP_LLVM_entry_value = 0x1003, ///< Only used in LLVM metadata. + DW_OP_LLVM_fragment = 0x1000, ///< Only used in LLVM metadata. + DW_OP_LLVM_convert = 0x1001, ///< Only used in LLVM metadata. + DW_OP_LLVM_tag_offset = 0x1002, ///< Only used in LLVM metadata. + DW_OP_LLVM_entry_value = 0x1003, ///< Only used in LLVM metadata. + DW_OP_LLVM_implicit_pointer = 0x1004, ///< Only used in LLVM metadata. }; enum TypeKind : uint8_t { diff --git a/llvm/lib/BinaryFormat/Dwarf.cpp b/llvm/lib/BinaryFormat/Dwarf.cpp --- a/llvm/lib/BinaryFormat/Dwarf.cpp +++ b/llvm/lib/BinaryFormat/Dwarf.cpp @@ -151,6 +151,8 @@ return "DW_OP_LLVM_tag_offset"; case DW_OP_LLVM_entry_value: return "DW_OP_LLVM_entry_value"; + case DW_OP_LLVM_implicit_pointer: + return "DW_OP_LLVM_implicit_pointer"; } } @@ -163,6 +165,7 @@ .Case("DW_OP_LLVM_fragment", DW_OP_LLVM_fragment) .Case("DW_OP_LLVM_tag_offset", DW_OP_LLVM_tag_offset) .Case("DW_OP_LLVM_entry_value", DW_OP_LLVM_entry_value) + .Case("DW_OP_LLVM_implicit_pointer", DW_OP_LLVM_implicit_pointer) .Default(0); } diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -2232,6 +2232,8 @@ if (I->getOp() == dwarf::DW_OP_LLVM_convert) { Out << FS << I->getArg(0); Out << FS << dwarf::AttributeEncodingString(I->getArg(1)); + } else if (I->getOp() == dwarf::DW_OP_LLVM_implicit_pointer) { + Out << FS << I->getArg(0); } else { for (unsigned A = 0, AE = I->getNumArgs(); A != AE; ++A) Out << FS << I->getArg(A); diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -964,6 +964,7 @@ case dwarf::DW_OP_LLVM_tag_offset: case dwarf::DW_OP_LLVM_entry_value: case dwarf::DW_OP_regx: + case dwarf::DW_OP_LLVM_implicit_pointer: return 2; default: return 1; @@ -1018,6 +1019,11 @@ return I->get() == expr_op_begin()->get() && I->getArg(0) == 1 && getNumElements() == 2; } + case dwarf::DW_OP_LLVM_implicit_pointer: { + // A DW_OP_LLVM_implicit_pointer operator must appear at the beginning + // and it has one argument. + return (I == expr_op_begin()) && (getNumElements() == 2); + } case dwarf::DW_OP_LLVM_convert: case dwarf::DW_OP_LLVM_tag_offset: case dwarf::DW_OP_constu: diff --git a/llvm/test/DebugInfo/X86/LLVM_implicit_pointer.ll b/llvm/test/DebugInfo/X86/LLVM_implicit_pointer.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/X86/LLVM_implicit_pointer.ll @@ -0,0 +1,76 @@ +; Round trip test for DW_OP_LLVM_implicit_pointer metadata + +; RUN: llvm-as < %s | llvm-dis | FileCheck %s + +; CHECK: !DIExpression(DW_OP_LLVM_implicit_pointer, 0) + +;--------------------------- +;static const char *b = "opq"; +;volatile int v; +;int main() { +; int var1 = 4; +; int *ptr1; +; +; v++; +; ptr1 = &var1; +; v++; +; +; return *ptr1 - 5; +;} +;--------------------------- + +; ModuleID = 'LLVM_implicit_pointer.c' +source_filename = "LLVM_implicit_pointer.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@v = common dso_local global i32 0, align 4, !dbg !0 +; Function Attrs: nofree norecurse nounwind uwtable +define dso_local i32 @main() local_unnamed_addr !dbg !12 { +entry: + call void @llvm.dbg.value(metadata i32 4, metadata !16, metadata !DIExpression()), !dbg !19 + %0 = load volatile i32, i32* @v, align 4, !dbg !20, !tbaa !21 + %inc = add nsw i32 %0, 1, !dbg !20 + store volatile i32 %inc, i32* @v, align 4, !dbg !20, !tbaa !21 + + call void @llvm.dbg.value(metadata i32 4, metadata !17, metadata !DIExpression(DW_OP_LLVM_implicit_pointer, 0)), !dbg !19 + + %1 = load volatile i32, i32* @v, align 4, !dbg !25, !tbaa !21 + %inc1 = add nsw i32 %1, 1, !dbg !25 + store volatile i32 %inc1, i32* @v, align 4, !dbg !25, !tbaa !21 + ret i32 -1, !dbg !26 +} +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "v", scope: !2, file: !3, line: 2, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "LLVM_implicit_pointer.c", directory: "/dir", checksumkind: CSK_MD5, checksum: "218aaa8dc9f04b056b56d944d06383dd") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !7) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !{i32 7, !"Dwarf Version", i32 5} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 10.0.0"} +!12 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 3, type: !13, scopeLine: 3, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !15) +!13 = !DISubroutineType(types: !14) +!14 = !{!7} +!15 = !{!16, !17} +!16 = !DILocalVariable(name: "var1", scope: !12, file: !3, line: 4, type: !7) +!17 = !DILocalVariable(name: "ptr1", scope: !12, file: !3, line: 5, type: !18) +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!19 = !DILocation(line: 0, scope: !12) +!20 = !DILocation(line: 7, column: 4, scope: !12) +!21 = !{!22, !22, i64 0} +!22 = !{!"int", !23, i64 0} +!23 = !{!"omnipotent char", !24, i64 0} +!24 = !{!"Simple C/C++ TBAA"} +!25 = !DILocation(line: 9, column: 4, scope: !12) +!26 = !DILocation(line: 11, column: 3, scope: !12)