[Metadata] Extend 'count' field of DISubrange to take a metadata node

Summary:
This patch extends the DISubrange 'count' field to take either a
(signed) constant integer value or a reference to a DILocalVariable
or DIGlobalVariable.

This is patch [1/3] in a series to extend LLVM's DISubrange Metadata
node to support debugging of C99 variable length arrays and vectors with
runtime length like the Scalable Vector Extension for AArch64. It is
also a first step towards representing more complex cases like arrays
in Fortran.

Reviewers: echristo, pcc, aprantl, dexonsmith, clayborg, kristof.beyls, dblaikie

Reviewed By: aprantl

Subscribers: rnk, probinson, fhahn, aemerson, rengolin, JDevlieghere, llvm-commits

Differential Revision: https://reviews.llvm.org/D41695

llvm-svn: 323313
This commit is contained in:
Sander de Smalen 2018-01-24 09:56:07 +00:00
parent e8404780c3
commit fdf40917d9
19 changed files with 370 additions and 34 deletions

View File

@ -4310,6 +4310,8 @@ DISubrange
``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 @@ DISubrange
!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

View File

@ -503,6 +503,7 @@ namespace llvm {
/// 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.

View File

@ -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 <cassert>
@ -332,31 +334,53 @@ class DISubrange : public DINode {
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<Metadata *> 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<ConstantInt*, DIVariable*> CountType;
CountType getCount() const {
if (auto *MD = dyn_cast<ConstantAsMetadata>(getRawCountNode()))
return CountType(cast<ConstantInt>(MD->getValue()));
if (auto *DV = dyn_cast<DIVariable>(getRawCountNode()))
return CountType(DV);
return CountType();
}
static bool classof(const Metadata *MD) {
return MD->getMetadataID() == DISubrangeKind;

View File

@ -3492,6 +3492,39 @@ template <class FieldTy> struct MDFieldImpl {
: 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
/// MD<typeofA>Field and MD<typeofB>Field structs, so not
/// to reimplement the specifics for representing each Field.
template <class FieldTypeA, class FieldTypeB> struct MDEitherFieldImpl {
typedef MDEitherFieldImpl<FieldTypeA, FieldTypeB> 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> {
uint64_t Max;
@ -3582,6 +3615,26 @@ struct ChecksumKindField : public MDFieldImpl<DIFile::ChecksumKind> {
ChecksumKindField(DIFile::ChecksumKind CSKind) : ImplTy(CSKind) {}
};
struct MDSignedOrMDField : MDEitherFieldImpl<MDSignedField, MDField> {
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 {
@ -3835,6 +3888,29 @@ bool LLParser::ParseMDField(LocTy Loc, StringRef Name, MDField &Result) {
return false;
}
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();
@ -3979,14 +4055,23 @@ bool LLParser::ParseGenericDINode(MDNode *&Result, bool IsDistinct) {
/// 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;
}

View File

@ -1174,14 +1174,25 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
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;
}

View File

@ -1442,8 +1442,9 @@ static uint64_t rotateSign(int64_t I) {
void ModuleBitcodeWriter::writeDISubrange(const DISubrange *N,
SmallVectorImpl<uint64_t> &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);

View File

@ -1325,7 +1325,9 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) {
const DISubrange *Subrange = cast<DISubrange>(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<ConstantInt*>())
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

View File

@ -1328,7 +1328,9 @@ void DwarfUnit::constructSubrangeDIE(DIE &Buffer, const DISubrange *SR,
// 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<ConstantInt*>())
Count = CI->getSExtValue();
if (DefaultLowerBound == -1 || LowerBound != DefaultLowerBound)
addUInt(DW_Subrange, dwarf::DW_AT_lower_bound, None, LowerBound);

View File

@ -1621,10 +1621,15 @@ static void writeDILocation(raw_ostream &Out, const DILocation *DL,
}
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<ConstantInt*>())
Printer.printInt("count", CE->getSExtValue(), /* ShouldSkipZero */ false);
else
Printer.printMetadata("count", N->getCount().dyn_cast<DIVariable*>(),
/*ShouldSkipNull */ false);
Printer.printInt("lowerBound", N->getLowerBound());
Out << ")";
}

View File

@ -582,6 +582,10 @@ DISubrange *DIBuilder::getOrCreateSubrange(int64_t Lo, int64_t Count) {
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 =

View File

@ -249,8 +249,17 @@ void GenericDINode::recalculateHash() {
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,

View File

@ -321,19 +321,34 @@ template <> struct MDNodeKeyImpl<GenericDINode> : MDNodeOpsKey {
};
template <> struct MDNodeKeyImpl<DISubrange> {
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<ConstantInt*>())
if (auto *MD = dyn_cast<ConstantAsMetadata>(CountNode))
if (RHSCount->getSExtValue() ==
cast<ConstantInt>(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<ConstantAsMetadata>(CountNode))
return hash_combine(cast<ConstantInt>(MD->getValue())->getSExtValue(),
LowerBound);
return hash_combine(CountNode, LowerBound);
}
};
template <> struct MDNodeKeyImpl<DIEnumerator> {

View File

@ -868,7 +868,12 @@ void Verifier::visitDIScope(const DIScope &N) {
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<ConstantInt*>() ||
Count.get<ConstantInt*>()->getSExtValue() >= -1,
"invalid subrange count", &N);
}
void Verifier::visitDIEnumerator(const DIEnumerator &N) {

View File

@ -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)

View File

@ -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)

Binary file not shown.

View File

@ -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)

View File

@ -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)

View File

@ -932,8 +932,11 @@ typedef MetadataTest DISubrangeTest;
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<ConstantInt*>());
EXPECT_EQ(5, Count.get<ConstantInt*>()->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, get) {
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<ConstantInt*>());
EXPECT_EQ(-1, Count.get<ConstantInt*>()->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<DINode::DIFlags>(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<DIVariable*>());
EXPECT_EQ(VlaExpr, Count.get<DIVariable*>());
ASSERT_TRUE(isa<DIVariable>(N->getRawCountNode()));
EXPECT_EQ(0, N->getLowerBound());
EXPECT_EQ("vla_expr", Count.get<DIVariable*>()->getName());
EXPECT_EQ(N, DISubrange::get(Context, VlaExpr, 0));
}
typedef MetadataTest DIEnumeratorTest;
TEST_F(DIEnumeratorTest, get) {