Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -5272,6 +5272,31 @@ of the stack. This opcode can be used to calculate bounds of fortran assumed rank array which has rank known at run time and current dimension number is implicitly first element of the stack. +- ``DW_OP_LLVM_implicit_pointer`` It specifies the dereferenced value. It can + be used to represent pointer variables which are optimized out but the value + it points to is known. + +.. code-block:: text + + IR for "*ptr = 4;" + -------------- + call void @llvm.dbg.value(metadata i32 4, metadata !17, metadata !20) + !17 = !DILocalVariable(name: "ptr1", scope: !12, file: !3, line: 5, + type: !18) + !18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) + !19 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !20 = !DIExpression(DW_OP_LLVM_implicit_pointer)) + + IR for "**ptr = 4;" + -------------- + call void @llvm.dbg.value(metadata i32 4, metadata !17, metadata !21) + !17 = !DILocalVariable(name: "ptr1", scope: !12, file: !3, line: 5, + type: !18) + !18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) + !19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) + !20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !21 = !DIExpression(DW_OP_LLVM_implicit_pointer, + DW_OP_LLVM_implicit_pointer)) DWARF specifies three kinds of simple location descriptions: Register, memory, and implicit location descriptions. Note that a location description is Index: llvm/include/llvm/BinaryFormat/Dwarf.h =================================================================== --- llvm/include/llvm/BinaryFormat/Dwarf.h +++ llvm/include/llvm/BinaryFormat/Dwarf.h @@ -120,10 +120,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 { Index: llvm/lib/BinaryFormat/Dwarf.cpp =================================================================== --- llvm/lib/BinaryFormat/Dwarf.cpp +++ 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); } Index: llvm/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/lib/IR/DebugInfoMetadata.cpp +++ llvm/lib/IR/DebugInfoMetadata.cpp @@ -1114,6 +1114,7 @@ return I->get() == expr_op_begin()->get() && I->getArg(0) == 1 && getNumElements() == 2; } + case dwarf::DW_OP_LLVM_implicit_pointer: case dwarf::DW_OP_LLVM_convert: case dwarf::DW_OP_LLVM_tag_offset: case dwarf::DW_OP_constu: Index: llvm/test/DebugInfo/X86/LLVM_implicit_pointer.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/LLVM_implicit_pointer.ll @@ -0,0 +1,87 @@ +; Round trip test for DW_OP_LLVM_implicit_pointer metadata + +; RUN: llvm-as < %s | llvm-dis | FileCheck %s + +;--------------------------- +;static const char *b = "opq"; +;volatile int v; +;int main() { +; int var = 4; +; int *ptr1; +; int **ptr2; +; +; v++; +; ptr1 = &var; +; ptr2 = &ptr1; +; v++; +; +; return *ptr1 - 5 + **ptr2; +;} +;--------------------------- + +; 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 = 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: +; CHECK: call void @llvm.dbg.value(metadata i32 4, metadata [[VAR:![0-9]+]], metadata !DIExpression()) + call void @llvm.dbg.value(metadata i32 4, metadata !16, metadata !DIExpression()), !dbg !21 + %0 = load volatile i32, i32* @v, align 4, !dbg !22, !tbaa !23 + %inc = add nsw i32 %0, 1, !dbg !22 + store volatile i32 %inc, i32* @v, align 4, !dbg !22, !tbaa !23 + +; CHECK: call void @llvm.dbg.value(metadata i32 4, metadata [[PTR1:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_implicit_pointer)) + call void @llvm.dbg.value(metadata i32 4, metadata !17, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !21 + +; CHECK: call void @llvm.dbg.value(metadata i32 4, metadata [[PTR2:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_implicit_pointer)) + call void @llvm.dbg.value(metadata i32 4, metadata !19, metadata !DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_implicit_pointer)), !dbg !21 + %1 = load volatile i32, i32* @v, align 4, !dbg !27, !tbaa !23 + %inc1 = add nsw i32 %1, 1, !dbg !27 + store volatile i32 %inc1, i32* @v, align 4, !dbg !27, !tbaa !23 + ret i32 3, !dbg !28 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +!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 12.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 12.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, !19} +; CHECK: [[VAR]] = !DILocalVariable(name: "var" +!16 = !DILocalVariable(name: "var", scope: !12, file: !3, line: 4, type: !7) +; CHECK: [[PTR1]] = !DILocalVariable(name: "ptr1" +!17 = !DILocalVariable(name: "ptr1", scope: !12, file: !3, line: 5, type: !18) +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +; CHECK: [[PTR2]] = !DILocalVariable(name: "ptr2" +!19 = !DILocalVariable(name: "ptr2", scope: !12, file: !3, line: 6, type: !20) +!20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64) +!21 = !DILocation(line: 0, scope: !12) +!22 = !DILocation(line: 8, column: 4, scope: !12) +!23 = !{!24, !24, i64 0} +!24 = !{!"int", !25, i64 0} +!25 = !{!"omnipotent char", !26, i64 0} +!26 = !{!"Simple C/C++ TBAA"} +!27 = !DILocation(line: 11, column: 4, scope: !12) +!28 = !DILocation(line: 13, column: 3, scope: !12)