1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 03:02:36 +01:00

AsmParser/Bitcode: Add support for MDLocation

This adds assembly and bitcode support for `MDLocation`.  The assembly
side is rather big, since this is the first `MDNode` subclass (that
isn't `MDTuple`).  Part of PR21433.

(If you're wondering where the mountains of testcase updates are, we
don't need them until I update `DILocation` and `DebugLoc` to actually
use this class.)

llvm-svn: 225830
This commit is contained in:
Duncan P. N. Exon Smith 2015-01-13 21:10:44 +00:00
parent fb153e33c0
commit 85eaac222d
15 changed files with 284 additions and 5 deletions

View File

@ -2883,6 +2883,23 @@ attached to the ``add`` instruction using the ``!dbg`` identifier:
More information about specific metadata nodes recognized by the More information about specific metadata nodes recognized by the
optimizers and code generator is found below. optimizers and code generator is found below.
Specialized Metadata Nodes
^^^^^^^^^^^^^^^^^^^^^^^^^^
Specialized metadata nodes are custom data structures in metadata (as opposed
to generic tuples). Their fields are labelled, and can be specified in any
order.
MDLocation
""""""""""
``MDLocation`` nodes represent source debug locations. The ``scope:`` field is
mandatory.
.. code-block:: llvm
!0 = !MDLocation(line: 2900, column: 42, scope: !1, inlinedAt: !2)
'``tbaa``' Metadata '``tbaa``' Metadata
^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^

View File

@ -142,7 +142,7 @@ namespace bitc {
METADATA_NAME = 4, // STRING: [values] METADATA_NAME = 4, // STRING: [values]
METADATA_DISTINCT_NODE = 5, // DISTINCT_NODE: [n x md num] METADATA_DISTINCT_NODE = 5, // DISTINCT_NODE: [n x md num]
METADATA_KIND = 6, // [n x [id, name]] METADATA_KIND = 6, // [n x [id, name]]
// 7 is unused. METADATA_LOCATION = 7, // [distinct, line, col, scope, inlined-at?]
METADATA_OLD_NODE = 8, // OLD_NODE: [n x (type num, value num)] METADATA_OLD_NODE = 8, // OLD_NODE: [n x (type num, value num)]
METADATA_OLD_FN_NODE = 9, // OLD_FN_NODE: [n x (type num, value num)] METADATA_OLD_FN_NODE = 9, // OLD_FN_NODE: [n x (type num, value num)]
METADATA_NAMED_NODE = 10, // NAMED_NODE: [n x mdnodes] METADATA_NAMED_NODE = 10, // NAMED_NODE: [n x mdnodes]

View File

@ -587,7 +587,10 @@ bool LLParser::ParseStandaloneMetadata() {
return TokError("unexpected type in metadata definition"); return TokError("unexpected type in metadata definition");
bool IsDistinct = EatIfPresent(lltok::kw_distinct); bool IsDistinct = EatIfPresent(lltok::kw_distinct);
if (ParseToken(lltok::exclaim, "Expected '!' here") || if (Lex.getKind() == lltok::MetadataVar) {
if (ParseSpecializedMDNode(Init, IsDistinct))
return true;
} else if (ParseToken(lltok::exclaim, "Expected '!' here") ||
ParseMDTuple(Init, IsDistinct)) ParseMDTuple(Init, IsDistinct))
return true; return true;
@ -2902,7 +2905,11 @@ bool LLParser::ParseMDTuple(MDNode *&MD, bool IsDistinct) {
/// MDNode: /// MDNode:
/// ::= !{ ... } /// ::= !{ ... }
/// ::= !7 /// ::= !7
/// ::= !MDLocation(...)
bool LLParser::ParseMDNode(MDNode *&N) { bool LLParser::ParseMDNode(MDNode *&N) {
if (Lex.getKind() == lltok::MetadataVar)
return ParseSpecializedMDNode(N);
return ParseToken(lltok::exclaim, "expected '!' here") || return ParseToken(lltok::exclaim, "expected '!' here") ||
ParseMDNodeTail(N); ParseMDNodeTail(N);
} }
@ -2916,6 +2923,106 @@ bool LLParser::ParseMDNodeTail(MDNode *&N) {
return ParseMDNodeID(N); return ParseMDNodeID(N);
} }
bool LLParser::ParseMDField(LocTy Loc, StringRef Name,
MDUnsignedField<uint32_t> &Result) {
if (Result.Seen)
return Error(Loc,
"field '" + Name + "' cannot be specified more than once");
if (Lex.getKind() != lltok::APSInt || Lex.getAPSIntVal().isSigned())
return TokError("expected unsigned integer");
uint64_t Val64 = Lex.getAPSIntVal().getLimitedValue(Result.Max + 1ull);
if (Val64 > Result.Max)
return TokError("value for '" + Name + "' too large, limit is " +
Twine(Result.Max));
Result.assign(Val64);
Lex.Lex();
return false;
}
bool LLParser::ParseMDField(LocTy Loc, StringRef Name, MDField &Result) {
if (Result.Seen)
return Error(Loc,
"field '" + Name + "' cannot be specified more than once");
Metadata *MD;
if (ParseMetadata(MD, nullptr))
return true;
Result.assign(MD);
return false;
}
template <class ParserTy>
bool LLParser::ParseMDFieldsImpl(ParserTy parseField) {
assert(Lex.getKind() == lltok::MetadataVar && "Expected metadata type name");
Lex.Lex();
if (ParseToken(lltok::lparen, "expected '(' here"))
return true;
if (EatIfPresent(lltok::rparen))
return false;
do {
if (Lex.getKind() != lltok::LabelStr)
return TokError("expected field label here");
if (parseField())
return true;
} while (EatIfPresent(lltok::comma));
return ParseToken(lltok::rparen, "expected ')' here");
}
bool LLParser::ParseSpecializedMDNode(MDNode *&N, bool IsDistinct) {
assert(Lex.getKind() == lltok::MetadataVar && "Expected metadata type name");
#define DISPATCH_TO_PARSER(CLASS) \
if (Lex.getStrVal() == #CLASS) \
return Parse##CLASS(N, IsDistinct);
DISPATCH_TO_PARSER(MDLocation);
#undef DISPATCH_TO_PARSER
return TokError("expected metadata type");
}
#define PARSE_MD_FIELD(NAME) \
do { \
if (Lex.getStrVal() == #NAME) { \
LocTy Loc = Lex.getLoc(); \
Lex.Lex(); \
if (ParseMDField(Loc, #NAME, NAME)) \
return true; \
return false; \
} \
} while (0)
/// ParseMDLocationFields:
/// ::= !MDLocation(line: 43, column: 8, scope: !5, inlinedAt: !6)
bool LLParser::ParseMDLocation(MDNode *&Result, bool IsDistinct) {
MDUnsignedField<uint32_t> line(0, ~0u >> 8);
MDUnsignedField<uint32_t> column(0, ~0u >> 24);
MDField scope;
MDField inlinedAt;
if (ParseMDFieldsImpl([&]() -> bool {
PARSE_MD_FIELD(line);
PARSE_MD_FIELD(column);
PARSE_MD_FIELD(scope);
PARSE_MD_FIELD(inlinedAt);
return TokError(Twine("invalid field '") + Lex.getStrVal() + "'");
}))
return true;
if (!scope.Seen)
return TokError("missing required field 'scope'");
auto get = (IsDistinct ? MDLocation::getDistinct : MDLocation::get);
Result = get(Context, line.Val, column.Val, scope.Val, inlinedAt.Val);
return false;
}
#undef PARSE_MD_FIELD
/// ParseMetadataAsValue /// ParseMetadataAsValue
/// ::= metadata i32 %local /// ::= metadata i32 %local
/// ::= metadata i32 @global /// ::= metadata i32 @global
@ -2960,7 +3067,16 @@ bool LLParser::ParseValueAsMetadata(Metadata *&MD, PerFunctionState *PFS) {
/// ::= !42 /// ::= !42
/// ::= !{...} /// ::= !{...}
/// ::= !"string" /// ::= !"string"
/// ::= !MDLocation(...)
bool LLParser::ParseMetadata(Metadata *&MD, PerFunctionState *PFS) { bool LLParser::ParseMetadata(Metadata *&MD, PerFunctionState *PFS) {
if (Lex.getKind() == lltok::MetadataVar) {
MDNode *N;
if (ParseSpecializedMDNode(N))
return true;
MD = N;
return false;
}
// ValueAsMetadata: // ValueAsMetadata:
// <type> <value> // <type> <value>
if (Lex.getKind() != lltok::exclaim) if (Lex.getKind() != lltok::exclaim)

View File

@ -80,6 +80,31 @@ namespace llvm {
} }
}; };
/// Structure to represent an optional metadata field.
template <class FieldTy> struct MDFieldImpl {
typedef MDFieldImpl ImplTy;
FieldTy Val;
bool Seen;
void assign(FieldTy Val) {
Seen = true;
this->Val = Val;
}
explicit MDFieldImpl(FieldTy Default) : Val(Default), Seen(false) {}
};
template <class NumTy> struct MDUnsignedField : public MDFieldImpl<NumTy> {
typedef typename MDUnsignedField::ImplTy ImplTy;
NumTy Max;
MDUnsignedField(NumTy Default = 0,
NumTy Max = std::numeric_limits<NumTy>::max())
: ImplTy(Default), Max(Max) {}
};
struct MDField : public MDFieldImpl<Metadata *> {
MDField() : ImplTy(nullptr) {}
};
class LLParser { class LLParser {
public: public:
typedef LLLexer::LocTy LocTy; typedef LLLexer::LocTy LocTy;
@ -393,6 +418,13 @@ namespace llvm {
bool ParseMDNodeVector(SmallVectorImpl<Metadata *> &MDs); bool ParseMDNodeVector(SmallVectorImpl<Metadata *> &MDs);
bool ParseInstructionMetadata(Instruction *Inst, PerFunctionState *PFS); bool ParseInstructionMetadata(Instruction *Inst, PerFunctionState *PFS);
bool ParseMDField(LocTy Loc, StringRef Name,
MDUnsignedField<uint32_t> &Result);
bool ParseMDField(LocTy Loc, StringRef Name, MDField &Result);
template <class ParserTy> bool ParseMDFieldsImpl(ParserTy parseField);
bool ParseSpecializedMDNode(MDNode *&N, bool IsDistinct = false);
bool ParseMDLocation(MDNode *&Result, bool IsDistinct);
// Function Parsing. // Function Parsing.
struct ArgInfo { struct ArgInfo {
LocTy Loc; LocTy Loc;

View File

@ -1267,6 +1267,20 @@ std::error_code BitcodeReader::ParseMetadata() {
NextMDValueNo++); NextMDValueNo++);
break; break;
} }
case bitc::METADATA_LOCATION: {
if (Record.size() != 5)
return Error("Invalid record");
auto get = Record[0] ? MDLocation::getDistinct : MDLocation::get;
unsigned Line = Record[1];
unsigned Column = Record[2];
MDNode *Scope = cast<MDNode>(MDValueList.getValueFwdRef(Record[3]));
Metadata *InlinedAt =
Record[4] ? MDValueList.getValueFwdRef(Record[4] - 1) : nullptr;
MDValueList.AssignValue(get(Context, Line, Column, Scope, InlinedAt),
NextMDValueNo++);
break;
}
case bitc::METADATA_STRING: { case bitc::METADATA_STRING: {
std::string String(Record.begin(), Record.end()); std::string String(Record.begin(), Record.end());
llvm::UpgradeMDStringConstant(String); llvm::UpgradeMDStringConstant(String);

View File

@ -779,6 +779,25 @@ static void WriteMDNode(const MDNode *N,
Record.clear(); Record.clear();
} }
static void WriteMDLocation(const MDLocation *N, const ValueEnumerator &VE,
BitstreamWriter &Stream,
SmallVectorImpl<uint64_t> &Record,
unsigned Abbrev) {
Record.push_back(N->isDistinct());
Record.push_back(N->getLine());
Record.push_back(N->getColumn());
Record.push_back(VE.getMetadataID(N->getScope()));
// Always emit the inlined-at location, even though it's optional.
if (Metadata *InlinedAt = N->getInlinedAt())
Record.push_back(VE.getMetadataID(InlinedAt) + 1);
else
Record.push_back(0);
Stream.EmitRecord(bitc::METADATA_LOCATION, Record, Abbrev);
Record.clear();
}
static void WriteModuleMetadata(const Module *M, static void WriteModuleMetadata(const Module *M,
const ValueEnumerator &VE, const ValueEnumerator &VE,
BitstreamWriter &Stream) { BitstreamWriter &Stream) {
@ -798,6 +817,22 @@ static void WriteModuleMetadata(const Module *M,
MDSAbbrev = Stream.EmitAbbrev(Abbv); MDSAbbrev = Stream.EmitAbbrev(Abbv);
} }
unsigned LocAbbrev = 0;
if (VE.hasMDLocation()) {
// Abbrev for METADATA_LOCATION.
//
// Assume the column is usually under 128, and always output the inlined-at
// location (it's never more expensive than building an array size 1).
BitCodeAbbrev *Abbv = new BitCodeAbbrev();
Abbv->Add(BitCodeAbbrevOp(bitc::METADATA_LOCATION));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
LocAbbrev = Stream.EmitAbbrev(Abbv);
}
unsigned NameAbbrev = 0; unsigned NameAbbrev = 0;
if (!M->named_metadata_empty()) { if (!M->named_metadata_empty()) {
// Abbrev for METADATA_NAME. // Abbrev for METADATA_NAME.
@ -810,6 +845,10 @@ static void WriteModuleMetadata(const Module *M,
SmallVector<uint64_t, 64> Record; SmallVector<uint64_t, 64> Record;
for (const Metadata *MD : MDs) { for (const Metadata *MD : MDs) {
if (const MDLocation *Loc = dyn_cast<MDLocation>(MD)) {
WriteMDLocation(Loc, VE, Stream, Record, LocAbbrev);
continue;
}
if (const MDNode *N = dyn_cast<MDNode>(MD)) { if (const MDNode *N = dyn_cast<MDNode>(MD)) {
WriteMDNode(N, VE, Stream, Record); WriteMDNode(N, VE, Stream, Record);
continue; continue;

View File

@ -282,7 +282,8 @@ static bool isIntOrIntVectorValue(const std::pair<const Value*, unsigned> &V) {
return V.first->getType()->isIntOrIntVectorTy(); return V.first->getType()->isIntOrIntVectorTy();
} }
ValueEnumerator::ValueEnumerator(const Module &M) : HasMDString(false) { ValueEnumerator::ValueEnumerator(const Module &M)
: HasMDString(false), HasMDLocation(false) {
if (shouldPreserveBitcodeUseListOrder()) if (shouldPreserveBitcodeUseListOrder())
UseListOrders = predictUseListOrder(M); UseListOrders = predictUseListOrder(M);
@ -547,6 +548,7 @@ void ValueEnumerator::EnumerateMetadata(const Metadata *MD) {
EnumerateValue(C->getValue()); EnumerateValue(C->getValue());
HasMDString |= isa<MDString>(MD); HasMDString |= isa<MDString>(MD);
HasMDLocation |= isa<MDLocation>(MD);
// Replace the dummy ID inserted above with the correct one. MDValueMap may // Replace the dummy ID inserted above with the correct one. MDValueMap may
// have changed by inserting operands, so we need a fresh lookup here. // have changed by inserting operands, so we need a fresh lookup here.

View File

@ -65,6 +65,7 @@ private:
typedef DenseMap<const Metadata *, unsigned> MetadataMapType; typedef DenseMap<const Metadata *, unsigned> MetadataMapType;
MetadataMapType MDValueMap; MetadataMapType MDValueMap;
bool HasMDString; bool HasMDString;
bool HasMDLocation;
typedef DenseMap<AttributeSet, unsigned> AttributeGroupMapType; typedef DenseMap<AttributeSet, unsigned> AttributeGroupMapType;
AttributeGroupMapType AttributeGroupMap; AttributeGroupMapType AttributeGroupMap;
@ -111,6 +112,7 @@ public:
unsigned getMetadataID(const Metadata *V) const; unsigned getMetadataID(const Metadata *V) const;
bool hasMDString() const { return HasMDString; } bool hasMDString() const { return HasMDString; }
bool hasMDLocation() const { return HasMDLocation; }
unsigned getTypeID(Type *T) const { unsigned getTypeID(Type *T) const {
TypeMapType::const_iterator I = TypeMap.find(T); TypeMapType::const_iterator I = TypeMap.find(T);

View File

@ -0,0 +1,4 @@
; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s
; CHECK: <stdin>:[[@LINE+1]]:18: error: invalid field 'bad'
!0 = !MDLocation(bad: 0)

View File

@ -0,0 +1,6 @@
; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s
!0 = !{}
; CHECK: <stdin>:[[@LINE+1]]:38: error: field 'line' cannot be specified more than once
!1 = !MDLocation(line: 3, scope: !0, line: 3)

View File

@ -0,0 +1,9 @@
; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s
!0 = !{}
; CHECK-NOT: error
!1 = !MDLocation(column: 255, scope: !0)
; CHECK: <stdin>:[[@LINE+1]]:26: error: value for 'column' too large, limit is 255
!2 = !MDLocation(column: 256, scope: !0)

View File

@ -0,0 +1,9 @@
; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s
!0 = !{}
; CHECK-NOT: error
!1 = !MDLocation(line: 16777215, scope: !0)
; CHECK: <stdin>:[[@LINE+1]]:24: error: value for 'line' too large, limit is 16777215
!2 = !MDLocation(line: 16777216, scope: !0)

View File

@ -0,0 +1,4 @@
; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s
; CHECK: <stdin>:[[@LINE+1]]:6: error: expected metadata type
!0 = !Invalid(field: 0)

View File

@ -0,0 +1,20 @@
; RUN: llvm-as < %s | llvm-dis | FileCheck %s
; RUN: verify-uselistorder %s
; CHECK: !named = !{!0, !1, !1, !2, !2, !3, !3}
!named = !{!0, !1, !2, !3, !4, !5, !6}
; CHECK: !0 = !{}
!0 = !{}
; CHECK-NEXT: !1 = !MDLocation(line: 3, column: 7, scope: !0)
!1 = !MDLocation(line: 3, column: 7, scope: !0)
!2 = !MDLocation(scope: !0, column: 7, line: 3)
; CHECK-NEXT: !2 = !MDLocation(line: 3, column: 7, scope: !0, inlinedAt: !1)
!3 = !MDLocation(scope: !0, inlinedAt: !1, column: 7, line: 3)
!4 = !MDLocation(column: 7, line: 3, scope: !0, inlinedAt: !1)
; CHECK-NEXT: !3 = !MDLocation(scope: !0)
!5 = !MDLocation(scope: !0)
!6 = !MDLocation(scope: !0, column: 0, line: 0)

View File

@ -62,7 +62,7 @@ syn keyword llvmKeyword uselistorder_bb
syn keyword llvmError getresult begin end syn keyword llvmError getresult begin end
" Misc syntax. " Misc syntax.
syn match llvmNoName /[%@]\d\+\>/ syn match llvmNoName /[%@!]\d\+\>/
syn match llvmNumber /-\?\<\d\+\>/ syn match llvmNumber /-\?\<\d\+\>/
syn match llvmFloat /-\?\<\d\+\.\d*\(e[+-]\d\+\)\?\>/ syn match llvmFloat /-\?\<\d\+\.\d*\(e[+-]\d\+\)\?\>/
syn match llvmFloat /\<0x\x\+\>/ syn match llvmFloat /\<0x\x\+\>/
@ -73,6 +73,11 @@ syn region llvmString start=/"/ skip=/\\"/ end=/"/
syn match llvmLabel /[-a-zA-Z$._][-a-zA-Z$._0-9]*:/ syn match llvmLabel /[-a-zA-Z$._][-a-zA-Z$._0-9]*:/
syn match llvmIdentifier /[%@][-a-zA-Z$._][-a-zA-Z$._0-9]*/ syn match llvmIdentifier /[%@][-a-zA-Z$._][-a-zA-Z$._0-9]*/
" Named metadata and specialized metadata keywords.
syn match llvmIdentifier /![-a-zA-Z$._][-a-zA-Z$._0-9]*\ze\s*$/
syn match llvmIdentifier /![-a-zA-Z$._][-a-zA-Z$._0-9]*\ze\s*[=!]/
syn match llvmType /!\zs\a\+\ze\s*(/
" Syntax-highlight dejagnu test commands. " Syntax-highlight dejagnu test commands.
syn match llvmSpecialComment /;\s*RUN:.*$/ syn match llvmSpecialComment /;\s*RUN:.*$/
syn match llvmSpecialComment /;\s*PR\d*\s*$/ syn match llvmSpecialComment /;\s*PR\d*\s*$/