Index: llvm/include/llvm/CodeGen/SelectionDAG.h =================================================================== --- llvm/include/llvm/CodeGen/SelectionDAG.h +++ llvm/include/llvm/CodeGen/SelectionDAG.h @@ -1309,6 +1309,11 @@ unsigned VReg, bool IsIndirect, const DebugLoc &DL, unsigned O); + /// Creates an Implicit Pointer SDDbgValue node. + SDDbgValue *getImpPtrDbgValue(DIVariable *Var, DIExpression *Expr, + DIVariable *Val, const DebugLoc &DL, + unsigned O); + /// Creates a SDDbgLabel node. SDDbgLabel *getDbgLabel(DILabel *Label, const DebugLoc &DL, unsigned O); Index: llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp +++ llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp @@ -744,6 +744,10 @@ // dropped. MIB.addReg(0U); } + } else if (SD->getKind() == SDDbgValue::IMPPTR) { + const MDNode *DV = SD->getImplicitPointer(); + // insert implicit pointer + MIB.addMetadata(DV, /* IsImplicitPointer */ true); } else { // Insert an Undef so we can see what we dropped. MIB.addReg(0U); Index: llvm/lib/CodeGen/SelectionDAG/SDNodeDbgValue.h =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SDNodeDbgValue.h +++ llvm/lib/CodeGen/SelectionDAG/SDNodeDbgValue.h @@ -33,7 +33,8 @@ SDNODE = 0, ///< Value is the result of an expression. CONST = 1, ///< Value is a constant. FRAMEIX = 2, ///< Value is contents of a stack location. - VREG = 3 ///< Value is a virtual register. + VREG = 3, ///< Value is a virtual register. + IMPPTR = 4 ///< Value is an implicit pointer. }; private: union { @@ -44,6 +45,7 @@ const Value *Const; ///< Valid for constants. unsigned FrameIx; ///< Valid for stack objects. unsigned VReg; ///< Valid for registers. + DIVariable *ImpPtr; } u; DIVariable *Var; DIExpression *Expr; @@ -86,6 +88,14 @@ u.FrameIx = VRegOrFrameIdx; } + /// Constructor for Implicit Pointer. + SDDbgValue(DIVariable *Var, DIExpression *Expr, DIVariable *Val, DebugLoc dl, + unsigned O) + : Var(Var), Expr(Expr), DL(std::move(dl)), Order(O), IsIndirect(false) { + kind = IMPPTR; + u.ImpPtr = Val; + } + /// Returns the kind. DbgValueKind getKind() const { return kind; } @@ -110,6 +120,12 @@ /// Returns the Virtual Register for a VReg unsigned getVReg() const { assert (kind==VREG); return u.VReg; } + /// Returns the implicit pointer target + DIVariable *getImplicitPointer() const { + assert(kind == IMPPTR); + return u.ImpPtr; + } + /// Returns whether this is an indirect value. bool isIndirect() const { return IsIndirect; } Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -8018,6 +8018,15 @@ SDDbgValue(Var, Expr, VReg, IsIndirect, DL, O, SDDbgValue::VREG); } +/// Implicit pointer +SDDbgValue *SelectionDAG::getImpPtrDbgValue(DIVariable *Var, DIExpression *Expr, + DIVariable *Val, const DebugLoc &DL, + unsigned O) { + assert(cast(Var)->isValidLocationForIntrinsic(DL) && + "Expected inlined-at fields to agree"); + return new (DbgInfo->getAlloc()) SDDbgValue(Var, Expr, Val, DL, O); +} + void SelectionDAG::transferDbgValues(SDValue From, SDValue To, unsigned OffsetInBits, unsigned SizeInBits, bool InvalidateDbg) { Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -1277,6 +1277,13 @@ return true; } + if (const llvm::MetadataAsValue *MDV = dyn_cast(V)) { + if (DILocalVariable *DLV = dyn_cast(MDV->getMetadata())) { + SDV = DAG.getImpPtrDbgValue(Var, Expr, DLV, dl, SDNodeOrder); + DAG.AddDbgValue(SDV, nullptr, false); + return true; + } + } // If the Value is a frame index, we can create a FrameIndex debug value // without relying on the DAG at all. if (const AllocaInst *AI = dyn_cast(V)) { Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -769,6 +769,11 @@ case VREG: OS << "(VREG=" << getVReg() << ')'; break; + case IMPPTR: + // implicit pointer will be printed as + // DbgVal(Order=1)(IMPPTR=arr):"ptr"!DIExpression(DW_OP_implicit_pointer, 0) + OS << "(IMPPTR=" << u.ImpPtr->getName() << ')'; + break; } if (isIndirect()) OS << "(Indirect)"; OS << ":\"" << Var->getName() << '"'; Index: llvm/test/DebugInfo/dwarfdump-implicit_pointer_instcomb.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/dwarfdump-implicit_pointer_instcomb.ll @@ -0,0 +1,108 @@ +; RUN: llc %s -O2 -filetype=obj -o %t.o +; RUN: llvm-dwarfdump %t.o | FileCheck %s + +; CHECK-LABEL: DW_AT_name ("var") +; CHECK-LABEL: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_implicit_pointer [[DIE:0x.+]] +0 + +; CHECK-LABEL: DW_TAG_formal_parameter +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_implicit_pointer [[DIE]] +0 +; CHECK-NEXT: "ptr" + +; Below is the original test case this IR is generated from +;--------------------------- +;volatile int gvar = 7; +; +;int func(int *ptr) { +; gvar = *ptr; +; return *ptr + 5; +;} +; +;int main() { +; int var = 4; +; int *ptrVar = &var; +; +; int res = func(ptrVar); +; +; return res; +;} +;--------------------------- + +; ModuleID = 'dwarfdump-implicit_pointer_instcomb.c' +source_filename = "dwarfdump-implicit_pointer_instcomb.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" + +@gvar = dso_local global i32 7, align 4, !dbg !0 + +; Function Attrs: nofree norecurse nounwind uwtable +define dso_local i32 @func(i32* nocapture readonly %ptr) local_unnamed_addr #0 !dbg !12 { +entry: + call void @llvm.dbg.value(metadata i32* %ptr, metadata !17, metadata !DIExpression()), !dbg !18 + %0 = load i32, i32* %ptr, align 4, !dbg !19 + store volatile i32 %0, i32* @gvar, align 4, !dbg !24 + %1 = load i32, i32* %ptr, align 4, !dbg !25 + %add = add nsw i32 %1, 5, !dbg !26 + ret i32 %add, !dbg !27 +} + +; Function Attrs: nounwind uwtable +define dso_local i32 @main() local_unnamed_addr #1 !dbg !28 { +entry: + call void @llvm.dbg.value(metadata i32 4, metadata !32, metadata !DIExpression()), !dbg !35 + call void @llvm.dbg.value(metadata !32, metadata !33, metadata !DIExpression(DW_OP_implicit_pointer, 0)), !dbg !35 + call void @llvm.dbg.value(metadata !32, metadata !17, metadata !DIExpression(DW_OP_implicit_pointer, 0)), !dbg !36 + store volatile i32 4, i32* @gvar, align 4, !dbg !38 + call void @llvm.dbg.value(metadata i32 9, metadata !34, metadata !DIExpression()), !dbg !35 + ret i32 9, !dbg !39 +} + +; 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: "gvar", scope: !2, file: !3, line: 14, 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, nameTableKind: None) +!3 = !DIFile(filename: "dwarfdump-implicit_pointer_instcomb.c", directory: "/dir", checksumkind: CSK_MD5, checksum: "1c991e568deb5a6321b60bc8bf8be8d6") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !7) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !{i32 2, !"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: "func", scope: !3, file: !3, line: 16, type: !13, scopeLine: 16, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !16) +!13 = !DISubroutineType(types: !14) +!14 = !{!7, !15} +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!16 = !{!17} +!17 = !DILocalVariable(name: "ptr", arg: 1, scope: !12, file: !3, line: 16, type: !15) +!18 = !DILocation(line: 0, scope: !12) +!19 = !DILocation(line: 17, column: 10, scope: !12) +!20 = !{!21, !21, i64 0} +!21 = !{!"int", !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 17, column: 8, scope: !12) +!25 = !DILocation(line: 18, column: 10, scope: !12) +!26 = !DILocation(line: 18, column: 15, scope: !12) +!27 = !DILocation(line: 18, column: 3, scope: !12) +!28 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 21, type: !29, scopeLine: 21, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !31) +!29 = !DISubroutineType(types: !30) +!30 = !{!7} +!31 = !{!32, !33, !34} +!32 = !DILocalVariable(name: "var", scope: !28, file: !3, line: 22, type: !7) +!33 = !DILocalVariable(name: "ptrVar", scope: !28, file: !3, line: 23, type: !15) +!34 = !DILocalVariable(name: "res", scope: !28, file: !3, line: 25, type: !7) +!35 = !DILocation(line: 0, scope: !28) +!36 = !DILocation(line: 0, scope: !12, inlinedAt: !37) +!37 = distinct !DILocation(line: 25, column: 13, scope: !28) +!38 = !DILocation(line: 17, column: 8, scope: !12, inlinedAt: !37) +!39 = !DILocation(line: 27, column: 3, scope: !28) Index: llvm/test/DebugInfo/dwarfdump-implicit_pointer_mem2reg.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/dwarfdump-implicit_pointer_mem2reg.ll @@ -0,0 +1,147 @@ +; RUN: llc %s -O2 -filetype=obj -o %t.o +; RUN: llvm-dwarfdump %t.o | FileCheck %s + +; CHECK-LABEL: DW_AT_name ("arr1") + +; 1. Test if more than one member location list is printed +; (for pointer to scalar) +; CHECK-LABEL: DW_AT_location ( +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_implicit_pointer {{0x.+}} +0 +; CHECK-NEXT: DW_AT_name ("ptr2") + +; 2. Test if More than one member location list is printed +; (for pointer to pointer to scalar) +; CHECK-LABEL: DW_AT_location ( +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_implicit_pointer {{0x.+}} +0 +; CHECK-NEXT: DW_AT_name ("ptrptr2") + +; 3. Test if one member location list is printed +; (for pointer to pointer to array) +; CHECK-LABEL: DW_AT_location ( +; CHECK-NEXT: : DW_OP_implicit_pointer {{0x.+}} +0 +; CHECK-NEXT: DW_AT_name ("ptrptr3") +; +; 4. Test if one member location list is printed +; (for pointer to pointer to scalar) +; CHECK-LABEL: DW_AT_location ( +; CHECK-NEXT: : DW_OP_implicit_pointer {{0x.+}} +0 +; CHECK-NEXT: DW_AT_name ("ptrptr1") + +; 5. Test if one member location list is printed +; (for pointer to array) +; CHECK-LABEL: DW_AT_location ( +; CHECK-NEXT: : DW_OP_implicit_pointer {{0x.+}} +0 +; CHECK-NEXT: DW_AT_name ("ptr3") + +; 6. Test if one member location list is printed +; (for pointer to scalar) +; CHECK-LABEL: DW_AT_location ( +; CHECK-NEXT: : DW_OP_implicit_pointer {{0x.+}} +0 +; CHECK-NEXT: DW_AT_name ("ptr1") + +; Below is the original test case this IR is generated from +;--------------------------- +;static const char *b = "opq"; +;volatile int v; +;int main() { +; int var1 = 4; +; int var2 = 5; +; int arr1[2] = {2, 3}; +; int *ptr1; +; int *ptr2 = 0; +; int *ptr3; +; int **ptrptr1; +; int **ptrptr2 = 0; +; int **ptrptr3; +; +; v++; +; ptr1 = &var1; +; ptr2 = &var2; +; ptr3 = arr1; +; ptrptr1 = &ptr1; +; ptrptr2 = &ptr2; +; ptrptr3 = &ptr3; +; v++; +; +; return arr1[0] + arr1[1] + *ptr1 + *ptr2 + **ptrptr1 + **ptrptr2 - 5; +;} +;--------------------------- + +; ModuleID = 'dwarfdump-implicit_pointer_mem2reg.c' +source_filename = "dwarfdump-implicit_pointer_mem2reg.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 #0 !dbg !12 { +entry: + call void @llvm.dbg.value(metadata i32 4, metadata !16, metadata !DIExpression()), !dbg !30 + call void @llvm.dbg.value(metadata i32 5, metadata !17, metadata !DIExpression()), !dbg !30 + call void @llvm.dbg.value(metadata i32 2, metadata !18, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !30 + call void @llvm.dbg.value(metadata i32 3, metadata !18, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)), !dbg !30 + call void @llvm.dbg.value(metadata i32* null, metadata !24, metadata !DIExpression()), !dbg !30 + call void @llvm.dbg.value(metadata i32** null, metadata !28, metadata !DIExpression()), !dbg !30 + %0 = load volatile i32, i32* @v, align 4, !dbg !31 + %inc = add nsw i32 %0, 1, !dbg !31 + store volatile i32 %inc, i32* @v, align 4, !dbg !31 + call void @llvm.dbg.value(metadata !16, metadata !22, metadata !DIExpression(DW_OP_implicit_pointer, 0)), !dbg !30 + call void @llvm.dbg.value(metadata !17, metadata !24, metadata !DIExpression(DW_OP_implicit_pointer, 0)), !dbg !30 + call void @llvm.dbg.value(metadata !18, metadata !25, metadata !DIExpression(DW_OP_implicit_pointer, 0)), !dbg !30 + call void @llvm.dbg.value(metadata !22, metadata !26, metadata !DIExpression(DW_OP_implicit_pointer, 0)), !dbg !30 + call void @llvm.dbg.value(metadata !24, metadata !28, metadata !DIExpression(DW_OP_implicit_pointer, 0)), !dbg !30 + call void @llvm.dbg.value(metadata !25, metadata !29, metadata !DIExpression(DW_OP_implicit_pointer, 0)), !dbg !30 + %1 = load volatile i32, i32* @v, align 4, !dbg !36 + %inc1 = add nsw i32 %1, 1, !dbg !36 + store volatile i32 %inc1, i32* @v, align 4, !dbg !36 + ret i32 18, !dbg !37 +} + +; 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: 45, 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, nameTableKind: None) +!3 = !DIFile(filename: "dwarfdump-implicit_pointer_mem2reg.c", directory: "/dir", checksumkind: CSK_MD5, checksum: "6ad1488ed7a007c3a33e08ec42847d87") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !7) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !{i32 2, !"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: 46, type: !13, scopeLine: 46, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !15) +!13 = !DISubroutineType(types: !14) +!14 = !{!7} +!15 = !{!16, !17, !18, !22, !24, !25, !26, !28, !29} +!16 = !DILocalVariable(name: "var1", scope: !12, file: !3, line: 47, type: !7) +!17 = !DILocalVariable(name: "var2", scope: !12, file: !3, line: 48, type: !7) +!18 = !DILocalVariable(name: "arr1", scope: !12, file: !3, line: 49, type: !19) +!19 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 64, elements: !20) +!20 = !{!21} +!21 = !DISubrange(count: 2) +!22 = !DILocalVariable(name: "ptr1", scope: !12, file: !3, line: 50, type: !23) +!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!24 = !DILocalVariable(name: "ptr2", scope: !12, file: !3, line: 51, type: !23) +!25 = !DILocalVariable(name: "ptr3", scope: !12, file: !3, line: 52, type: !23) +!26 = !DILocalVariable(name: "ptrptr1", scope: !12, file: !3, line: 53, type: !27) +!27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64) +!28 = !DILocalVariable(name: "ptrptr2", scope: !12, file: !3, line: 54, type: !27) +!29 = !DILocalVariable(name: "ptrptr3", scope: !12, file: !3, line: 55, type: !27) +!30 = !DILocation(line: 0, scope: !12) +!31 = !DILocation(line: 57, column: 4, scope: !12) +!32 = !{!33, !33, i64 0} +!33 = !{!"int", !34, i64 0} +!34 = !{!"omnipotent char", !35, i64 0} +!35 = !{!"Simple C/C++ TBAA"} +!36 = !DILocation(line: 64, column: 4, scope: !12) +!37 = !DILocation(line: 66, column: 3, scope: !12) Index: llvm/test/DebugInfo/dwarfdump-implicit_pointer_sroa.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/dwarfdump-implicit_pointer_sroa.ll @@ -0,0 +1,130 @@ +; RUN: llc %s -O2 -filetype=obj -o %t.o +; RUN: llvm-dwarfdump %t.o | FileCheck %s + +; CHECK-LABEL: DW_AT_name ("arr2") + +; 1. Test if more than 2 member location list is printed (for pointer pointing to aggregate) +; CHECK-LABEL: DW_AT_location ( +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_implicit_pointer [[DIE:0x.+]] +0 +; CHECK-NEXT: : DW_OP_implicit_pointer [[DIE]] +4) +; CHECK-NEXT: DW_AT_name ("ptr1") + +; 2. Test if location lists are merged to two (for pointer pointing to aggregate) +; CHECK-LABEL: DW_AT_location ( +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_implicit_pointer [[DIE]] +0 +; CHECK-NEXT: DW_AT_name ("ptr3") + +; 3. Test if one member location list is not omited (for pointer pointing to aggregate) +; CHECK-LABEL: DW_AT_location ( +; CHECK-NEXT: : DW_OP_implicit_pointer {{0x.+}} +0 +; CHECK-NEXT: DW_AT_name ("ptr2") + +; Below is the original test case this IR is generated from +;--------------------------- +;static const char *b = "opq"; +;volatile int v; +;int main() { +; int arr1[2] = {1, 2}; +; int arr2[2] = {6, 7}; +; int *ptr1 = 0; +; int *ptr2; +; int *ptr3 = 0; +; +; v++; +; ptr1 = arr1; +; ptr2 = arr2; +; ptr3 = arr1; +; (*ptr1)++; +; (*ptr2)++; +; (*ptr3)++; +; v++; +; ptr1++; +; (*ptr1)++; +; (*ptr2)++; +; (*ptr3)++; +; v++; +; return arr1[0] + arr1[1] + arr2[0] + arr2[1] - 5; +;} +;--------------------------- + +; ModuleID = 'dwarfdump-implicit_pointer_sroa.c' +source_filename = "dwarfdump-implicit_pointer_sroa.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 #0 !dbg !12 { +entry: + call void @llvm.dbg.value(metadata i32 1, metadata !16, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !25 + call void @llvm.dbg.value(metadata i32 2, metadata !16, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)), !dbg !25 + call void @llvm.dbg.value(metadata i32 6, metadata !20, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !25 + call void @llvm.dbg.value(metadata i32 7, metadata !20, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)), !dbg !25 + call void @llvm.dbg.value(metadata i32* null, metadata !21, metadata !DIExpression()), !dbg !25 + call void @llvm.dbg.value(metadata i32* null, metadata !24, metadata !DIExpression()), !dbg !25 + %0 = load volatile i32, i32* @v, align 4, !dbg !26 + %inc = add nsw i32 %0, 1, !dbg !26 + store volatile i32 %inc, i32* @v, align 4, !dbg !26 + call void @llvm.dbg.value(metadata !16, metadata !21, metadata !DIExpression(DW_OP_implicit_pointer, 0)), !dbg !25 + call void @llvm.dbg.value(metadata !20, metadata !23, metadata !DIExpression(DW_OP_implicit_pointer, 0)), !dbg !25 + call void @llvm.dbg.value(metadata !16, metadata !24, metadata !DIExpression(DW_OP_implicit_pointer, 0)), !dbg !25 + call void @llvm.dbg.value(metadata i32 2, metadata !16, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !25 + call void @llvm.dbg.value(metadata i32 7, metadata !20, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !25 + call void @llvm.dbg.value(metadata i32 3, metadata !16, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !25 + %1 = load volatile i32, i32* @v, align 4, !dbg !31 + %inc6 = add nsw i32 %1, 1, !dbg !31 + store volatile i32 %inc6, i32* @v, align 4, !dbg !31 + call void @llvm.dbg.value(metadata !16, metadata !21, metadata !DIExpression(DW_OP_implicit_pointer, 4)), !dbg !25 + call void @llvm.dbg.value(metadata i32 3, metadata !16, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)), !dbg !25 + call void @llvm.dbg.value(metadata i32 8, metadata !20, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !25 + call void @llvm.dbg.value(metadata i32 4, metadata !16, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !25 + %2 = load volatile i32, i32* @v, align 4, !dbg !32 + %inc10 = add nsw i32 %2, 1, !dbg !32 + store volatile i32 %inc10, i32* @v, align 4, !dbg !32 + ret i32 17, !dbg !33 +} + +; 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: 25, 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, nameTableKind: None) +!3 = !DIFile(filename: "dwarfdump-implicit_pointer_sroa.c", directory: "/dir", checksumkind: CSK_MD5, checksum: "955d25ccee581cfd1dc4cfad0d994e8f") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !7) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !{i32 2, !"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: 26, type: !13, scopeLine: 26, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !15) +!13 = !DISubroutineType(types: !14) +!14 = !{!7} +!15 = !{!16, !20, !21, !23, !24} +!16 = !DILocalVariable(name: "arr1", scope: !12, file: !3, line: 27, type: !17) +!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 64, elements: !18) +!18 = !{!19} +!19 = !DISubrange(count: 2) +!20 = !DILocalVariable(name: "arr2", scope: !12, file: !3, line: 28, type: !17) +!21 = !DILocalVariable(name: "ptr1", scope: !12, file: !3, line: 29, type: !22) +!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!23 = !DILocalVariable(name: "ptr2", scope: !12, file: !3, line: 30, type: !22) +!24 = !DILocalVariable(name: "ptr3", scope: !12, file: !3, line: 31, type: !22) +!25 = !DILocation(line: 0, scope: !12) +!26 = !DILocation(line: 33, column: 4, scope: !12) +!27 = !{!28, !28, i64 0} +!28 = !{!"int", !29, i64 0} +!29 = !{!"omnipotent char", !30, i64 0} +!30 = !{!"Simple C/C++ TBAA"} +!31 = !DILocation(line: 40, column: 4, scope: !12) +!32 = !DILocation(line: 45, column: 4, scope: !12) +!33 = !DILocation(line: 46, column: 3, scope: !12) Index: llvm/test/DebugInfo/dwarfdump-implicit_pointer_sroa_inline.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/dwarfdump-implicit_pointer_sroa_inline.ll @@ -0,0 +1,99 @@ +; RUN: llc %s -O2 -filetype=obj -o %t.o +; RUN: llvm-dwarfdump %t.o | FileCheck %s + +; CHECK: DW_TAG_inlined_subroutine + +; Test if More than 2 member location list is printed (for pointer pointing to aggregate) +; CHECK: DW_TAG_formal_parameter +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: : DW_OP_implicit_pointer [[DIE:0x.+]] +0 +; CHECK-NEXT: : DW_OP_implicit_pointer [[DIE]] +4) +; CHECK-NEXT: DW_AT_abstract_origin ({{0x.+}} "ptr") + +; Below is the original test case this IR is generated from +;--------------------------- +;static const char *b = "opq"; +;volatile int v; +;static inline void foo(int *ptr) { +; (*ptr)++; +; v++; +; ptr++; +; (*ptr)++; +; v++; +;} +; +;int main() { +; int arr[2] = {1, 2}; +; v++; +; foo(arr); +; return arr[0] + arr[1] - 5; +;} +;--------------------------- + +; ModuleID = 'dwarfdump-implicit_pointer_sroa_inline.c' +source_filename = "dwarfdump-implicit_pointer_sroa_inline.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: nounwind uwtable +define dso_local i32 @main() local_unnamed_addr #0 !dbg !12 { +entry: + %0 = load volatile i32, i32* @v, align 4, !dbg !20 + %inc = add nsw i32 %0, 1, !dbg !20 + store volatile i32 %inc, i32* @v, align 4, !dbg !20 + call void @llvm.dbg.value(metadata !16, metadata !25, metadata !DIExpression(DW_OP_implicit_pointer, 0)), !dbg !31 + %1 = load volatile i32, i32* @v, align 4, !dbg !33 + %inc1.i = add nsw i32 %1, 1, !dbg !33 + store volatile i32 %inc1.i, i32* @v, align 4, !dbg !33 + call void @llvm.dbg.value(metadata !16, metadata !25, metadata !DIExpression(DW_OP_implicit_pointer, 4)), !dbg !31 + %2 = load volatile i32, i32* @v, align 4, !dbg !34 + %inc3.i = add nsw i32 %2, 1, !dbg !34 + store volatile i32 %inc3.i, i32* @v, align 4, !dbg !34 + ret i32 0, !dbg !35 +} + +; 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: 14, 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, nameTableKind: None) +!3 = !DIFile(filename: "dwarfdump-implicit_pointer_sroa_inline.c", directory: "/dir", checksumkind: CSK_MD5, checksum: "f9bbaee6b152b3bc05125796b573408a") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !7) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !{i32 2, !"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: 23, type: !13, scopeLine: 23, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !15) +!13 = !DISubroutineType(types: !14) +!14 = !{!7} +!15 = !{!16} +!16 = !DILocalVariable(name: "arr", scope: !12, file: !3, line: 24, type: !17) +!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 64, elements: !18) +!18 = !{!19} +!19 = !DISubrange(count: 2) +!20 = !DILocation(line: 25, 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 = !DILocalVariable(name: "ptr", arg: 1, scope: !26, file: !3, line: 15, type: !29) +!26 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 15, type: !27, scopeLine: 15, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !30) +!27 = !DISubroutineType(types: !28) +!28 = !{null, !29} +!29 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!30 = !{!25} +!31 = !DILocation(line: 0, scope: !26, inlinedAt: !32) +!32 = distinct !DILocation(line: 26, column: 3, scope: !12) +!33 = !DILocation(line: 17, column: 4, scope: !26, inlinedAt: !32) +!34 = !DILocation(line: 20, column: 4, scope: !26, inlinedAt: !32) +!35 = !DILocation(line: 27, column: 3, scope: !12)