Index: llvm/trunk/docs/LangRef.rst =================================================================== --- llvm/trunk/docs/LangRef.rst +++ llvm/trunk/docs/LangRef.rst @@ -4310,6 +4310,8 @@ ``DISubrange`` nodes are the elements for ``DW_TAG_array_type`` variants of :ref:`DICompositeType`. ``count: -1`` indicates an empty array. +``count: !9`` describes the count with a :ref:`DILocalVariable`. +``count: !11`` describes the count with a :ref:`DIGlobalVariable`. .. code-block:: llvm @@ -4317,6 +4319,20 @@ !1 = !DISubrange(count: 5, lowerBound: 1) ; array counting from 1 !2 = !DISubrange(count: -1) ; empty array. + ; Scopes used in rest of example + !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) + + ; 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) + .. _DIEnumerator: DIEnumerator Index: llvm/trunk/include/llvm/IR/DIBuilder.h =================================================================== --- llvm/trunk/include/llvm/IR/DIBuilder.h +++ llvm/trunk/include/llvm/IR/DIBuilder.h @@ -503,6 +503,7 @@ /// Create a descriptor for a value range. This /// implicitly uniques the values returned. DISubrange *getOrCreateSubrange(int64_t Lo, int64_t Count); + DISubrange *getOrCreateSubrange(int64_t Lo, Metadata *CountNode); /// Create a new descriptor for the specified variable. /// \param Context Variable scope. Index: llvm/trunk/include/llvm/IR/DebugInfoMetadata.h =================================================================== --- llvm/trunk/include/llvm/IR/DebugInfoMetadata.h +++ llvm/trunk/include/llvm/IR/DebugInfoMetadata.h @@ -18,11 +18,13 @@ #include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/Metadata.h" #include "llvm/Support/Casting.h" #include @@ -332,31 +334,53 @@ friend class LLVMContextImpl; friend class MDNode; - int64_t Count; int64_t LowerBound; - DISubrange(LLVMContext &C, StorageType Storage, int64_t Count, - int64_t LowerBound) - : DINode(C, DISubrangeKind, Storage, dwarf::DW_TAG_subrange_type, None), - Count(Count), LowerBound(LowerBound) {} + DISubrange(LLVMContext &C, StorageType Storage, Metadata *Node, + int64_t LowerBound, ArrayRef Ops) + : DINode(C, DISubrangeKind, Storage, dwarf::DW_TAG_subrange_type, Ops), + LowerBound(LowerBound) {} + ~DISubrange() = default; static DISubrange *getImpl(LLVMContext &Context, int64_t Count, int64_t LowerBound, StorageType Storage, bool ShouldCreate = true); + static DISubrange *getImpl(LLVMContext &Context, Metadata *CountNode, + int64_t LowerBound, StorageType Storage, + bool ShouldCreate = true); + TempDISubrange cloneImpl() const { - return getTemporary(getContext(), getCount(), getLowerBound()); + return getTemporary(getContext(), getRawCountNode(), getLowerBound()); } public: DEFINE_MDNODE_GET(DISubrange, (int64_t Count, int64_t LowerBound = 0), (Count, LowerBound)) + DEFINE_MDNODE_GET(DISubrange, (Metadata *CountNode, int64_t LowerBound = 0), + (CountNode, LowerBound)) + TempDISubrange clone() const { return cloneImpl(); } int64_t getLowerBound() const { return LowerBound; } - int64_t getCount() const { return Count; } + + Metadata *getRawCountNode() const { + return getOperand(0).get(); + } + + typedef PointerUnion CountType; + + CountType getCount() const { + if (auto *MD = dyn_cast(getRawCountNode())) + return CountType(cast(MD->getValue())); + + if (auto *DV = dyn_cast(getRawCountNode())) + return CountType(DV); + + return CountType(); + } static bool classof(const Metadata *MD) { return MD->getMetadataID() == DISubrangeKind; Index: llvm/trunk/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/trunk/lib/AsmParser/LLParser.cpp +++ llvm/trunk/lib/AsmParser/LLParser.cpp @@ -3492,6 +3492,39 @@ : Val(std::move(Default)), Seen(false) {} }; +/// Structure to represent an optional metadata field that +/// can be of either type (A or B) and encapsulates the +/// MDField and MDField structs, so not +/// to reimplement the specifics for representing each Field. +template struct MDEitherFieldImpl { + typedef MDEitherFieldImpl ImplTy; + FieldTypeA A; + FieldTypeB B; + bool Seen; + + enum { + IsInvalid = 0, + IsTypeA = 1, + IsTypeB = 2 + } WhatIs; + + void assign(FieldTypeA A) { + Seen = true; + this->A = std::move(A); + WhatIs = IsTypeA; + } + + void assign(FieldTypeB B) { + Seen = true; + this->B = std::move(B); + WhatIs = IsTypeB; + } + + explicit MDEitherFieldImpl(FieldTypeA DefaultA, FieldTypeB DefaultB) + : A(std::move(DefaultA)), B(std::move(DefaultB)), Seen(false), + WhatIs(IsInvalid) {} +}; + struct MDUnsignedField : public MDFieldImpl { uint64_t Max; @@ -3582,6 +3615,26 @@ ChecksumKindField(DIFile::ChecksumKind CSKind) : ImplTy(CSKind) {} }; +struct MDSignedOrMDField : MDEitherFieldImpl { + MDSignedOrMDField(int64_t Default = 0, bool AllowNull = true) + : ImplTy(MDSignedField(Default), MDField(AllowNull)) {} + + MDSignedOrMDField(int64_t Default, int64_t Min, int64_t Max, + bool AllowNull = true) + : ImplTy(MDSignedField(Default, Min, Max), MDField(AllowNull)) {} + + bool isMDSignedField() const { return WhatIs == IsTypeA; } + bool isMDField() const { return WhatIs == IsTypeB; } + int64_t getMDSignedValue() const { + assert(isMDSignedField() && "Wrong field type"); + return A.Val; + } + Metadata *getMDFieldValue() const { + assert(isMDField() && "Wrong field type"); + return B.Val; + } +}; + } // end anonymous namespace namespace llvm { @@ -3836,6 +3889,29 @@ } template <> +bool LLParser::ParseMDField(LocTy Loc, StringRef Name, + MDSignedOrMDField &Result) { + // Try to parse a signed int. + if (Lex.getKind() == lltok::APSInt) { + MDSignedField Res = Result.A; + if (!ParseMDField(Loc, Name, Res)) { + Result.assign(Res); + return false; + } + return true; + } + + // Otherwise, try to parse as an MDField. + MDField Res = Result.B; + if (!ParseMDField(Loc, Name, Res)) { + Result.assign(Res); + return false; + } + + return true; +} + +template <> bool LLParser::ParseMDField(LocTy Loc, StringRef Name, MDStringField &Result) { LocTy ValueLoc = Lex.getLoc(); std::string S; @@ -3979,14 +4055,23 @@ /// ParseDISubrange: /// ::= !DISubrange(count: 30, lowerBound: 2) +/// ::= !DISubrange(count: !node, lowerBound: 2) bool LLParser::ParseDISubrange(MDNode *&Result, bool IsDistinct) { #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ - REQUIRED(count, MDSignedField, (-1, -1, INT64_MAX)); \ + REQUIRED(count, MDSignedOrMDField, (-1, -1, INT64_MAX, false)); \ OPTIONAL(lowerBound, MDSignedField, ); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS - Result = GET_OR_DISTINCT(DISubrange, (Context, count.Val, lowerBound.Val)); + if (count.isMDSignedField()) + Result = GET_OR_DISTINCT( + DISubrange, (Context, count.getMDSignedValue(), lowerBound.Val)); + else if (count.isMDField()) + Result = GET_OR_DISTINCT( + DISubrange, (Context, count.getMDFieldValue(), lowerBound.Val)); + else + return true; + return false; } Index: llvm/trunk/lib/Bitcode/Reader/MetadataLoader.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Reader/MetadataLoader.cpp +++ llvm/trunk/lib/Bitcode/Reader/MetadataLoader.cpp @@ -1174,14 +1174,25 @@ break; } case bitc::METADATA_SUBRANGE: { - if (Record.size() != 3) - return error("Invalid record"); + Metadata *Val = nullptr; + // Operand 'count' is interpreted as: + // - Signed integer (version 0) + // - Metadata node (version 1) + switch (Record[0] >> 1) { + case 0: + Val = GET_OR_DISTINCT(DISubrange, + (Context, Record[1], unrotateSign(Record.back()))); + break; + case 1: + Val = GET_OR_DISTINCT(DISubrange, (Context, getMDOrNull(Record[1]), + unrotateSign(Record.back()))); + break; + default: + return error("Invalid record: Unsupported version of DISubrange"); + } - IsDistinct = Record[0]; - MetadataList.assignValue( - GET_OR_DISTINCT(DISubrange, - (Context, Record[1], unrotateSign(Record[2]))), - NextMetadataNo); + MetadataList.assignValue(Val, NextMetadataNo); + IsDistinct = Record[0] & 1; NextMetadataNo++; break; } Index: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1442,8 +1442,9 @@ void ModuleBitcodeWriter::writeDISubrange(const DISubrange *N, SmallVectorImpl &Record, unsigned Abbrev) { - Record.push_back(N->isDistinct()); - Record.push_back(N->getCount()); + const uint64_t Version = 1 << 1; + Record.push_back((uint64_t)N->isDistinct() | Version); + Record.push_back(VE.getMetadataOrNullID(N->getRawCountNode())); Record.push_back(rotateSign(N->getLowerBound())); Stream.EmitRecord(bitc::METADATA_SUBRANGE, Record, Abbrev); Index: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -1325,7 +1325,9 @@ const DISubrange *Subrange = cast(Element); assert(Subrange->getLowerBound() == 0 && "codeview doesn't support subranges with lower bounds"); - int64_t Count = Subrange->getCount(); + int64_t Count = -1; + if (auto *CI = Subrange->getCount().dyn_cast()) + Count = CI->getSExtValue(); // Forward declarations of arrays without a size and VLAs use a count of -1. // Emit a count of zero in these cases to match what MSVC does for arrays Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1328,7 +1328,9 @@ // DW_AT_lower_bound and DW_AT_count attributes. int64_t LowerBound = SR->getLowerBound(); int64_t DefaultLowerBound = getDefaultLowerBound(); - int64_t Count = SR->getCount(); + int64_t Count = -1; + if (auto *CI = SR->getCount().dyn_cast()) + Count = CI->getSExtValue(); if (DefaultLowerBound == -1 || LowerBound != DefaultLowerBound) addUInt(DW_Subrange, dwarf::DW_AT_lower_bound, None, LowerBound); Index: llvm/trunk/lib/IR/AsmWriter.cpp =================================================================== --- llvm/trunk/lib/IR/AsmWriter.cpp +++ llvm/trunk/lib/IR/AsmWriter.cpp @@ -1621,10 +1621,15 @@ } static void writeDISubrange(raw_ostream &Out, const DISubrange *N, - TypePrinting *, SlotTracker *, const Module *) { + TypePrinting *TypePrinter, SlotTracker *Machine, + const Module *Context) { Out << "!DISubrange("; - MDFieldPrinter Printer(Out); - Printer.printInt("count", N->getCount(), /* ShouldSkipZero */ false); + MDFieldPrinter Printer(Out, TypePrinter, Machine, Context); + if (auto *CE = N->getCount().dyn_cast()) + Printer.printInt("count", CE->getSExtValue(), /* ShouldSkipZero */ false); + else + Printer.printMetadata("count", N->getCount().dyn_cast(), + /*ShouldSkipNull */ false); Printer.printInt("lowerBound", N->getLowerBound()); Out << ")"; } Index: llvm/trunk/lib/IR/DIBuilder.cpp =================================================================== --- llvm/trunk/lib/IR/DIBuilder.cpp +++ llvm/trunk/lib/IR/DIBuilder.cpp @@ -582,6 +582,10 @@ return DISubrange::get(VMContext, Count, Lo); } +DISubrange *DIBuilder::getOrCreateSubrange(int64_t Lo, Metadata *CountNode) { + return DISubrange::get(VMContext, CountNode, Lo); +} + static void checkGlobalVariableScope(DIScope *Context) { #ifndef NDEBUG if (auto *CT = Index: llvm/trunk/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/trunk/lib/IR/DebugInfoMetadata.cpp +++ llvm/trunk/lib/IR/DebugInfoMetadata.cpp @@ -249,8 +249,17 @@ DISubrange *DISubrange::getImpl(LLVMContext &Context, int64_t Count, int64_t Lo, StorageType Storage, bool ShouldCreate) { - DEFINE_GETIMPL_LOOKUP(DISubrange, (Count, Lo)); - DEFINE_GETIMPL_STORE_NO_OPS(DISubrange, (Count, Lo)); + auto *CountNode = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(Context), Count)); + return getImpl(Context, CountNode, Lo, Storage, ShouldCreate); +} + +DISubrange *DISubrange::getImpl(LLVMContext &Context, Metadata *CountNode, + int64_t Lo, StorageType Storage, + bool ShouldCreate) { + DEFINE_GETIMPL_LOOKUP(DISubrange, (CountNode, Lo)); + Metadata *Ops[] = { CountNode }; + DEFINE_GETIMPL_STORE(DISubrange, (CountNode, Lo), Ops); } DIEnumerator *DIEnumerator::getImpl(LLVMContext &Context, int64_t Value, Index: llvm/trunk/lib/IR/LLVMContextImpl.h =================================================================== --- llvm/trunk/lib/IR/LLVMContextImpl.h +++ llvm/trunk/lib/IR/LLVMContextImpl.h @@ -321,19 +321,34 @@ }; template <> struct MDNodeKeyImpl { - int64_t Count; + Metadata *CountNode; int64_t LowerBound; - MDNodeKeyImpl(int64_t Count, int64_t LowerBound) - : Count(Count), LowerBound(LowerBound) {} + MDNodeKeyImpl(Metadata *CountNode, int64_t LowerBound) + : CountNode(CountNode), LowerBound(LowerBound) {} MDNodeKeyImpl(const DISubrange *N) - : Count(N->getCount()), LowerBound(N->getLowerBound()) {} + : CountNode(N->getRawCountNode()), + LowerBound(N->getLowerBound()) {} bool isKeyOf(const DISubrange *RHS) const { - return Count == RHS->getCount() && LowerBound == RHS->getLowerBound(); + if (LowerBound != RHS->getLowerBound()) + return false; + + if (auto *RHSCount = RHS->getCount().dyn_cast()) + if (auto *MD = dyn_cast(CountNode)) + if (RHSCount->getSExtValue() == + cast(MD->getValue())->getSExtValue()) + return true; + + return CountNode == RHS->getRawCountNode(); } - unsigned getHashValue() const { return hash_combine(Count, LowerBound); } + unsigned getHashValue() const { + if (auto *MD = dyn_cast(CountNode)) + return hash_combine(cast(MD->getValue())->getSExtValue(), + LowerBound); + return hash_combine(CountNode, LowerBound); + } }; template <> struct MDNodeKeyImpl { Index: llvm/trunk/lib/IR/Verifier.cpp =================================================================== --- llvm/trunk/lib/IR/Verifier.cpp +++ llvm/trunk/lib/IR/Verifier.cpp @@ -868,7 +868,12 @@ void Verifier::visitDISubrange(const DISubrange &N) { AssertDI(N.getTag() == dwarf::DW_TAG_subrange_type, "invalid tag", &N); - AssertDI(N.getCount() >= -1, "invalid subrange count", &N); + auto Count = N.getCount(); + AssertDI(Count, "Count must either be a signed constant or a DIVariable", + &N); + AssertDI(!Count.is() || + Count.get()->getSExtValue() >= -1, + "invalid subrange count", &N); } void Verifier::visitDIEnumerator(const DIEnumerator &N) { Index: llvm/trunk/test/Assembler/invalid-disubrange-count-node.ll =================================================================== --- llvm/trunk/test/Assembler/invalid-disubrange-count-node.ll +++ llvm/trunk/test/Assembler/invalid-disubrange-count-node.ll @@ -0,0 +1,4 @@ +; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s + +; CHECK: [[@LINE+1]]:{{[0-9]+}}: error: 'count' cannot be null +!0 = !DISubrange(count: null) Index: llvm/trunk/test/Bitcode/disubrange-v0.ll =================================================================== --- llvm/trunk/test/Bitcode/disubrange-v0.ll +++ llvm/trunk/test/Bitcode/disubrange-v0.ll @@ -0,0 +1,41 @@ +; Check that a DISubrange built with an older version of LLVM is correctly restored. +; RUN: llvm-dis < %s.bc | FileCheck %s +; RUN: llvm-dis < %s.bc | llvm-as | llvm-dis | FileCheck %s + +define void @foo(i32 %n) { +entry: + %array = alloca i32, i64 42, align 16 + call void @llvm.dbg.declare(metadata i32* %array, metadata !19, metadata !12), !dbg !18 + ret void +} + +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 5.0.1", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "vla.c", directory: "/path/to") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 5.0.1"} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 20, type: !8, isLocal: false, isDefinition: true, scopeLine: 20, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{null, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!16, !19} +!12 = !DIExpression() +!16 = !DILocalVariable(name: "vla_expr", scope: !7, file: !1, line: 21, type: !17) +!17 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned) +!18 = !DILocation(line: 21, column: 7, scope: !7) +!19 = !DILocalVariable(name: "array", scope: !7, file: !1, line: 21, type: !20) +!20 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, align: 32, elements: !21) +!21 = !{!22} +; CHECK-DAG: ![[NODE:[0-9]+]] = !DILocalVariable(name: "array" +; CHECK-DAG: ![[CONST:[0-9]+]] = !DISubrange(count: 42, lowerBound: 1) +; CHECK-DAG: ![[MULTI:[0-9]+]] = !{![[CONST]]} +; CHECK-DAG: elements: ![[MULTI]] +!22 = !DISubrange(count: 42, lowerBound: 1) Index: llvm/trunk/test/Bitcode/disubrange.ll =================================================================== --- llvm/trunk/test/Bitcode/disubrange.ll +++ llvm/trunk/test/Bitcode/disubrange.ll @@ -0,0 +1,49 @@ +; 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. +; RUN: llvm-as < %s | llvm-dis | FileCheck %s + +define void @foo(i32 %n) { +entry: + %0 = zext i32 %n to i64 + %vla = alloca i32, i64 %0, align 16 + call void @llvm.dbg.declare(metadata i32* %vla, metadata !19, metadata !12), !dbg !18 + ret void +} + +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 5.0.1", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "vla.c", directory: "/path/to") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 5.0.1"} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 20, type: !8, isLocal: false, isDefinition: true, scopeLine: 20, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{null, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!16, !19} +!12 = !DIExpression() +!16 = !DILocalVariable(name: "vla_expr", scope: !7, file: !1, line: 21, type: !17) +!17 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned) +!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} + +; 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: elements: ![[MULTI]] +!22 = !DISubrange(count: !16) +!23 = !DISubrange(count: !16) +!24 = !DISubrange(count: 16) +!25 = !DISubrange(count: i16 16) +!26 = !DISubrange(count: i32 16) +!27 = !DISubrange(count: i64 16) Index: llvm/trunk/test/Verifier/invalid-disubrange-count-node.ll =================================================================== --- llvm/trunk/test/Verifier/invalid-disubrange-count-node.ll +++ llvm/trunk/test/Verifier/invalid-disubrange-count-node.ll @@ -0,0 +1,37 @@ +; RUN: llvm-as < %s -disable-output 2>&1 | FileCheck %s + +define void @foo(i32 %n) { +entry: + %0 = zext i32 %n to i64 + %vla = alloca i32, i64 %0, align 16 + call void @llvm.dbg.declare(metadata i32* %vla, metadata !19, metadata !12), !dbg !18 + ret void +} + +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 5.0.1", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "vla.c", directory: "/path/to") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 5.0.1"} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 20, type: !8, isLocal: false, isDefinition: true, scopeLine: 20, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{null, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!16, !19} +!12 = !DIExpression() +!16 = !DILocalVariable(name: "vla_expr", scope: !7, file: !1, line: 21, type: !17) +!17 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned) +!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} +; CHECK: Count must either be a signed constant or a DIVariable +!22 = !DISubrange(count: !17) Index: llvm/trunk/unittests/IR/MetadataTest.cpp =================================================================== --- llvm/trunk/unittests/IR/MetadataTest.cpp +++ llvm/trunk/unittests/IR/MetadataTest.cpp @@ -932,8 +932,11 @@ TEST_F(DISubrangeTest, get) { auto *N = DISubrange::get(Context, 5, 7); + auto Count = N->getCount(); EXPECT_EQ(dwarf::DW_TAG_subrange_type, N->getTag()); - EXPECT_EQ(5, N->getCount()); + ASSERT_TRUE(Count); + ASSERT_TRUE(Count.is()); + EXPECT_EQ(5, Count.get()->getSExtValue()); EXPECT_EQ(7, N->getLowerBound()); EXPECT_EQ(N, DISubrange::get(Context, 5, 7)); EXPECT_EQ(DISubrange::get(Context, 5, 0), DISubrange::get(Context, 5)); @@ -944,12 +947,34 @@ TEST_F(DISubrangeTest, getEmptyArray) { auto *N = DISubrange::get(Context, -1, 0); + auto Count = N->getCount(); EXPECT_EQ(dwarf::DW_TAG_subrange_type, N->getTag()); - EXPECT_EQ(-1, N->getCount()); + ASSERT_TRUE(Count); + ASSERT_TRUE(Count.is()); + EXPECT_EQ(-1, Count.get()->getSExtValue()); EXPECT_EQ(0, N->getLowerBound()); EXPECT_EQ(N, DISubrange::get(Context, -1, 0)); } +TEST_F(DISubrangeTest, getVariableCount) { + DILocalScope *Scope = getSubprogram(); + DIFile *File = getFile(); + DIType *Type = getDerivedType(); + DINode::DIFlags Flags = static_cast(7); + auto *VlaExpr = DILocalVariable::get(Context, Scope, "vla_expr", File, 8, + Type, 2, Flags, 8); + + auto *N = DISubrange::get(Context, VlaExpr, 0); + auto Count = N->getCount(); + ASSERT_TRUE(Count); + ASSERT_TRUE(Count.is()); + EXPECT_EQ(VlaExpr, Count.get()); + ASSERT_TRUE(isa(N->getRawCountNode())); + EXPECT_EQ(0, N->getLowerBound()); + EXPECT_EQ("vla_expr", Count.get()->getName()); + EXPECT_EQ(N, DISubrange::get(Context, VlaExpr, 0)); +} + typedef MetadataTest DIEnumeratorTest; TEST_F(DIEnumeratorTest, get) {