Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -4308,6 +4308,7 @@ ``DISubrange`` nodes are the elements for ``DW_TAG_array_type`` variants of :ref:`DICompositeType`. ``count: -1`` indicates an empty array. +``count: !3`` describes the count with a :ref:`DIExpression`. ``count: !9`` describes the count with a :ref:`DILocalVariable`. ``count: !11`` describes the count with a :ref:`DIGlobalVariable`. @@ -4317,19 +4318,22 @@ !1 = !DISubrange(count: 5, lowerBound: 1) ; array counting from 1 !2 = !DISubrange(count: -1) ; empty array. - ; Scopes used in rest of example + !3 = !DIExpression(DW_OP_constu, 42) + !4 = !DISubrange(count !3, lowerBound: 1) ; array counting from 1 to 43 + + ; Scopes !6 = !DIFile(filename: "vla.c", directory: "/path/to/file") !7 = distinct !DICompileUnit(language: DW_LANG_C99, ... !8 = distinct !DISubprogram(name: "foo", scope: !7, file: !6, line: 5, ... ; Use of local variable as count value - !9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) - !10 = !DILocalVariable(name: "count", scope: !8, file: !6, line: 42, type: !9) - !11 = !DISubrange(count !10, lowerBound: 0) + !8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !9 = !DILocalVariable(name: "count", scope: !8, file: !6, line: 42, type: !8) + !10 = !DISubrange(count !9, lowerBound: 0) ; Use of global variable as count value - !12 = !DIGlobalVariable(name: "count", scope: !8, file: !6, line: 22, type: !9) - !13 = !DISubrange(count !12, lowerBound: 0) + !11 = !DIGlobalVariable(name: "count", scope: !8, file: !6, line: 22, type: !8) + !12 = !DISubrange(count !11, lowerBound: 0) .. _DIEnumerator: Index: include/llvm/IR/DebugInfoMetadata.h =================================================================== --- include/llvm/IR/DebugInfoMetadata.h +++ include/llvm/IR/DebugInfoMetadata.h @@ -379,6 +379,10 @@ return dyn_cast(getRawCountNode()); } + DIExpression *getCountExpression() const { + return dyn_cast(getRawCountNode()); + } + static bool classof(const Metadata *MD) { return MD->getMetadataID() == DISubrangeKind; } Index: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1311,7 +1311,13 @@ if (DefaultLowerBound == -1 || LowerBound != DefaultLowerBound) addUInt(DW_Subrange, dwarf::DW_AT_lower_bound, None, LowerBound); - if (auto *CV = SR->getCountVariable()) { + if (auto *Expr = SR->getCountExpression()) { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DExpr(*Asm, *this, *Loc); + DExpr.addExpression(Expr); + DExpr.finalize(); + addBlock(DW_Subrange, dwarf::DW_AT_count, Loc); + } else if (auto *CV = SR->getCountVariable()) { // I think we can assert() here that the DIE of the count variable has // already been instantiated, since 'finishVariableDefinition' that // creates the types for a variable is always called _after_ the DIEs Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -1628,7 +1628,7 @@ if (auto *CE = N->getCount()) Printer.printInt("count", CE->getSExtValue(), /* ShouldSkipZero */ false); else - Printer.printMetadata("count", N->getCountVariable(), + Printer.printMetadata("count", N->getRawCountNode(), /*ShouldSkipNull */ false); Printer.printInt("lowerBound", N->getLowerBound()); Out << ")"; Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -860,8 +860,9 @@ AssertDI(N.getTag() == dwarf::DW_TAG_subrange_type, "invalid tag", &N); auto *CI = N.getCount(); AssertDI(!CI || CI->getSExtValue() >= -1, "invalid subrange count", &N); - AssertDI(CI || N.getCountVariable(), - "Count must either be a signed constant or a DIVariable", + AssertDI( + CI || N.getCountVariable() || N.getCountExpression(), + "Count must either be a signed constant, a DIVariable or a DIExpression", &N); } Index: test/Assembler/debug-info.ll =================================================================== --- test/Assembler/debug-info.ll +++ test/Assembler/debug-info.ll @@ -1,8 +1,8 @@ ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s ; RUN: verify-uselistorder %s -; CHECK: !named = !{!0, !0, !1, !2, !3, !4, !5, !6, !7, !8, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !27, !28, !29, !30, !31, !32, !33, !33} -!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29, !30, !31, !32, !33, !34, !35, !36, !37} +; CHECK: !named = !{!0, !0, !1, !2, !3, !4, !5, !6, !7, !8, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !27, !28, !29, !30, !31, !32, !33, !33, !34, !34, !35} +!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29, !30, !31, !32, !33, !34, !35, !36, !37, !39, !41, !43} ; CHECK: !0 = !DISubrange(count: 3) ; CHECK-NEXT: !1 = !DISubrange(count: 3, lowerBound: 4) @@ -85,3 +85,12 @@ !35 = !DIFile(filename: "file", directory: "dir", checksumkind: CSK_MD5, checksum: "000102030405060708090a0b0c0d0e0f") !36 = !DIFile(filename: "file", directory: "dir", checksumkind: CSK_None) !37 = !DIFile(filename: "file", directory: "dir", checksumkind: CSK_None, checksum: "") + +; CHECK-NEXT: !34 = !DISubrange(count: !DIExpression(DW_OP_constu, 42), lowerBound: 4) +; CHECK-NEXT: !35 = !DISubrange(count: !DIExpression(DW_OP_constu, 1)) +!38 = !DIExpression(DW_OP_constu, 42) +!39 = !DISubrange(count: !38, lowerBound: 4) +!40 = !DIExpression(DW_OP_constu, 42) +!41 = !DISubrange(count: !40, lowerBound: 4) +!42 = !DIExpression(DW_OP_constu, 1) +!43 = !DISubrange(count: !42, lowerBound: 0) Index: test/Bitcode/disubrange.ll =================================================================== --- test/Bitcode/disubrange.ll +++ test/Bitcode/disubrange.ll @@ -1,5 +1,6 @@ ; Check that the DISubrange 'count' reference is correctly uniqued and restored, -; since it can take the value of either a signed integer or a DIVariable. +; since it can take the value of either a signed integer, a DIExpression +; or a DIVariable. ; RUN: llvm-as < %s | llvm-dis | FileCheck %s define void @foo(i32 %n) { @@ -34,12 +35,13 @@ !18 = !DILocation(line: 21, column: 7, scope: !7) !19 = !DILocalVariable(name: "vla", scope: !7, file: !1, line: 21, type: !20) !20 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, align: 32, elements: !21) -!21 = !{!22, !23, !24, !25, !26, !27} +!21 = !{!22, !23, !24, !25, !26, !27, !28} ; CHECK-DAG: ![[NODE:[0-9]+]] = !DILocalVariable(name: "vla_expr" ; CHECK-DAG: ![[RANGE:[0-9]+]] = !DISubrange(count: ![[NODE]]) ; CHECK-DAG: ![[CONST:[0-9]+]] = !DISubrange(count: 16) -; CHECK-DAG: ![[MULTI:[0-9]+]] = !{![[RANGE]], ![[RANGE]], ![[CONST]], ![[CONST]], ![[CONST]], ![[CONST]]} +; CHECK-DAG: ![[EXPR:[0-9]+]] = !DISubrange(count: !DIExpression(DW_OP_constu, 16)) +; CHECK-DAG: ![[MULTI:[0-9]+]] = !{![[RANGE]], ![[RANGE]], ![[CONST]], ![[CONST]], ![[CONST]], ![[CONST]], ![[EXPR]]} ; CHECK-DAG: elements: ![[MULTI]] !22 = !DISubrange(count: !16) !23 = !DISubrange(count: !16) @@ -47,3 +49,4 @@ !25 = !DISubrange(count: i16 16) !26 = !DISubrange(count: i32 16) !27 = !DISubrange(count: i64 16) +!28 = !DISubrange(count: !DIExpression(DW_OP_constu, 16)) \ No newline at end of file Index: test/DebugInfo/Generic/disubrange.ll =================================================================== --- test/DebugInfo/Generic/disubrange.ll +++ test/DebugInfo/Generic/disubrange.ll @@ -4,6 +4,8 @@ ; CHECK-DAG: DW_AT_count [DW_FORM_ref4] (cu + {{.*}} => {[[NODE:[0-9a-zA-Zx]+]]}) ; CHECK-DAG: [[NODE]]: DW_TAG_variable [4] +; CHECK: DW_AT_count [DW_FORM_exprloc] (<0x2> 10 2a ) + define void @foo(i32 %n) !dbg !7 { entry: call void @llvm.dbg.value(metadata i32 %n, i64 0, metadata !12, metadata !19), !dbg !20 @@ -33,8 +35,10 @@ !14 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned) !15 = !DILocalVariable(name: "vla", scope: !7, file: !1, line: 21, type: !16) !16 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, align: 32, elements: !17) -!17 = !{!18, !18} +!17 = !{!18, !22} !18 = !DISubrange(count: !13) !19 = !DIExpression() !20 = !DILocation(line: 20, column: 14, scope: !7) !21 = !DILocation(line: 22, column: 1, scope: !7) +!22 = !DISubrange(count: !23) +!23 = !DIExpression(DW_OP_constu, 42) Index: test/Verifier/invalid-disubrange-count-node.ll =================================================================== --- test/Verifier/invalid-disubrange-count-node.ll +++ test/Verifier/invalid-disubrange-count-node.ll @@ -33,5 +33,5 @@ !19 = !DILocalVariable(name: "vla", scope: !7, file: !1, line: 21, type: !20) !20 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, align: 32, elements: !21) !21 = !{!22} -; CHECK: Count must either be a signed constant or a DIVariable +; CHECK: Count must either be a signed constant, a DIVariable or a DIExpression !22 = !DISubrange(count: !17) Index: unittests/IR/MetadataTest.cpp =================================================================== --- unittests/IR/MetadataTest.cpp +++ unittests/IR/MetadataTest.cpp @@ -943,6 +943,18 @@ EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); } +TEST_F(DISubrangeTest, getCountExpression) { + uint64_t Elements[] = { dwarf::DW_OP_constu, 5 }; + auto *N = DISubrange::get(Context, DIExpression::get(Context, Elements), 7); + EXPECT_EQ(dwarf::DW_TAG_subrange_type, N->getTag()); + EXPECT_NE(nullptr, N->getCountExpression()); + EXPECT_EQ(nullptr, N->getCount()); + EXPECT_EQ(7, N->getLowerBound()); + + TempDISubrange Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + TEST_F(DISubrangeTest, getEmptyArray) { auto *N = DISubrange::get(Context, -1, 0); EXPECT_EQ(dwarf::DW_TAG_subrange_type, N->getTag());