mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
[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:
parent
46e41bf2fe
commit
ee2cc50e7b
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 << ")";
|
||||
}
|
||||
|
@ -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 =
|
||||
|
@ -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,
|
||||
|
@ -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> {
|
||||
|
@ -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) {
|
||||
|
4
test/Assembler/invalid-disubrange-count-node.ll
Normal file
4
test/Assembler/invalid-disubrange-count-node.ll
Normal 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)
|
41
test/Bitcode/disubrange-v0.ll
Normal file
41
test/Bitcode/disubrange-v0.ll
Normal 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)
|
BIN
test/Bitcode/disubrange-v0.ll.bc
Normal file
BIN
test/Bitcode/disubrange-v0.ll.bc
Normal file
Binary file not shown.
49
test/Bitcode/disubrange.ll
Normal file
49
test/Bitcode/disubrange.ll
Normal 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)
|
37
test/Verifier/invalid-disubrange-count-node.ll
Normal file
37
test/Verifier/invalid-disubrange-count-node.ll
Normal 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)
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user