mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 20:23:11 +01:00
[TableGen] Improve handling of template arguments
This requires changes to TableGen files and some C++ files due to incompatible multiclass template arguments that slipped through before the improved handling.
This commit is contained in:
parent
6f5491a95a
commit
f8fbe9eb04
@ -299,7 +299,7 @@ wide range of records conveniently and compactly.
|
|||||||
:token:`ClassID`
|
:token:`ClassID`
|
||||||
Specifying a class name in a type context indicates
|
Specifying a class name in a type context indicates
|
||||||
that the type of the defined value must
|
that the type of the defined value must
|
||||||
be a subclass of the specified class. This is useful in conjunction with
|
be a subclass of the specified class. This is useful in conjunction with
|
||||||
the ``list`` type; for example, to constrain the elements of the list to a
|
the ``list`` type; for example, to constrain the elements of the list to a
|
||||||
common base class (e.g., a ``list<Register>`` can only contain definitions
|
common base class (e.g., a ``list<Register>`` can only contain definitions
|
||||||
derived from the ``Register`` class).
|
derived from the ``Register`` class).
|
||||||
@ -554,19 +554,22 @@ classes and records can inherit.
|
|||||||
TemplateArgDecl: `Type` `TokIdentifier` ["=" `Value`]
|
TemplateArgDecl: `Type` `TokIdentifier` ["=" `Value`]
|
||||||
|
|
||||||
A class can be parameterized by a list of "template arguments," whose values
|
A class can be parameterized by a list of "template arguments," whose values
|
||||||
can be used in the class's record body. These template arguments are
|
can be used in the class's record body. These template arguments are
|
||||||
specified each time the class is inherited by another class or record.
|
specified each time the class is inherited by another class or record.
|
||||||
|
|
||||||
If a template argument is not assigned a default value with ``=``, it is
|
If a template argument is not assigned a default value with ``=``, it is
|
||||||
uninitialized (has the "value" ``?``) and must be specified in the template
|
uninitialized (has the "value" ``?``) and must be specified in the template
|
||||||
argument list when the class is inherited. If an argument is assigned a
|
argument list when the class is inherited (required argument). If an
|
||||||
default value, then it need not be specified in the argument list. The
|
argument is assigned a default value, then it need not be specified in the
|
||||||
template argument default values are evaluated from left to right.
|
argument list (optional argument). In the declaration, all required template
|
||||||
|
arguments must precede any optional arguments. The template argument default
|
||||||
|
values are evaluated from left to right.
|
||||||
|
|
||||||
The :token:`RecordBody` is defined below. It can include a list of
|
The :token:`RecordBody` is defined below. It can include a list of
|
||||||
superclasses from which the current class inherits, along with field definitions
|
superclasses from which the current class inherits, along with field
|
||||||
and other statements. When a class ``C`` inherits from another class ``D``,
|
definitions and other statements. When a class ``C`` inherits from another
|
||||||
the fields of ``D`` are effectively merged into the fields of ``C``.
|
class ``D``, the fields of ``D`` are effectively merged into the fields of
|
||||||
|
``C``.
|
||||||
|
|
||||||
A given class can only be defined once. A ``class`` statement is
|
A given class can only be defined once. A ``class`` statement is
|
||||||
considered to define the class if *any* of the following are true (the
|
considered to define the class if *any* of the following are true (the
|
||||||
@ -605,7 +608,7 @@ of the fields of the class or record.
|
|||||||
RecordBody: `ParentClassList` `Body`
|
RecordBody: `ParentClassList` `Body`
|
||||||
ParentClassList: [":" `ParentClassListNE`]
|
ParentClassList: [":" `ParentClassListNE`]
|
||||||
ParentClassListNE: `ClassRef` ("," `ClassRef`)*
|
ParentClassListNE: `ClassRef` ("," `ClassRef`)*
|
||||||
ClassRef: (`ClassID` | `MultiClassID`) ["<" `ValueList` ">"]
|
ClassRef: (`ClassID` | `MultiClassID`) ["<" [`ValueList`] ">"]
|
||||||
|
|
||||||
A :token:`ParentClassList` containing a :token:`MultiClassID` is valid only
|
A :token:`ParentClassList` containing a :token:`MultiClassID` is valid only
|
||||||
in the class list of a ``defm`` statement. In that case, the ID must be the
|
in the class list of a ``defm`` statement. In that case, the ID must be the
|
||||||
|
@ -2024,6 +2024,12 @@ public:
|
|||||||
|
|
||||||
void set(Init *Key, Init *Value) { Map[Key] = {Value, false}; }
|
void set(Init *Key, Init *Value) { Map[Key] = {Value, false}; }
|
||||||
|
|
||||||
|
bool isComplete(Init *VarName) const {
|
||||||
|
auto It = Map.find(VarName);
|
||||||
|
assert(It != Map.end() && "key must be present in map");
|
||||||
|
return It->second.V->isComplete();
|
||||||
|
}
|
||||||
|
|
||||||
Init *resolve(Init *VarName) override;
|
Init *resolve(Init *VarName) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2344,13 +2344,13 @@ void Record::resolveReferences(Resolver &R, const RecordVal *SkipVal) {
|
|||||||
if (TypedInit *VRT = dyn_cast<TypedInit>(VR))
|
if (TypedInit *VRT = dyn_cast<TypedInit>(VR))
|
||||||
Type =
|
Type =
|
||||||
(Twine("of type '") + VRT->getType()->getAsString() + "' ").str();
|
(Twine("of type '") + VRT->getType()->getAsString() + "' ").str();
|
||||||
PrintFatalError(getLoc(), Twine("Invalid value ") + Type +
|
PrintFatalError(
|
||||||
"is found when setting '" +
|
getLoc(),
|
||||||
Value.getNameInitAsString() +
|
Twine("Invalid value ") + Type + "found when setting field '" +
|
||||||
"' of type '" +
|
Value.getNameInitAsString() + "' of type '" +
|
||||||
Value.getType()->getAsString() +
|
Value.getType()->getAsString() +
|
||||||
"' after resolving references: " +
|
"' after resolving references: " + VR->getAsUnquotedString() +
|
||||||
VR->getAsUnquotedString() + "\n");
|
"\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,38 +229,33 @@ bool TGParser::SetValue(Record *CurRec, SMLoc Loc, Init *ValName,
|
|||||||
/// args as SubClass's template arguments.
|
/// args as SubClass's template arguments.
|
||||||
bool TGParser::AddSubClass(Record *CurRec, SubClassReference &SubClass) {
|
bool TGParser::AddSubClass(Record *CurRec, SubClassReference &SubClass) {
|
||||||
Record *SC = SubClass.Rec;
|
Record *SC = SubClass.Rec;
|
||||||
// Add all of the values in the subclass into the current class.
|
|
||||||
for (const RecordVal &Val : SC->getValues())
|
|
||||||
if (AddValue(CurRec, SubClass.RefRange.Start, Val))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
ArrayRef<Init *> TArgs = SC->getTemplateArgs();
|
|
||||||
|
|
||||||
// Ensure that an appropriate number of template arguments are specified.
|
|
||||||
if (TArgs.size() < SubClass.TemplateArgs.size())
|
|
||||||
return Error(SubClass.RefRange.Start,
|
|
||||||
"More template args specified than expected");
|
|
||||||
|
|
||||||
// Loop over all of the template arguments, setting them to the specified
|
|
||||||
// value or leaving them as the default if necessary.
|
|
||||||
MapResolver R(CurRec);
|
MapResolver R(CurRec);
|
||||||
|
|
||||||
for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
|
// Loop over all the subclass record's fields. Add template arguments
|
||||||
if (i < SubClass.TemplateArgs.size()) {
|
// to the resolver map. Add regular fields to the new record.
|
||||||
// If a value is specified for this template arg, set it now.
|
for (const RecordVal &Field : SC->getValues()) {
|
||||||
if (SetValue(CurRec, SubClass.RefRange.Start, TArgs[i],
|
if (Field.isTemplateArg()) {
|
||||||
None, SubClass.TemplateArgs[i]))
|
R.set(Field.getNameInit(), Field.getValue());
|
||||||
|
} else {
|
||||||
|
if (AddValue(CurRec, SubClass.RefRange.Start, Field))
|
||||||
return true;
|
return true;
|
||||||
} else if (!CurRec->getValue(TArgs[i])->getValue()->isComplete()) {
|
|
||||||
return Error(SubClass.RefRange.Start,
|
|
||||||
"Value not specified for template argument #" +
|
|
||||||
Twine(i) + " (" + TArgs[i]->getAsUnquotedString() +
|
|
||||||
") of subclass '" + SC->getNameInitAsString() + "'!");
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
R.set(TArgs[i], CurRec->getValue(TArgs[i])->getValue());
|
ArrayRef<Init *> TArgs = SC->getTemplateArgs();
|
||||||
|
assert(SubClass.TemplateArgs.size() <= TArgs.size() &&
|
||||||
|
"Too many template arguments allowed");
|
||||||
|
|
||||||
CurRec->removeValue(TArgs[i]);
|
// Loop over the template argument names. If a value was specified,
|
||||||
|
// reset the map value. If not and there was no default, complain.
|
||||||
|
for (unsigned I = 0, E = TArgs.size(); I != E; ++I) {
|
||||||
|
if (I < SubClass.TemplateArgs.size())
|
||||||
|
R.set(TArgs[I], SubClass.TemplateArgs[I]);
|
||||||
|
else if (!R.isComplete(TArgs[I]))
|
||||||
|
return Error(SubClass.RefRange.Start,
|
||||||
|
"Value not specified for template argument '" +
|
||||||
|
TArgs[I]->getAsUnquotedString() + "' (#" + Twine(I) +
|
||||||
|
") of parent class '" + SC->getNameInitAsString() + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
Init *Name;
|
Init *Name;
|
||||||
@ -584,8 +579,8 @@ MultiClass *TGParser::ParseMultiClassID() {
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ParseSubClassReference - Parse a reference to a subclass or to a templated
|
/// ParseSubClassReference - Parse a reference to a subclass or a
|
||||||
/// subclass. This returns a SubClassRefTy with a null Record* on error.
|
/// multiclass. This returns a SubClassRefTy with a null Record* on error.
|
||||||
///
|
///
|
||||||
/// SubClassRef ::= ClassID
|
/// SubClassRef ::= ClassID
|
||||||
/// SubClassRef ::= ClassID '<' ValueList '>'
|
/// SubClassRef ::= ClassID '<' ValueList '>'
|
||||||
@ -609,25 +604,18 @@ ParseSubClassReference(Record *CurRec, bool isDefm) {
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Lex.getCode() == tgtok::greater) {
|
if (ParseTemplateArgValueList(Result.TemplateArgs, CurRec, Result.Rec)) {
|
||||||
TokError("subclass reference requires a non-empty list of template values");
|
Result.Rec = nullptr; // Error parsing value list.
|
||||||
Result.Rec = nullptr;
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseValueList(Result.TemplateArgs, CurRec, Result.Rec);
|
if (CheckTemplateArgValues(Result.TemplateArgs, Result.RefRange.Start,
|
||||||
if (Result.TemplateArgs.empty()) {
|
Result.Rec)) {
|
||||||
Result.Rec = nullptr; // Error parsing value list.
|
Result.Rec = nullptr; // Error checking value list.
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!consume(tgtok::greater)) {
|
|
||||||
TokError("expected '>' in template value list");
|
|
||||||
Result.Rec = nullptr;
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
Result.RefRange.End = Lex.getLoc();
|
Result.RefRange.End = Lex.getLoc();
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,23 +640,12 @@ ParseSubMultiClassReference(MultiClass *CurMC) {
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Lex.getCode() == tgtok::greater) {
|
if (ParseTemplateArgValueList(Result.TemplateArgs, &CurMC->Rec,
|
||||||
TokError("subclass reference requires a non-empty list of template values");
|
&Result.MC->Rec)) {
|
||||||
Result.MC = nullptr;
|
Result.MC = nullptr; // Error parsing value list.
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseValueList(Result.TemplateArgs, &CurMC->Rec, &Result.MC->Rec);
|
|
||||||
if (Result.TemplateArgs.empty()) {
|
|
||||||
Result.MC = nullptr; // Error parsing value list.
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!consume(tgtok::greater)) {
|
|
||||||
TokError("expected '>' in template value list");
|
|
||||||
Result.MC = nullptr;
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
Result.RefRange.End = Lex.getLoc();
|
Result.RefRange.End = Lex.getLoc();
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
@ -2032,15 +2009,9 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
|
|||||||
if (Lex.Lex() != tgtok::less) // consume the Id.
|
if (Lex.Lex() != tgtok::less) // consume the Id.
|
||||||
return ParseIDValue(CurRec, Name, NameLoc, Mode); // Value ::= IDValue
|
return ParseIDValue(CurRec, Name, NameLoc, Mode); // Value ::= IDValue
|
||||||
|
|
||||||
// Value ::= ID '<' ValueListNE '>'
|
// Value ::= CLASSID '<' ValueListNE '>' (CLASSID has been consumed)
|
||||||
if (Lex.Lex() == tgtok::greater) {
|
// This is supposed to synthesize a new anonymous definition, deriving
|
||||||
TokError("expected non-empty value list");
|
// from the class with the template arguments, but no body.
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a CLASS<initvalslist> expression. This is supposed to synthesize
|
|
||||||
// a new anonymous definition, deriving from CLASS<initvalslist> with no
|
|
||||||
// body.
|
|
||||||
Record *Class = Records.getClass(Name->getValue());
|
Record *Class = Records.getClass(Name->getValue());
|
||||||
if (!Class) {
|
if (!Class) {
|
||||||
Error(NameLoc, "Expected a class name, got '" + Name->getValue() + "'");
|
Error(NameLoc, "Expected a class name, got '" + Name->getValue() + "'");
|
||||||
@ -2048,44 +2019,26 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
|
|||||||
}
|
}
|
||||||
|
|
||||||
SmallVector<Init *, 8> Args;
|
SmallVector<Init *, 8> Args;
|
||||||
ParseValueList(Args, CurRec, Class);
|
Lex.Lex(); // consume the <
|
||||||
if (Args.empty()) return nullptr;
|
if (ParseTemplateArgValueList(Args, CurRec, Class))
|
||||||
|
return nullptr; // Error parsing value list.
|
||||||
|
|
||||||
if (!consume(tgtok::greater)) {
|
if (CheckTemplateArgValues(Args, NameLoc, Class))
|
||||||
TokError("expected '>' at end of value list");
|
return nullptr; // Error checking template argument values.
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Typecheck the template arguments list
|
// Loop through the arguments that were not specified and make sure
|
||||||
ArrayRef<Init *> ExpectedArgs = Class->getTemplateArgs();
|
// they have a complete value.
|
||||||
if (ExpectedArgs.size() < Args.size()) {
|
// TODO: If we just keep a required argument count, we can do away
|
||||||
Error(NameLoc,
|
// with this checking.
|
||||||
"More template args specified than expected");
|
ArrayRef<Init *> TArgs = Class->getTemplateArgs();
|
||||||
return nullptr;
|
for (unsigned I = Args.size(), E = TArgs.size(); I < E; ++I) {
|
||||||
}
|
RecordVal *Arg = Class->getValue(TArgs[I]);
|
||||||
|
if (!Arg->getValue()->isComplete())
|
||||||
for (unsigned i = 0, e = ExpectedArgs.size(); i != e; ++i) {
|
Error(NameLoc, "Value not specified for template argument '" +
|
||||||
RecordVal *ExpectedArg = Class->getValue(ExpectedArgs[i]);
|
TArgs[I]->getAsUnquotedString() + "' (#" + Twine(I) +
|
||||||
if (i < Args.size()) {
|
") of parent class '" +
|
||||||
if (TypedInit *TI = dyn_cast<TypedInit>(Args[i])) {
|
Class->getNameInitAsString() + "'");
|
||||||
RecTy *ExpectedType = ExpectedArg->getType();
|
|
||||||
if (!TI->getType()->typeIsConvertibleTo(ExpectedType)) {
|
|
||||||
Error(NameLoc,
|
|
||||||
"Value specified for template argument #" + Twine(i) + " (" +
|
|
||||||
ExpectedArg->getNameInitAsString() + ") is of type '" +
|
|
||||||
TI->getType()->getAsString() + "', expected '" +
|
|
||||||
ExpectedType->getAsString() + "': " + TI->getAsString());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else if (ExpectedArg->getValue()->isComplete())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Error(NameLoc,
|
|
||||||
"Value not specified for template argument #" + Twine(i) + " (" +
|
|
||||||
ExpectedArgs[i]->getAsUnquotedString() + ")");
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return VarDefInit::get(Class, Args)->Fold();
|
return VarDefInit::get(Class, Args)->Fold();
|
||||||
@ -2158,7 +2111,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Lex.getCode() != tgtok::r_square) {
|
if (Lex.getCode() != tgtok::r_square) {
|
||||||
ParseValueList(Vals, CurRec, nullptr,
|
ParseValueList(Vals, CurRec,
|
||||||
GivenListTy ? GivenListTy->getElementType() : nullptr);
|
GivenListTy ? GivenListTy->getElementType() : nullptr);
|
||||||
if (Vals.empty()) return nullptr;
|
if (Vals.empty()) return nullptr;
|
||||||
}
|
}
|
||||||
@ -2522,32 +2475,15 @@ void TGParser::ParseDagArgList(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ParseValueList - Parse a comma separated list of values, returning them as a
|
/// ParseValueList - Parse a comma separated list of values, returning them
|
||||||
/// vector. Note that this always expects to be able to parse at least one
|
/// in a vector. Note that this always expects to be able to parse at least one
|
||||||
/// value. It returns an empty list if this is not possible.
|
/// value. It returns an empty list if this is not possible.
|
||||||
///
|
///
|
||||||
/// ValueList ::= Value (',' Value)
|
/// ValueList ::= Value (',' Value)
|
||||||
///
|
///
|
||||||
void TGParser::ParseValueList(SmallVectorImpl<Init*> &Result, Record *CurRec,
|
void TGParser::ParseValueList(SmallVectorImpl<Init *> &Result, Record *CurRec,
|
||||||
Record *ArgsRec, RecTy *EltTy) {
|
RecTy *ItemType) {
|
||||||
RecTy *ItemType = EltTy;
|
|
||||||
unsigned int ArgN = 0;
|
|
||||||
if (ArgsRec && !EltTy) {
|
|
||||||
ArrayRef<Init *> TArgs = ArgsRec->getTemplateArgs();
|
|
||||||
if (TArgs.empty()) {
|
|
||||||
TokError("template argument provided to non-template class");
|
|
||||||
Result.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const RecordVal *RV = ArgsRec->getValue(TArgs[ArgN]);
|
|
||||||
if (!RV) {
|
|
||||||
errs() << "Cannot find template arg " << ArgN << " (" << TArgs[ArgN]
|
|
||||||
<< ")\n";
|
|
||||||
}
|
|
||||||
assert(RV && "Template argument record not found??");
|
|
||||||
ItemType = RV->getType();
|
|
||||||
++ArgN;
|
|
||||||
}
|
|
||||||
Result.push_back(ParseValue(CurRec, ItemType));
|
Result.push_back(ParseValue(CurRec, ItemType));
|
||||||
if (!Result.back()) {
|
if (!Result.back()) {
|
||||||
Result.clear();
|
Result.clear();
|
||||||
@ -2558,19 +2494,6 @@ void TGParser::ParseValueList(SmallVectorImpl<Init*> &Result, Record *CurRec,
|
|||||||
// ignore trailing comma for lists
|
// ignore trailing comma for lists
|
||||||
if (Lex.getCode() == tgtok::r_square)
|
if (Lex.getCode() == tgtok::r_square)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ArgsRec && !EltTy) {
|
|
||||||
ArrayRef<Init *> TArgs = ArgsRec->getTemplateArgs();
|
|
||||||
if (ArgN >= TArgs.size()) {
|
|
||||||
TokError("too many template arguments");
|
|
||||||
Result.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const RecordVal *RV = ArgsRec->getValue(TArgs[ArgN]);
|
|
||||||
assert(RV && "Template argument record not found??");
|
|
||||||
ItemType = RV->getType();
|
|
||||||
++ArgN;
|
|
||||||
}
|
|
||||||
Result.push_back(ParseValue(CurRec, ItemType));
|
Result.push_back(ParseValue(CurRec, ItemType));
|
||||||
if (!Result.back()) {
|
if (!Result.back()) {
|
||||||
Result.clear();
|
Result.clear();
|
||||||
@ -2579,9 +2502,48 @@ void TGParser::ParseValueList(SmallVectorImpl<Init*> &Result, Record *CurRec,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseTemplateArgValueList - Parse a template argument list with the syntax
|
||||||
|
// shown, filling in the Result vector. The open angle has been consumed.
|
||||||
|
// An empty argument list is allowed. Return false if okay, true if an
|
||||||
|
// error was detected.
|
||||||
|
//
|
||||||
|
// TemplateArgList ::= '<' [Value {',' Value}*] '>'
|
||||||
|
bool TGParser::ParseTemplateArgValueList(SmallVectorImpl<Init *> &Result,
|
||||||
|
Record *CurRec, Record *ArgsRec) {
|
||||||
|
|
||||||
|
assert(Result.empty() && "Result vector is not empty");
|
||||||
|
ArrayRef<Init *> TArgs = ArgsRec->getTemplateArgs();
|
||||||
|
unsigned ArgIndex = 0;
|
||||||
|
RecTy *ItemType;
|
||||||
|
|
||||||
|
if (consume(tgtok::greater)) // empty value list
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (ArgIndex >= TArgs.size()) {
|
||||||
|
TokError("Too many template arguments: " + utostr(ArgIndex + 1));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const RecordVal *Arg = ArgsRec->getValue(TArgs[ArgIndex]);
|
||||||
|
assert(Arg && "Template argument record not found");
|
||||||
|
|
||||||
|
ItemType = Arg->getType();
|
||||||
|
Init *Value = ParseValue(CurRec, ItemType);
|
||||||
|
if (!Value)
|
||||||
|
return true;
|
||||||
|
Result.push_back(Value);
|
||||||
|
|
||||||
|
if (consume(tgtok::greater)) // end of argument list?
|
||||||
|
return false;
|
||||||
|
if (!consume(tgtok::comma)) // must be comma
|
||||||
|
return true;
|
||||||
|
++ArgIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// ParseDeclaration - Read a declaration, returning the name of field ID, or an
|
/// ParseDeclaration - Read a declaration, returning the name of field ID, or an
|
||||||
/// empty string on error. This can happen in a number of different context's,
|
/// empty string on error. This can happen in a number of different contexts,
|
||||||
/// including within a def or in the template args for a def (which which case
|
/// including within a def or in the template args for a class (in which case
|
||||||
/// CurRec will be non-null) and within the template args for a multiclass (in
|
/// CurRec will be non-null) and within the template args for a multiclass (in
|
||||||
/// which case CurRec will be null, but CurMultiClass will be set). This can
|
/// which case CurRec will be null, but CurMultiClass will be set). This can
|
||||||
/// also happen within a def that is within a multiclass, which will set both
|
/// also happen within a def that is within a multiclass, which will set both
|
||||||
@ -2612,23 +2574,28 @@ Init *TGParser::ParseDeclaration(Record *CurRec,
|
|||||||
Init *DeclName = StringInit::get(Str);
|
Init *DeclName = StringInit::get(Str);
|
||||||
Lex.Lex();
|
Lex.Lex();
|
||||||
|
|
||||||
if (ParsingTemplateArgs) {
|
bool BadField;
|
||||||
if (CurRec)
|
if (!ParsingTemplateArgs) { // def, possibly in a multiclass
|
||||||
DeclName = QualifyName(*CurRec, CurMultiClass, DeclName, ":");
|
BadField = AddValue(CurRec, IdLoc,
|
||||||
else
|
RecordVal(DeclName, IdLoc, Type,
|
||||||
assert(CurMultiClass);
|
HasField ? RecordVal::FK_NonconcreteOK
|
||||||
if (CurMultiClass)
|
: RecordVal::FK_Normal));
|
||||||
DeclName = QualifyName(CurMultiClass->Rec, CurMultiClass, DeclName,
|
|
||||||
"::");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the field to the record.
|
} else if (CurRec) { // class template argument
|
||||||
if (AddValue(CurRec, IdLoc, RecordVal(DeclName, IdLoc, Type,
|
DeclName = QualifyName(*CurRec, CurMultiClass, DeclName, ":");
|
||||||
HasField ? RecordVal::FK_NonconcreteOK
|
BadField = AddValue(CurRec, IdLoc, RecordVal(DeclName, IdLoc, Type,
|
||||||
: RecordVal::FK_Normal)))
|
RecordVal::FK_TemplateArg));
|
||||||
|
|
||||||
|
} else { // multiclass template argument
|
||||||
|
assert(CurMultiClass && "invalid context for template argument");
|
||||||
|
DeclName = QualifyName(CurMultiClass->Rec, CurMultiClass, DeclName, "::");
|
||||||
|
BadField = AddValue(CurRec, IdLoc, RecordVal(DeclName, IdLoc, Type,
|
||||||
|
RecordVal::FK_TemplateArg));
|
||||||
|
}
|
||||||
|
if (BadField)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// If a value is present, parse it.
|
// If a value is present, parse it and set new field's value.
|
||||||
if (consume(tgtok::equal)) {
|
if (consume(tgtok::equal)) {
|
||||||
SMLoc ValLoc = Lex.getLoc();
|
SMLoc ValLoc = Lex.getLoc();
|
||||||
Init *Val = ParseValue(CurRec, Type);
|
Init *Val = ParseValue(CurRec, Type);
|
||||||
@ -2715,7 +2682,7 @@ VarInit *TGParser::ParseForeachDeclaration(Init *&ForeachListValue) {
|
|||||||
if (!Ranges.empty()) {
|
if (!Ranges.empty()) {
|
||||||
assert(!IterType && "Type already initialized?");
|
assert(!IterType && "Type already initialized?");
|
||||||
IterType = IntRecTy::get();
|
IterType = IntRecTy::get();
|
||||||
std::vector<Init*> Values;
|
std::vector<Init *> Values;
|
||||||
for (unsigned R : Ranges)
|
for (unsigned R : Ranges)
|
||||||
Values.push_back(IntInit::get(R));
|
Values.push_back(IntInit::get(R));
|
||||||
ForeachListValue = ListInit::get(Values, IterType);
|
ForeachListValue = ListInit::get(Values, IterType);
|
||||||
@ -2729,7 +2696,7 @@ VarInit *TGParser::ParseForeachDeclaration(Init *&ForeachListValue) {
|
|||||||
|
|
||||||
/// ParseTemplateArgList - Read a template argument list, which is a non-empty
|
/// ParseTemplateArgList - Read a template argument list, which is a non-empty
|
||||||
/// sequence of template-declarations in <>'s. If CurRec is non-null, these are
|
/// sequence of template-declarations in <>'s. If CurRec is non-null, these are
|
||||||
/// template args for a def, which may or may not be in a multiclass. If null,
|
/// template args for a class, which may or may not be in a multiclass. If null,
|
||||||
/// these are the template args for a multiclass.
|
/// these are the template args for a multiclass.
|
||||||
///
|
///
|
||||||
/// TemplateArgList ::= '<' Declaration (',' Declaration)* '>'
|
/// TemplateArgList ::= '<' Declaration (',' Declaration)* '>'
|
||||||
@ -3493,32 +3460,28 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
|
|||||||
while (true) {
|
while (true) {
|
||||||
if (!Ref.Rec) return true;
|
if (!Ref.Rec) return true;
|
||||||
|
|
||||||
// To instantiate a multiclass, we need to first get the multiclass, then
|
// To instantiate a multiclass, we get the multiclass and then loop
|
||||||
// instantiate each def contained in the multiclass with the SubClassRef
|
// through its template argument names. Substs contains a substitution
|
||||||
// template parameters.
|
// value for each argument, either the value specified or the default.
|
||||||
|
// Then we can resolve the template arguments.
|
||||||
MultiClass *MC = MultiClasses[std::string(Ref.Rec->getName())].get();
|
MultiClass *MC = MultiClasses[std::string(Ref.Rec->getName())].get();
|
||||||
assert(MC && "Didn't lookup multiclass correctly?");
|
assert(MC && "Didn't lookup multiclass correctly?");
|
||||||
ArrayRef<Init*> TemplateVals = Ref.TemplateArgs;
|
|
||||||
|
|
||||||
// Verify that the correct number of template arguments were specified.
|
ArrayRef<Init *> TemplateVals = Ref.TemplateArgs;
|
||||||
ArrayRef<Init *> TArgs = MC->Rec.getTemplateArgs();
|
ArrayRef<Init *> TArgs = MC->Rec.getTemplateArgs();
|
||||||
if (TArgs.size() < TemplateVals.size())
|
|
||||||
return Error(SubClassLoc,
|
|
||||||
"more template args specified than multiclass expects");
|
|
||||||
|
|
||||||
SubstStack Substs;
|
SubstStack Substs;
|
||||||
|
|
||||||
for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
|
for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
|
||||||
if (i < TemplateVals.size()) {
|
if (i < TemplateVals.size()) {
|
||||||
Substs.emplace_back(TArgs[i], TemplateVals[i]);
|
Substs.emplace_back(TArgs[i], TemplateVals[i]);
|
||||||
} else {
|
} else {
|
||||||
Init *Default = MC->Rec.getValue(TArgs[i])->getValue();
|
Init *Default = MC->Rec.getValue(TArgs[i])->getValue();
|
||||||
if (!Default->isComplete()) {
|
if (!Default->isComplete())
|
||||||
return Error(SubClassLoc,
|
return Error(SubClassLoc,
|
||||||
"value not specified for template argument #" +
|
"value not specified for template argument '" +
|
||||||
Twine(i) + " (" + TArgs[i]->getAsUnquotedString() +
|
TArgs[i]->getAsUnquotedString() + "' (#" +
|
||||||
") of multiclass '" + MC->Rec.getNameInitAsString() +
|
Twine(i) + ") of multiclass '" +
|
||||||
"'");
|
MC->Rec.getNameInitAsString() + "'");
|
||||||
}
|
|
||||||
Substs.emplace_back(TArgs[i], Default);
|
Substs.emplace_back(TArgs[i], Default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3537,7 +3500,7 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
|
|||||||
|
|
||||||
SubClassLoc = Lex.getLoc();
|
SubClassLoc = Lex.getLoc();
|
||||||
|
|
||||||
// A defm can inherit from regular classes (non-multiclass) as
|
// A defm can inherit from regular classes (non-multiclasses) as
|
||||||
// long as they come in the end of the inheritance list.
|
// long as they come in the end of the inheritance list.
|
||||||
InheritFromClass = (Records.getClass(Lex.getCurStrVal()) != nullptr);
|
InheritFromClass = (Records.getClass(Lex.getCurStrVal()) != nullptr);
|
||||||
|
|
||||||
@ -3642,6 +3605,41 @@ bool TGParser::ParseFile() {
|
|||||||
return TokError("Unexpected token at top level");
|
return TokError("Unexpected token at top level");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check the types of the template argument values for a class
|
||||||
|
// inheritance, multiclass invocation, or anonymous class invocation.
|
||||||
|
// If necessary, replace an argument with a cast to the required type.
|
||||||
|
// The argument count has already been checked.
|
||||||
|
bool TGParser::CheckTemplateArgValues(SmallVectorImpl<llvm::Init *> &Values,
|
||||||
|
SMLoc Loc, Record *ArgsRec) {
|
||||||
|
|
||||||
|
ArrayRef<Init *> TArgs = ArgsRec->getTemplateArgs();
|
||||||
|
|
||||||
|
for (unsigned I = 0, E = Values.size(); I < E; ++I) {
|
||||||
|
RecordVal *Arg = ArgsRec->getValue(TArgs[I]);
|
||||||
|
RecTy *ArgType = Arg->getType();
|
||||||
|
auto *Value = Values[I];
|
||||||
|
|
||||||
|
if (TypedInit *ArgValue = dyn_cast<TypedInit>(Value)) {
|
||||||
|
auto *CastValue = ArgValue->getCastTo(ArgType);
|
||||||
|
if (CastValue) {
|
||||||
|
assert((!isa<TypedInit>(CastValue) ||
|
||||||
|
cast<TypedInit>(CastValue)->getType()->typeIsA(ArgType)) &&
|
||||||
|
"result of template arg value cast has wrong type");
|
||||||
|
Values[I] = CastValue;
|
||||||
|
} else {
|
||||||
|
PrintFatalError(Loc,
|
||||||
|
"Value specified for template argument '" +
|
||||||
|
Arg->getNameInitAsString() + "' (#" + Twine(I) +
|
||||||
|
") is of type " + ArgValue->getType()->getAsString() +
|
||||||
|
"; expected type " + ArgType->getAsString() + ": " +
|
||||||
|
ArgValue->getAsString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Check an assertion: Obtain the condition value and be sure it is true.
|
// Check an assertion: Obtain the condition value and be sure it is true.
|
||||||
// If not, print a nonfatal error along with the message.
|
// If not, print a nonfatal error along with the message.
|
||||||
void TGParser::CheckAssert(SMLoc Loc, Init *Condition, Init *Message) {
|
void TGParser::CheckAssert(SMLoc Loc, Init *Condition, Init *Message) {
|
||||||
|
@ -243,8 +243,10 @@ private: // Parser methods.
|
|||||||
IDParseMode Mode = ParseValueMode);
|
IDParseMode Mode = ParseValueMode);
|
||||||
Init *ParseValue(Record *CurRec, RecTy *ItemType = nullptr,
|
Init *ParseValue(Record *CurRec, RecTy *ItemType = nullptr,
|
||||||
IDParseMode Mode = ParseValueMode);
|
IDParseMode Mode = ParseValueMode);
|
||||||
void ParseValueList(SmallVectorImpl<llvm::Init*> &Result, Record *CurRec,
|
void ParseValueList(SmallVectorImpl<llvm::Init*> &Result,
|
||||||
Record *ArgsRec = nullptr, RecTy *EltTy = nullptr);
|
Record *CurRec, RecTy *ItemType = nullptr);
|
||||||
|
bool ParseTemplateArgValueList(SmallVectorImpl<llvm::Init *> &Result,
|
||||||
|
Record *CurRec, Record *ArgsRec);
|
||||||
void ParseDagArgList(
|
void ParseDagArgList(
|
||||||
SmallVectorImpl<std::pair<llvm::Init*, StringInit*>> &Result,
|
SmallVectorImpl<std::pair<llvm::Init*, StringInit*>> &Result,
|
||||||
Record *CurRec);
|
Record *CurRec);
|
||||||
@ -264,6 +266,8 @@ private: // Parser methods.
|
|||||||
MultiClass *ParseMultiClassID();
|
MultiClass *ParseMultiClassID();
|
||||||
bool ApplyLetStack(Record *CurRec);
|
bool ApplyLetStack(Record *CurRec);
|
||||||
bool ApplyLetStack(RecordsEntry &Entry);
|
bool ApplyLetStack(RecordsEntry &Entry);
|
||||||
|
bool CheckTemplateArgValues(SmallVectorImpl<llvm::Init *> &Values,
|
||||||
|
SMLoc Loc, Record *ArgsRec);
|
||||||
void CheckAssert(SMLoc Loc, Init *Condition, Init *Message);
|
void CheckAssert(SMLoc Loc, Init *Condition, Init *Message);
|
||||||
void CheckRecordAsserts(Record &Rec);
|
void CheckRecordAsserts(Record &Rec);
|
||||||
};
|
};
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
// RUN: not llvm-tblgen %s 2>&1 | FileCheck %s
|
// RUN: not llvm-tblgen %s 2>&1 | FileCheck %s
|
||||||
// XFAIL: vg_leak
|
// XFAIL: vg_leak
|
||||||
|
|
||||||
class A<A x> {
|
class Cl<Cl rec> {
|
||||||
A a = x;
|
Cl Arec = rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
// At the time A0 is referenced, A has not yet been established as a superclass.
|
// At the time A0 is referenced, A has not yet been established as a superclass.
|
||||||
// This kind of self-reference is discourage, but if you *really* want it, you
|
// This kind of self-reference is discourage, but if you *really* want it, you
|
||||||
// can force it with !cast.
|
// can force it with !cast.
|
||||||
//
|
//
|
||||||
// CHECK: Field 'A:x' of type 'A' is incompatible with value
|
// CHECK: alue specified for template argument 'Cl:rec'
|
||||||
def A0 : A<A0>;
|
|
||||||
|
def Rec0 : Cl<Rec0>;
|
||||||
|
142
test/TableGen/template-args.td
Normal file
142
test/TableGen/template-args.td
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
// RUN: llvm-tblgen %s | FileCheck %s
|
||||||
|
// RUN: not llvm-tblgen -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s
|
||||||
|
// RUN: not llvm-tblgen -DERROR2 %s 2>&1 | FileCheck --check-prefix=ERROR2 %s
|
||||||
|
// RUN: not llvm-tblgen -DERROR3 %s 2>&1 | FileCheck --check-prefix=ERROR3 %s
|
||||||
|
// RUN: not llvm-tblgen -DERROR4 %s 2>&1 | FileCheck --check-prefix=ERROR4 %s
|
||||||
|
// RUN: not llvm-tblgen -DERROR5 %s 2>&1 | FileCheck --check-prefix=ERROR5 %s
|
||||||
|
// RUN: not llvm-tblgen -DERROR6 %s 2>&1 | FileCheck --check-prefix=ERROR6 %s
|
||||||
|
|
||||||
|
// This file tests that template arguments are type-checked and cast
|
||||||
|
// if necessary.
|
||||||
|
|
||||||
|
// Class template arguments.
|
||||||
|
|
||||||
|
class Class1<string nm> {
|
||||||
|
string Name = nm;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: def Rec1
|
||||||
|
// CHECK: string Name = "Alice"
|
||||||
|
// CHECK: string NameName = "AliceAlice"
|
||||||
|
|
||||||
|
def Rec1 : Class1<"Alice"> {
|
||||||
|
string NameName = Name # Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ERROR1
|
||||||
|
// ERROR1: Value specified for template argument 'Class1:nm' (#0) is of type int
|
||||||
|
|
||||||
|
def Rec2 : Class1<42> {
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class Class2<bits<8> cd> {
|
||||||
|
int Code = cd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: def Rec3
|
||||||
|
// CHECK: int Code = 42
|
||||||
|
// CHECK: list<int> CodeList = [42]
|
||||||
|
|
||||||
|
def Rec3 : Class2<0b00101010> {
|
||||||
|
list<int> CodeList = [Code];
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: def Rec4
|
||||||
|
// CHECK: int Code = 42
|
||||||
|
// CHECK: list<int> CodeList = [42]
|
||||||
|
|
||||||
|
def Rec4 : Class2<42> {
|
||||||
|
list<int> CodeList = [Code];
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ERROR2
|
||||||
|
// ERROR2: Value specified for template argument 'Class2:cd' (#0) is of type string
|
||||||
|
|
||||||
|
def Rec5 : Class2<"oops"> {
|
||||||
|
list<int> CodeList = [Code];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Anonymous class instantiation template arguments.
|
||||||
|
|
||||||
|
// CHECK: def Rec6
|
||||||
|
// CHECK: string Name = "Ted"
|
||||||
|
|
||||||
|
def Rec6 {
|
||||||
|
string Name = Class1<"Ted">.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ERROR3
|
||||||
|
// ERROR3: Value specified for template argument 'Class1:nm' (#0) is of type int
|
||||||
|
|
||||||
|
def Rec7 {
|
||||||
|
string Name = Class1<42>.Name;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// CHECK: def Rec8
|
||||||
|
// CHECK: list<int> CodeList = [42]
|
||||||
|
|
||||||
|
def Rec8 {
|
||||||
|
list<int> CodeList = [Class2<42>.Code];
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ERROR4
|
||||||
|
// ERROR4: Value specified for template argument 'Class2:cd' (#0) is of type string
|
||||||
|
|
||||||
|
def Rec9 {
|
||||||
|
list<int> CodeList = [Class2<"huh?">.Code];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Multiclass template arguments.
|
||||||
|
|
||||||
|
multiclass MC1<string nm> {
|
||||||
|
def _1 {
|
||||||
|
string Name = nm;
|
||||||
|
}
|
||||||
|
def _2 {
|
||||||
|
string NameNmae = nm # nm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: def RecMC1_1
|
||||||
|
// CHECK: string Name = "Carol"
|
||||||
|
// CHECK: def RecMC1_2
|
||||||
|
// CHECK: string NameNmae = "CarolCarol"
|
||||||
|
|
||||||
|
defm RecMC1 : MC1<"Carol">;
|
||||||
|
|
||||||
|
#ifdef ERROR5
|
||||||
|
// ERROR5: Value specified for template argument 'MC1::nm' (#0) is of type int
|
||||||
|
|
||||||
|
defm RecMC2 : MC1<42>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
multiclass MC2<bits<8> cd> {
|
||||||
|
def _1 {
|
||||||
|
bits<8> Code = cd;
|
||||||
|
}
|
||||||
|
def _2 {
|
||||||
|
int Code = cd;
|
||||||
|
}
|
||||||
|
def _3 {
|
||||||
|
list<int> CodeList = [cd];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: def RecMC3_1
|
||||||
|
// CHECK: bits<8> Code = { 0, 0, 1, 0, 1, 0, 1, 0 }
|
||||||
|
// CHECK: def RecMC3_2
|
||||||
|
// CHECK: int Code = 42
|
||||||
|
// CHECK: def RecMC3_3
|
||||||
|
// CHECK: list<int> CodeList = [42]
|
||||||
|
|
||||||
|
defm RecMC3 : MC2<42>;
|
||||||
|
|
||||||
|
#ifdef ERROR6
|
||||||
|
// ERROR6: Value specified for template argument 'MC2::cd' (#0) is of type string
|
||||||
|
|
||||||
|
defm RecMC4 : MC2<"Bob">;
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user