Skip to content

Commit fdf4091

Browse files
committedJan 24, 2018
[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
1 parent e840478 commit fdf4091

19 files changed

+370
-34
lines changed
 

‎llvm/docs/LangRef.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4310,13 +4310,29 @@ DISubrange
43104310

43114311
``DISubrange`` nodes are the elements for ``DW_TAG_array_type`` variants of
43124312
:ref:`DICompositeType`. ``count: -1`` indicates an empty array.
4313+
``count: !9`` describes the count with a :ref:`DILocalVariable`.
4314+
``count: !11`` describes the count with a :ref:`DIGlobalVariable`.
43134315

43144316
.. code-block:: llvm
43154317

43164318
!0 = !DISubrange(count: 5, lowerBound: 0) ; array counting from 0
43174319
!1 = !DISubrange(count: 5, lowerBound: 1) ; array counting from 1
43184320
!2 = !DISubrange(count: -1) ; empty array.
43194321

4322+
; Scopes used in rest of example
4323+
!6 = !DIFile(filename: "vla.c", directory: "/path/to/file")
4324+
!7 = distinct !DICompileUnit(language: DW_LANG_C99, ...
4325+
!8 = distinct !DISubprogram(name: "foo", scope: !7, file: !6, line: 5, ...
4326+
4327+
; Use of local variable as count value
4328+
!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
4329+
!10 = !DILocalVariable(name: "count", scope: !8, file: !6, line: 42, type: !9)
4330+
!11 = !DISubrange(count !10, lowerBound: 0)
4331+
4332+
; Use of global variable as count value
4333+
!12 = !DIGlobalVariable(name: "count", scope: !8, file: !6, line: 22, type: !9)
4334+
!13 = !DISubrange(count !12, lowerBound: 0)
4335+
43204336
.. _DIEnumerator:
43214337

43224338
DIEnumerator

‎llvm/include/llvm/IR/DIBuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,7 @@ namespace llvm {
503503
/// Create a descriptor for a value range. This
504504
/// implicitly uniques the values returned.
505505
DISubrange *getOrCreateSubrange(int64_t Lo, int64_t Count);
506+
DISubrange *getOrCreateSubrange(int64_t Lo, Metadata *CountNode);
506507

507508
/// Create a new descriptor for the specified variable.
508509
/// \param Context Variable scope.

‎llvm/include/llvm/IR/DebugInfoMetadata.h

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818
#include "llvm/ADT/BitmaskEnum.h"
1919
#include "llvm/ADT/None.h"
2020
#include "llvm/ADT/Optional.h"
21+
#include "llvm/ADT/PointerUnion.h"
2122
#include "llvm/ADT/STLExtras.h"
2223
#include "llvm/ADT/SmallVector.h"
2324
#include "llvm/ADT/StringRef.h"
2425
#include "llvm/ADT/iterator_range.h"
2526
#include "llvm/BinaryFormat/Dwarf.h"
27+
#include "llvm/IR/Constants.h"
2628
#include "llvm/IR/Metadata.h"
2729
#include "llvm/Support/Casting.h"
2830
#include <cassert>
@@ -332,31 +334,53 @@ class DISubrange : public DINode {
332334
friend class LLVMContextImpl;
333335
friend class MDNode;
334336

335-
int64_t Count;
336337
int64_t LowerBound;
337338

338-
DISubrange(LLVMContext &C, StorageType Storage, int64_t Count,
339-
int64_t LowerBound)
340-
: DINode(C, DISubrangeKind, Storage, dwarf::DW_TAG_subrange_type, None),
341-
Count(Count), LowerBound(LowerBound) {}
339+
DISubrange(LLVMContext &C, StorageType Storage, Metadata *Node,
340+
int64_t LowerBound, ArrayRef<Metadata *> Ops)
341+
: DINode(C, DISubrangeKind, Storage, dwarf::DW_TAG_subrange_type, Ops),
342+
LowerBound(LowerBound) {}
343+
342344
~DISubrange() = default;
343345

344346
static DISubrange *getImpl(LLVMContext &Context, int64_t Count,
345347
int64_t LowerBound, StorageType Storage,
346348
bool ShouldCreate = true);
347349

350+
static DISubrange *getImpl(LLVMContext &Context, Metadata *CountNode,
351+
int64_t LowerBound, StorageType Storage,
352+
bool ShouldCreate = true);
353+
348354
TempDISubrange cloneImpl() const {
349-
return getTemporary(getContext(), getCount(), getLowerBound());
355+
return getTemporary(getContext(), getRawCountNode(), getLowerBound());
350356
}
351357

352358
public:
353359
DEFINE_MDNODE_GET(DISubrange, (int64_t Count, int64_t LowerBound = 0),
354360
(Count, LowerBound))
355361

362+
DEFINE_MDNODE_GET(DISubrange, (Metadata *CountNode, int64_t LowerBound = 0),
363+
(CountNode, LowerBound))
364+
356365
TempDISubrange clone() const { return cloneImpl(); }
357366

358367
int64_t getLowerBound() const { return LowerBound; }
359-
int64_t getCount() const { return Count; }
368+
369+
Metadata *getRawCountNode() const {
370+
return getOperand(0).get();
371+
}
372+
373+
typedef PointerUnion<ConstantInt*, DIVariable*> CountType;
374+
375+
CountType getCount() const {
376+
if (auto *MD = dyn_cast<ConstantAsMetadata>(getRawCountNode()))
377+
return CountType(cast<ConstantInt>(MD->getValue()));
378+
379+
if (auto *DV = dyn_cast<DIVariable>(getRawCountNode()))
380+
return CountType(DV);
381+
382+
return CountType();
383+
}
360384

361385
static bool classof(const Metadata *MD) {
362386
return MD->getMetadataID() == DISubrangeKind;

‎llvm/lib/AsmParser/LLParser.cpp

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3492,6 +3492,39 @@ template <class FieldTy> struct MDFieldImpl {
34923492
: Val(std::move(Default)), Seen(false) {}
34933493
};
34943494

3495+
/// Structure to represent an optional metadata field that
3496+
/// can be of either type (A or B) and encapsulates the
3497+
/// MD<typeofA>Field and MD<typeofB>Field structs, so not
3498+
/// to reimplement the specifics for representing each Field.
3499+
template <class FieldTypeA, class FieldTypeB> struct MDEitherFieldImpl {
3500+
typedef MDEitherFieldImpl<FieldTypeA, FieldTypeB> ImplTy;
3501+
FieldTypeA A;
3502+
FieldTypeB B;
3503+
bool Seen;
3504+
3505+
enum {
3506+
IsInvalid = 0,
3507+
IsTypeA = 1,
3508+
IsTypeB = 2
3509+
} WhatIs;
3510+
3511+
void assign(FieldTypeA A) {
3512+
Seen = true;
3513+
this->A = std::move(A);
3514+
WhatIs = IsTypeA;
3515+
}
3516+
3517+
void assign(FieldTypeB B) {
3518+
Seen = true;
3519+
this->B = std::move(B);
3520+
WhatIs = IsTypeB;
3521+
}
3522+
3523+
explicit MDEitherFieldImpl(FieldTypeA DefaultA, FieldTypeB DefaultB)
3524+
: A(std::move(DefaultA)), B(std::move(DefaultB)), Seen(false),
3525+
WhatIs(IsInvalid) {}
3526+
};
3527+
34953528
struct MDUnsignedField : public MDFieldImpl<uint64_t> {
34963529
uint64_t Max;
34973530

@@ -3582,6 +3615,26 @@ struct ChecksumKindField : public MDFieldImpl<DIFile::ChecksumKind> {
35823615
ChecksumKindField(DIFile::ChecksumKind CSKind) : ImplTy(CSKind) {}
35833616
};
35843617

3618+
struct MDSignedOrMDField : MDEitherFieldImpl<MDSignedField, MDField> {
3619+
MDSignedOrMDField(int64_t Default = 0, bool AllowNull = true)
3620+
: ImplTy(MDSignedField(Default), MDField(AllowNull)) {}
3621+
3622+
MDSignedOrMDField(int64_t Default, int64_t Min, int64_t Max,
3623+
bool AllowNull = true)
3624+
: ImplTy(MDSignedField(Default, Min, Max), MDField(AllowNull)) {}
3625+
3626+
bool isMDSignedField() const { return WhatIs == IsTypeA; }
3627+
bool isMDField() const { return WhatIs == IsTypeB; }
3628+
int64_t getMDSignedValue() const {
3629+
assert(isMDSignedField() && "Wrong field type");
3630+
return A.Val;
3631+
}
3632+
Metadata *getMDFieldValue() const {
3633+
assert(isMDField() && "Wrong field type");
3634+
return B.Val;
3635+
}
3636+
};
3637+
35853638
} // end anonymous namespace
35863639

35873640
namespace llvm {
@@ -3835,6 +3888,29 @@ bool LLParser::ParseMDField(LocTy Loc, StringRef Name, MDField &Result) {
38353888
return false;
38363889
}
38373890

3891+
template <>
3892+
bool LLParser::ParseMDField(LocTy Loc, StringRef Name,
3893+
MDSignedOrMDField &Result) {
3894+
// Try to parse a signed int.
3895+
if (Lex.getKind() == lltok::APSInt) {
3896+
MDSignedField Res = Result.A;
3897+
if (!ParseMDField(Loc, Name, Res)) {
3898+
Result.assign(Res);
3899+
return false;
3900+
}
3901+
return true;
3902+
}
3903+
3904+
// Otherwise, try to parse as an MDField.
3905+
MDField Res = Result.B;
3906+
if (!ParseMDField(Loc, Name, Res)) {
3907+
Result.assign(Res);
3908+
return false;
3909+
}
3910+
3911+
return true;
3912+
}
3913+
38383914
template <>
38393915
bool LLParser::ParseMDField(LocTy Loc, StringRef Name, MDStringField &Result) {
38403916
LocTy ValueLoc = Lex.getLoc();
@@ -3979,14 +4055,23 @@ bool LLParser::ParseGenericDINode(MDNode *&Result, bool IsDistinct) {
39794055

39804056
/// ParseDISubrange:
39814057
/// ::= !DISubrange(count: 30, lowerBound: 2)
4058+
/// ::= !DISubrange(count: !node, lowerBound: 2)
39824059
bool LLParser::ParseDISubrange(MDNode *&Result, bool IsDistinct) {
39834060
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
3984-
REQUIRED(count, MDSignedField, (-1, -1, INT64_MAX)); \
4061+
REQUIRED(count, MDSignedOrMDField, (-1, -1, INT64_MAX, false)); \
39854062
OPTIONAL(lowerBound, MDSignedField, );
39864063
PARSE_MD_FIELDS();
39874064
#undef VISIT_MD_FIELDS
39884065

3989-
Result = GET_OR_DISTINCT(DISubrange, (Context, count.Val, lowerBound.Val));
4066+
if (count.isMDSignedField())
4067+
Result = GET_OR_DISTINCT(
4068+
DISubrange, (Context, count.getMDSignedValue(), lowerBound.Val));
4069+
else if (count.isMDField())
4070+
Result = GET_OR_DISTINCT(
4071+
DISubrange, (Context, count.getMDFieldValue(), lowerBound.Val));
4072+
else
4073+
return true;
4074+
39904075
return false;
39914076
}
39924077

‎llvm/lib/Bitcode/Reader/MetadataLoader.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,14 +1174,25 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
11741174
break;
11751175
}
11761176
case bitc::METADATA_SUBRANGE: {
1177-
if (Record.size() != 3)
1178-
return error("Invalid record");
1177+
Metadata *Val = nullptr;
1178+
// Operand 'count' is interpreted as:
1179+
// - Signed integer (version 0)
1180+
// - Metadata node (version 1)
1181+
switch (Record[0] >> 1) {
1182+
case 0:
1183+
Val = GET_OR_DISTINCT(DISubrange,
1184+
(Context, Record[1], unrotateSign(Record.back())));
1185+
break;
1186+
case 1:
1187+
Val = GET_OR_DISTINCT(DISubrange, (Context, getMDOrNull(Record[1]),
1188+
unrotateSign(Record.back())));
1189+
break;
1190+
default:
1191+
return error("Invalid record: Unsupported version of DISubrange");
1192+
}
11791193

1180-
IsDistinct = Record[0];
1181-
MetadataList.assignValue(
1182-
GET_OR_DISTINCT(DISubrange,
1183-
(Context, Record[1], unrotateSign(Record[2]))),
1184-
NextMetadataNo);
1194+
MetadataList.assignValue(Val, NextMetadataNo);
1195+
IsDistinct = Record[0] & 1;
11851196
NextMetadataNo++;
11861197
break;
11871198
}

‎llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1442,8 +1442,9 @@ static uint64_t rotateSign(int64_t I) {
14421442
void ModuleBitcodeWriter::writeDISubrange(const DISubrange *N,
14431443
SmallVectorImpl<uint64_t> &Record,
14441444
unsigned Abbrev) {
1445-
Record.push_back(N->isDistinct());
1446-
Record.push_back(N->getCount());
1445+
const uint64_t Version = 1 << 1;
1446+
Record.push_back((uint64_t)N->isDistinct() | Version);
1447+
Record.push_back(VE.getMetadataOrNullID(N->getRawCountNode()));
14471448
Record.push_back(rotateSign(N->getLowerBound()));
14481449

14491450
Stream.EmitRecord(bitc::METADATA_SUBRANGE, Record, Abbrev);

‎llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1325,7 +1325,9 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) {
13251325
const DISubrange *Subrange = cast<DISubrange>(Element);
13261326
assert(Subrange->getLowerBound() == 0 &&
13271327
"codeview doesn't support subranges with lower bounds");
1328-
int64_t Count = Subrange->getCount();
1328+
int64_t Count = -1;
1329+
if (auto *CI = Subrange->getCount().dyn_cast<ConstantInt*>())
1330+
Count = CI->getSExtValue();
13291331

13301332
// Forward declarations of arrays without a size and VLAs use a count of -1.
13311333
// Emit a count of zero in these cases to match what MSVC does for arrays

‎llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1328,7 +1328,9 @@ void DwarfUnit::constructSubrangeDIE(DIE &Buffer, const DISubrange *SR,
13281328
// DW_AT_lower_bound and DW_AT_count attributes.
13291329
int64_t LowerBound = SR->getLowerBound();
13301330
int64_t DefaultLowerBound = getDefaultLowerBound();
1331-
int64_t Count = SR->getCount();
1331+
int64_t Count = -1;
1332+
if (auto *CI = SR->getCount().dyn_cast<ConstantInt*>())
1333+
Count = CI->getSExtValue();
13321334

13331335
if (DefaultLowerBound == -1 || LowerBound != DefaultLowerBound)
13341336
addUInt(DW_Subrange, dwarf::DW_AT_lower_bound, None, LowerBound);

‎llvm/lib/IR/AsmWriter.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,10 +1621,15 @@ static void writeDILocation(raw_ostream &Out, const DILocation *DL,
16211621
}
16221622

16231623
static void writeDISubrange(raw_ostream &Out, const DISubrange *N,
1624-
TypePrinting *, SlotTracker *, const Module *) {
1624+
TypePrinting *TypePrinter, SlotTracker *Machine,
1625+
const Module *Context) {
16251626
Out << "!DISubrange(";
1626-
MDFieldPrinter Printer(Out);
1627-
Printer.printInt("count", N->getCount(), /* ShouldSkipZero */ false);
1627+
MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
1628+
if (auto *CE = N->getCount().dyn_cast<ConstantInt*>())
1629+
Printer.printInt("count", CE->getSExtValue(), /* ShouldSkipZero */ false);
1630+
else
1631+
Printer.printMetadata("count", N->getCount().dyn_cast<DIVariable*>(),
1632+
/*ShouldSkipNull */ false);
16281633
Printer.printInt("lowerBound", N->getLowerBound());
16291634
Out << ")";
16301635
}

‎llvm/lib/IR/DIBuilder.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,10 @@ DISubrange *DIBuilder::getOrCreateSubrange(int64_t Lo, int64_t Count) {
582582
return DISubrange::get(VMContext, Count, Lo);
583583
}
584584

585+
DISubrange *DIBuilder::getOrCreateSubrange(int64_t Lo, Metadata *CountNode) {
586+
return DISubrange::get(VMContext, CountNode, Lo);
587+
}
588+
585589
static void checkGlobalVariableScope(DIScope *Context) {
586590
#ifndef NDEBUG
587591
if (auto *CT =

‎llvm/lib/IR/DebugInfoMetadata.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,17 @@ void GenericDINode::recalculateHash() {
249249

250250
DISubrange *DISubrange::getImpl(LLVMContext &Context, int64_t Count, int64_t Lo,
251251
StorageType Storage, bool ShouldCreate) {
252-
DEFINE_GETIMPL_LOOKUP(DISubrange, (Count, Lo));
253-
DEFINE_GETIMPL_STORE_NO_OPS(DISubrange, (Count, Lo));
252+
auto *CountNode = ConstantAsMetadata::get(
253+
ConstantInt::getSigned(Type::getInt64Ty(Context), Count));
254+
return getImpl(Context, CountNode, Lo, Storage, ShouldCreate);
255+
}
256+
257+
DISubrange *DISubrange::getImpl(LLVMContext &Context, Metadata *CountNode,
258+
int64_t Lo, StorageType Storage,
259+
bool ShouldCreate) {
260+
DEFINE_GETIMPL_LOOKUP(DISubrange, (CountNode, Lo));
261+
Metadata *Ops[] = { CountNode };
262+
DEFINE_GETIMPL_STORE(DISubrange, (CountNode, Lo), Ops);
254263
}
255264

256265
DIEnumerator *DIEnumerator::getImpl(LLVMContext &Context, int64_t Value,

‎llvm/lib/IR/LLVMContextImpl.h

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -321,19 +321,34 @@ template <> struct MDNodeKeyImpl<GenericDINode> : MDNodeOpsKey {
321321
};
322322

323323
template <> struct MDNodeKeyImpl<DISubrange> {
324-
int64_t Count;
324+
Metadata *CountNode;
325325
int64_t LowerBound;
326326

327-
MDNodeKeyImpl(int64_t Count, int64_t LowerBound)
328-
: Count(Count), LowerBound(LowerBound) {}
327+
MDNodeKeyImpl(Metadata *CountNode, int64_t LowerBound)
328+
: CountNode(CountNode), LowerBound(LowerBound) {}
329329
MDNodeKeyImpl(const DISubrange *N)
330-
: Count(N->getCount()), LowerBound(N->getLowerBound()) {}
330+
: CountNode(N->getRawCountNode()),
331+
LowerBound(N->getLowerBound()) {}
331332

332333
bool isKeyOf(const DISubrange *RHS) const {
333-
return Count == RHS->getCount() && LowerBound == RHS->getLowerBound();
334+
if (LowerBound != RHS->getLowerBound())
335+
return false;
336+
337+
if (auto *RHSCount = RHS->getCount().dyn_cast<ConstantInt*>())
338+
if (auto *MD = dyn_cast<ConstantAsMetadata>(CountNode))
339+
if (RHSCount->getSExtValue() ==
340+
cast<ConstantInt>(MD->getValue())->getSExtValue())
341+
return true;
342+
343+
return CountNode == RHS->getRawCountNode();
334344
}
335345

336-
unsigned getHashValue() const { return hash_combine(Count, LowerBound); }
346+
unsigned getHashValue() const {
347+
if (auto *MD = dyn_cast<ConstantAsMetadata>(CountNode))
348+
return hash_combine(cast<ConstantInt>(MD->getValue())->getSExtValue(),
349+
LowerBound);
350+
return hash_combine(CountNode, LowerBound);
351+
}
337352
};
338353

339354
template <> struct MDNodeKeyImpl<DIEnumerator> {

0 commit comments

Comments
 (0)