1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 03:02:36 +01:00
llvm-mirror/lib/TableGen/TGParser.cpp
J-Y You 3d86bcfc2f [TableGen] Fix instantiating multiclass in foreach
If multiclass argument comes from loop varaible and argument is record type,
it will not recognize the type. This patch ensures that loop variables are
resolved correctly.

Differential Revision: https://reviews.llvm.org/D95308
2021-01-29 10:25:33 -05:00

3702 lines
111 KiB
C++

//===- TGParser.cpp - Parser for TableGen Files ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Implement the Parser for TableGen.
//
//===----------------------------------------------------------------------===//
#include "TGParser.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SourceMgr.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <limits>
using namespace llvm;
//===----------------------------------------------------------------------===//
// Support Code for the Semantic Actions.
//===----------------------------------------------------------------------===//
namespace llvm {
struct SubClassReference {
SMRange RefRange;
Record *Rec;
SmallVector<Init*, 4> TemplateArgs;
SubClassReference() : Rec(nullptr) {}
bool isInvalid() const { return Rec == nullptr; }
};
struct SubMultiClassReference {
SMRange RefRange;
MultiClass *MC;
SmallVector<Init*, 4> TemplateArgs;
SubMultiClassReference() : MC(nullptr) {}
bool isInvalid() const { return MC == nullptr; }
void dump() const;
};
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void SubMultiClassReference::dump() const {
errs() << "Multiclass:\n";
MC->dump();
errs() << "Template args:\n";
for (Init *TA : TemplateArgs)
TA->dump();
}
#endif
} // end namespace llvm
static bool checkBitsConcrete(Record &R, const RecordVal &RV) {
BitsInit *BV = cast<BitsInit>(RV.getValue());
for (unsigned i = 0, e = BV->getNumBits(); i != e; ++i) {
Init *Bit = BV->getBit(i);
bool IsReference = false;
if (auto VBI = dyn_cast<VarBitInit>(Bit)) {
if (auto VI = dyn_cast<VarInit>(VBI->getBitVar())) {
if (R.getValue(VI->getName()))
IsReference = true;
}
} else if (isa<VarInit>(Bit)) {
IsReference = true;
}
if (!(IsReference || Bit->isConcrete()))
return false;
}
return true;
}
static void checkConcrete(Record &R) {
for (const RecordVal &RV : R.getValues()) {
// HACK: Disable this check for variables declared with 'field'. This is
// done merely because existing targets have legitimate cases of
// non-concrete variables in helper defs. Ideally, we'd introduce a
// 'maybe' or 'optional' modifier instead of this.
if (RV.isNonconcreteOK())
continue;
if (Init *V = RV.getValue()) {
bool Ok = isa<BitsInit>(V) ? checkBitsConcrete(R, RV) : V->isConcrete();
if (!Ok) {
PrintError(R.getLoc(),
Twine("Initializer of '") + RV.getNameInitAsString() +
"' in '" + R.getNameInitAsString() +
"' could not be fully resolved: " +
RV.getValue()->getAsString());
}
}
}
}
/// Return an Init with a qualifier prefix referring
/// to CurRec's name.
static Init *QualifyName(Record &CurRec, MultiClass *CurMultiClass,
Init *Name, StringRef Scoper) {
Init *NewName =
BinOpInit::getStrConcat(CurRec.getNameInit(), StringInit::get(Scoper));
NewName = BinOpInit::getStrConcat(NewName, Name);
if (CurMultiClass && Scoper != "::") {
Init *Prefix = BinOpInit::getStrConcat(CurMultiClass->Rec.getNameInit(),
StringInit::get("::"));
NewName = BinOpInit::getStrConcat(Prefix, NewName);
}
if (BinOpInit *BinOp = dyn_cast<BinOpInit>(NewName))
NewName = BinOp->Fold(&CurRec);
return NewName;
}
/// Return the qualified version of the implicit 'NAME' template argument.
static Init *QualifiedNameOfImplicitName(Record &Rec,
MultiClass *MC = nullptr) {
return QualifyName(Rec, MC, StringInit::get("NAME"), MC ? "::" : ":");
}
static Init *QualifiedNameOfImplicitName(MultiClass *MC) {
return QualifiedNameOfImplicitName(MC->Rec, MC);
}
bool TGParser::AddValue(Record *CurRec, SMLoc Loc, const RecordVal &RV) {
if (!CurRec)
CurRec = &CurMultiClass->Rec;
if (RecordVal *ERV = CurRec->getValue(RV.getNameInit())) {
// The value already exists in the class, treat this as a set.
if (ERV->setValue(RV.getValue()))
return Error(Loc, "New definition of '" + RV.getName() + "' of type '" +
RV.getType()->getAsString() + "' is incompatible with " +
"previous definition of type '" +
ERV->getType()->getAsString() + "'");
} else {
CurRec->addValue(RV);
}
return false;
}
/// SetValue -
/// Return true on error, false on success.
bool TGParser::SetValue(Record *CurRec, SMLoc Loc, Init *ValName,
ArrayRef<unsigned> BitList, Init *V,
bool AllowSelfAssignment) {
if (!V) return false;
if (!CurRec) CurRec = &CurMultiClass->Rec;
RecordVal *RV = CurRec->getValue(ValName);
if (!RV)
return Error(Loc, "Value '" + ValName->getAsUnquotedString() +
"' unknown!");
// Do not allow assignments like 'X = X'. This will just cause infinite loops
// in the resolution machinery.
if (BitList.empty())
if (VarInit *VI = dyn_cast<VarInit>(V))
if (VI->getNameInit() == ValName && !AllowSelfAssignment)
return Error(Loc, "Recursion / self-assignment forbidden");
// If we are assigning to a subset of the bits in the value... then we must be
// assigning to a field of BitsRecTy, which must have a BitsInit
// initializer.
//
if (!BitList.empty()) {
BitsInit *CurVal = dyn_cast<BitsInit>(RV->getValue());
if (!CurVal)
return Error(Loc, "Value '" + ValName->getAsUnquotedString() +
"' is not a bits type");
// Convert the incoming value to a bits type of the appropriate size...
Init *BI = V->getCastTo(BitsRecTy::get(BitList.size()));
if (!BI)
return Error(Loc, "Initializer is not compatible with bit range");
SmallVector<Init *, 16> NewBits(CurVal->getNumBits());
// Loop over bits, assigning values as appropriate.
for (unsigned i = 0, e = BitList.size(); i != e; ++i) {
unsigned Bit = BitList[i];
if (NewBits[Bit])
return Error(Loc, "Cannot set bit #" + Twine(Bit) + " of value '" +
ValName->getAsUnquotedString() + "' more than once");
NewBits[Bit] = BI->getBit(i);
}
for (unsigned i = 0, e = CurVal->getNumBits(); i != e; ++i)
if (!NewBits[i])
NewBits[i] = CurVal->getBit(i);
V = BitsInit::get(NewBits);
}
if (RV->setValue(V, Loc)) {
std::string InitType;
if (BitsInit *BI = dyn_cast<BitsInit>(V))
InitType = (Twine("' of type bit initializer with length ") +
Twine(BI->getNumBits())).str();
else if (TypedInit *TI = dyn_cast<TypedInit>(V))
InitType = (Twine("' of type '") + TI->getType()->getAsString()).str();
return Error(Loc, "Field '" + ValName->getAsUnquotedString() +
"' of type '" + RV->getType()->getAsString() +
"' is incompatible with value '" +
V->getAsString() + InitType + "'");
}
return false;
}
/// AddSubClass - Add SubClass as a subclass to CurRec, resolving its template
/// args as SubClass's template arguments.
bool TGParser::AddSubClass(Record *CurRec, SubClassReference &SubClass) {
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);
for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
if (i < SubClass.TemplateArgs.size()) {
// If a value is specified for this template arg, set it now.
if (SetValue(CurRec, SubClass.RefRange.Start, TArgs[i],
None, SubClass.TemplateArgs[i]))
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());
CurRec->removeValue(TArgs[i]);
}
Init *Name;
if (CurRec->isClass())
Name =
VarInit::get(QualifiedNameOfImplicitName(*CurRec), StringRecTy::get());
else
Name = CurRec->getNameInit();
R.set(QualifiedNameOfImplicitName(*SC), Name);
CurRec->resolveReferences(R);
// Since everything went well, we can now set the "superclass" list for the
// current record.
ArrayRef<std::pair<Record *, SMRange>> SCs = SC->getSuperClasses();
for (const auto &SCPair : SCs) {
if (CurRec->isSubClassOf(SCPair.first))
return Error(SubClass.RefRange.Start,
"Already subclass of '" + SCPair.first->getName() + "'!\n");
CurRec->addSuperClass(SCPair.first, SCPair.second);
}
if (CurRec->isSubClassOf(SC))
return Error(SubClass.RefRange.Start,
"Already subclass of '" + SC->getName() + "'!\n");
CurRec->addSuperClass(SC, SubClass.RefRange);
return false;
}
bool TGParser::AddSubClass(RecordsEntry &Entry, SubClassReference &SubClass) {
if (Entry.Rec)
return AddSubClass(Entry.Rec.get(), SubClass);
for (auto &E : Entry.Loop->Entries) {
if (AddSubClass(E, SubClass))
return true;
}
return false;
}
/// AddSubMultiClass - Add SubMultiClass as a subclass to
/// CurMC, resolving its template args as SubMultiClass's
/// template arguments.
bool TGParser::AddSubMultiClass(MultiClass *CurMC,
SubMultiClassReference &SubMultiClass) {
MultiClass *SMC = SubMultiClass.MC;
ArrayRef<Init *> SMCTArgs = SMC->Rec.getTemplateArgs();
if (SMCTArgs.size() < SubMultiClass.TemplateArgs.size())
return Error(SubMultiClass.RefRange.Start,
"More template args specified than expected");
// Prepare the mapping of template argument name to value, filling in default
// values if necessary.
SubstStack TemplateArgs;
for (unsigned i = 0, e = SMCTArgs.size(); i != e; ++i) {
if (i < SubMultiClass.TemplateArgs.size()) {
TemplateArgs.emplace_back(SMCTArgs[i], SubMultiClass.TemplateArgs[i]);
} else {
Init *Default = SMC->Rec.getValue(SMCTArgs[i])->getValue();
if (!Default->isComplete()) {
return Error(SubMultiClass.RefRange.Start,
"value not specified for template argument #" + Twine(i) +
" (" + SMCTArgs[i]->getAsUnquotedString() +
") of multiclass '" + SMC->Rec.getNameInitAsString() +
"'");
}
TemplateArgs.emplace_back(SMCTArgs[i], Default);
}
}
TemplateArgs.emplace_back(
QualifiedNameOfImplicitName(SMC),
VarInit::get(QualifiedNameOfImplicitName(CurMC), StringRecTy::get()));
// Add all of the defs in the subclass into the current multiclass.
return resolve(SMC->Entries, TemplateArgs, false, &CurMC->Entries);
}
/// Add a record or foreach loop to the current context (global record keeper,
/// current inner-most foreach loop, or multiclass).
bool TGParser::addEntry(RecordsEntry E) {
assert(!E.Rec || !E.Loop);
if (!Loops.empty()) {
Loops.back()->Entries.push_back(std::move(E));
return false;
}
if (E.Loop) {
SubstStack Stack;
return resolve(*E.Loop, Stack, CurMultiClass == nullptr,
CurMultiClass ? &CurMultiClass->Entries : nullptr);
}
if (CurMultiClass) {
CurMultiClass->Entries.push_back(std::move(E));
return false;
}
return addDefOne(std::move(E.Rec));
}
/// Resolve the entries in \p Loop, going over inner loops recursively
/// and making the given subsitutions of (name, value) pairs.
///
/// The resulting records are stored in \p Dest if non-null. Otherwise, they
/// are added to the global record keeper.
bool TGParser::resolve(const ForeachLoop &Loop, SubstStack &Substs,
bool Final, std::vector<RecordsEntry> *Dest,
SMLoc *Loc) {
MapResolver R;
for (const auto &S : Substs)
R.set(S.first, S.second);
Init *List = Loop.ListValue->resolveReferences(R);
auto LI = dyn_cast<ListInit>(List);
if (!LI) {
if (!Final) {
Dest->emplace_back(std::make_unique<ForeachLoop>(Loop.Loc, Loop.IterVar,
List));
return resolve(Loop.Entries, Substs, Final, &Dest->back().Loop->Entries,
Loc);
}
PrintError(Loop.Loc, Twine("attempting to loop over '") +
List->getAsString() + "', expected a list");
return true;
}
bool Error = false;
for (auto Elt : *LI) {
if (Loop.IterVar)
Substs.emplace_back(Loop.IterVar->getNameInit(), Elt);
Error = resolve(Loop.Entries, Substs, Final, Dest);
if (Loop.IterVar)
Substs.pop_back();
if (Error)
break;
}
return Error;
}
/// Resolve the entries in \p Source, going over loops recursively and
/// making the given substitutions of (name, value) pairs.
///
/// The resulting records are stored in \p Dest if non-null. Otherwise, they
/// are added to the global record keeper.
bool TGParser::resolve(const std::vector<RecordsEntry> &Source,
SubstStack &Substs, bool Final,
std::vector<RecordsEntry> *Dest, SMLoc *Loc) {
bool Error = false;
for (auto &E : Source) {
if (E.Loop) {
Error = resolve(*E.Loop, Substs, Final, Dest);
} else {
auto Rec = std::make_unique<Record>(*E.Rec);
if (Loc)
Rec->appendLoc(*Loc);
MapResolver R(Rec.get());
for (const auto &S : Substs)
R.set(S.first, S.second);
Rec->resolveReferences(R);
if (Dest)
Dest->push_back(std::move(Rec));
else
Error = addDefOne(std::move(Rec));
}
if (Error)
break;
}
return Error;
}
/// Resolve the record fully and add it to the record keeper.
bool TGParser::addDefOne(std::unique_ptr<Record> Rec) {
if (Record *Prev = Records.getDef(Rec->getNameInitAsString())) {
if (!Rec->isAnonymous()) {
PrintError(Rec->getLoc(),
"def already exists: " + Rec->getNameInitAsString());
PrintNote(Prev->getLoc(), "location of previous definition");
return true;
}
Rec->setName(Records.getNewAnonymousName());
}
Rec->resolveReferences();
checkConcrete(*Rec);
CheckRecordAsserts(*Rec);
if (!isa<StringInit>(Rec->getNameInit())) {
PrintError(Rec->getLoc(), Twine("record name '") +
Rec->getNameInit()->getAsString() +
"' could not be fully resolved");
return true;
}
// If ObjectBody has template arguments, it's an error.
assert(Rec->getTemplateArgs().empty() && "How'd this get template args?");
for (DefsetRecord *Defset : Defsets) {
DefInit *I = Rec->getDefInit();
if (!I->getType()->typeIsA(Defset->EltTy)) {
PrintError(Rec->getLoc(), Twine("adding record of incompatible type '") +
I->getType()->getAsString() +
"' to defset");
PrintNote(Defset->Loc, "location of defset declaration");
return true;
}
Defset->Elements.push_back(I);
}
Records.addDef(std::move(Rec));
return false;
}
//===----------------------------------------------------------------------===//
// Parser Code
//===----------------------------------------------------------------------===//
/// isObjectStart - Return true if this is a valid first token for a statement.
static bool isObjectStart(tgtok::TokKind K) {
return K == tgtok::Assert || K == tgtok::Class || K == tgtok::Def ||
K == tgtok::Defm || K == tgtok::Defset || K == tgtok::Defvar ||
K == tgtok::Foreach || K == tgtok::If || K == tgtok::Let ||
K == tgtok::MultiClass;
}
bool TGParser::consume(tgtok::TokKind K) {
if (Lex.getCode() == K) {
Lex.Lex();
return true;
}
return false;
}
/// ParseObjectName - If a valid object name is specified, return it. If no
/// name is specified, return the unset initializer. Return nullptr on parse
/// error.
/// ObjectName ::= Value [ '#' Value ]*
/// ObjectName ::= /*empty*/
///
Init *TGParser::ParseObjectName(MultiClass *CurMultiClass) {
switch (Lex.getCode()) {
case tgtok::colon:
case tgtok::semi:
case tgtok::l_brace:
// These are all of the tokens that can begin an object body.
// Some of these can also begin values but we disallow those cases
// because they are unlikely to be useful.
return UnsetInit::get();
default:
break;
}
Record *CurRec = nullptr;
if (CurMultiClass)
CurRec = &CurMultiClass->Rec;
Init *Name = ParseValue(CurRec, StringRecTy::get(), ParseNameMode);
if (!Name)
return nullptr;
if (CurMultiClass) {
Init *NameStr = QualifiedNameOfImplicitName(CurMultiClass);
HasReferenceResolver R(NameStr);
Name->resolveReferences(R);
if (!R.found())
Name = BinOpInit::getStrConcat(VarInit::get(NameStr, StringRecTy::get()),
Name);
}
return Name;
}
/// ParseClassID - Parse and resolve a reference to a class name. This returns
/// null on error.
///
/// ClassID ::= ID
///
Record *TGParser::ParseClassID() {
if (Lex.getCode() != tgtok::Id) {
TokError("expected name for ClassID");
return nullptr;
}
Record *Result = Records.getClass(Lex.getCurStrVal());
if (!Result) {
std::string Msg("Couldn't find class '" + Lex.getCurStrVal() + "'");
if (MultiClasses[Lex.getCurStrVal()].get())
TokError(Msg + ". Use 'defm' if you meant to use multiclass '" +
Lex.getCurStrVal() + "'");
else
TokError(Msg);
}
Lex.Lex();
return Result;
}
/// ParseMultiClassID - Parse and resolve a reference to a multiclass name.
/// This returns null on error.
///
/// MultiClassID ::= ID
///
MultiClass *TGParser::ParseMultiClassID() {
if (Lex.getCode() != tgtok::Id) {
TokError("expected name for MultiClassID");
return nullptr;
}
MultiClass *Result = MultiClasses[Lex.getCurStrVal()].get();
if (!Result)
TokError("Couldn't find multiclass '" + Lex.getCurStrVal() + "'");
Lex.Lex();
return Result;
}
/// ParseSubClassReference - Parse a reference to a subclass or to a templated
/// subclass. This returns a SubClassRefTy with a null Record* on error.
///
/// SubClassRef ::= ClassID
/// SubClassRef ::= ClassID '<' ValueList '>'
///
SubClassReference TGParser::
ParseSubClassReference(Record *CurRec, bool isDefm) {
SubClassReference Result;
Result.RefRange.Start = Lex.getLoc();
if (isDefm) {
if (MultiClass *MC = ParseMultiClassID())
Result.Rec = &MC->Rec;
} else {
Result.Rec = ParseClassID();
}
if (!Result.Rec) return Result;
// If there is no template arg list, we're done.
if (!consume(tgtok::less)) {
Result.RefRange.End = Lex.getLoc();
return Result;
}
if (Lex.getCode() == tgtok::greater) {
TokError("subclass reference requires a non-empty list of template values");
Result.Rec = nullptr;
return Result;
}
ParseValueList(Result.TemplateArgs, CurRec, Result.Rec);
if (Result.TemplateArgs.empty()) {
Result.Rec = nullptr; // Error parsing value list.
return Result;
}
if (!consume(tgtok::greater)) {
TokError("expected '>' in template value list");
Result.Rec = nullptr;
return Result;
}
Result.RefRange.End = Lex.getLoc();
return Result;
}
/// ParseSubMultiClassReference - Parse a reference to a subclass or to a
/// templated submulticlass. This returns a SubMultiClassRefTy with a null
/// Record* on error.
///
/// SubMultiClassRef ::= MultiClassID
/// SubMultiClassRef ::= MultiClassID '<' ValueList '>'
///
SubMultiClassReference TGParser::
ParseSubMultiClassReference(MultiClass *CurMC) {
SubMultiClassReference Result;
Result.RefRange.Start = Lex.getLoc();
Result.MC = ParseMultiClassID();
if (!Result.MC) return Result;
// If there is no template arg list, we're done.
if (!consume(tgtok::less)) {
Result.RefRange.End = Lex.getLoc();
return Result;
}
if (Lex.getCode() == tgtok::greater) {
TokError("subclass reference requires a non-empty list of template values");
Result.MC = nullptr;
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();
return Result;
}
/// ParseRangePiece - Parse a bit/value range.
/// RangePiece ::= INTVAL
/// RangePiece ::= INTVAL '...' INTVAL
/// RangePiece ::= INTVAL '-' INTVAL
/// RangePiece ::= INTVAL INTVAL
// The last two forms are deprecated.
bool TGParser::ParseRangePiece(SmallVectorImpl<unsigned> &Ranges,
TypedInit *FirstItem) {
Init *CurVal = FirstItem;
if (!CurVal)
CurVal = ParseValue(nullptr);
IntInit *II = dyn_cast_or_null<IntInit>(CurVal);
if (!II)
return TokError("expected integer or bitrange");
int64_t Start = II->getValue();
int64_t End;
if (Start < 0)
return TokError("invalid range, cannot be negative");
switch (Lex.getCode()) {
default:
Ranges.push_back(Start);
return false;
case tgtok::dotdotdot:
case tgtok::minus: {
Lex.Lex(); // eat
Init *I_End = ParseValue(nullptr);
IntInit *II_End = dyn_cast_or_null<IntInit>(I_End);
if (!II_End) {
TokError("expected integer value as end of range");
return true;
}
End = II_End->getValue();
break;
}
case tgtok::IntVal: {
End = -Lex.getCurIntVal();
Lex.Lex();
break;
}
}
if (End < 0)
return TokError("invalid range, cannot be negative");
// Add to the range.
if (Start < End)
for (; Start <= End; ++Start)
Ranges.push_back(Start);
else
for (; Start >= End; --Start)
Ranges.push_back(Start);
return false;
}
/// ParseRangeList - Parse a list of scalars and ranges into scalar values.
///
/// RangeList ::= RangePiece (',' RangePiece)*
///
void TGParser::ParseRangeList(SmallVectorImpl<unsigned> &Result) {
// Parse the first piece.
if (ParseRangePiece(Result)) {
Result.clear();
return;
}
while (consume(tgtok::comma))
// Parse the next range piece.
if (ParseRangePiece(Result)) {
Result.clear();
return;
}
}
/// ParseOptionalRangeList - Parse either a range list in <>'s or nothing.
/// OptionalRangeList ::= '<' RangeList '>'
/// OptionalRangeList ::= /*empty*/
bool TGParser::ParseOptionalRangeList(SmallVectorImpl<unsigned> &Ranges) {
SMLoc StartLoc = Lex.getLoc();
if (!consume(tgtok::less))
return false;
// Parse the range list.
ParseRangeList(Ranges);
if (Ranges.empty()) return true;
if (!consume(tgtok::greater)) {
TokError("expected '>' at end of range list");
return Error(StartLoc, "to match this '<'");
}
return false;
}
/// ParseOptionalBitList - Parse either a bit list in {}'s or nothing.
/// OptionalBitList ::= '{' RangeList '}'
/// OptionalBitList ::= /*empty*/
bool TGParser::ParseOptionalBitList(SmallVectorImpl<unsigned> &Ranges) {
SMLoc StartLoc = Lex.getLoc();
if (!consume(tgtok::l_brace))
return false;
// Parse the range list.
ParseRangeList(Ranges);
if (Ranges.empty()) return true;
if (!consume(tgtok::r_brace)) {
TokError("expected '}' at end of bit list");
return Error(StartLoc, "to match this '{'");
}
return false;
}
/// ParseType - Parse and return a tblgen type. This returns null on error.
///
/// Type ::= STRING // string type
/// Type ::= CODE // code type
/// Type ::= BIT // bit type
/// Type ::= BITS '<' INTVAL '>' // bits<x> type
/// Type ::= INT // int type
/// Type ::= LIST '<' Type '>' // list<x> type
/// Type ::= DAG // dag type
/// Type ::= ClassID // Record Type
///
RecTy *TGParser::ParseType() {
switch (Lex.getCode()) {
default: TokError("Unknown token when expecting a type"); return nullptr;
case tgtok::String:
case tgtok::Code: Lex.Lex(); return StringRecTy::get();
case tgtok::Bit: Lex.Lex(); return BitRecTy::get();
case tgtok::Int: Lex.Lex(); return IntRecTy::get();
case tgtok::Dag: Lex.Lex(); return DagRecTy::get();
case tgtok::Id:
if (Record *R = ParseClassID()) return RecordRecTy::get(R);
TokError("unknown class name");
return nullptr;
case tgtok::Bits: {
if (Lex.Lex() != tgtok::less) { // Eat 'bits'
TokError("expected '<' after bits type");
return nullptr;
}
if (Lex.Lex() != tgtok::IntVal) { // Eat '<'
TokError("expected integer in bits<n> type");
return nullptr;
}
uint64_t Val = Lex.getCurIntVal();
if (Lex.Lex() != tgtok::greater) { // Eat count.
TokError("expected '>' at end of bits<n> type");
return nullptr;
}
Lex.Lex(); // Eat '>'
return BitsRecTy::get(Val);
}
case tgtok::List: {
if (Lex.Lex() != tgtok::less) { // Eat 'bits'
TokError("expected '<' after list type");
return nullptr;
}
Lex.Lex(); // Eat '<'
RecTy *SubType = ParseType();
if (!SubType) return nullptr;
if (!consume(tgtok::greater)) {
TokError("expected '>' at end of list<ty> type");
return nullptr;
}
return ListRecTy::get(SubType);
}
}
}
/// ParseIDValue
Init *TGParser::ParseIDValue(Record *CurRec, StringInit *Name, SMLoc NameLoc,
IDParseMode Mode) {
if (CurRec) {
if (const RecordVal *RV = CurRec->getValue(Name))
return VarInit::get(Name, RV->getType());
}
if ((CurRec && CurRec->isClass()) || CurMultiClass) {
Init *TemplateArgName;
if (CurMultiClass) {
TemplateArgName =
QualifyName(CurMultiClass->Rec, CurMultiClass, Name, "::");
} else
TemplateArgName = QualifyName(*CurRec, CurMultiClass, Name, ":");
Record *TemplateRec = CurMultiClass ? &CurMultiClass->Rec : CurRec;
if (TemplateRec->isTemplateArg(TemplateArgName)) {
const RecordVal *RV = TemplateRec->getValue(TemplateArgName);
assert(RV && "Template arg doesn't exist??");
return VarInit::get(TemplateArgName, RV->getType());
} else if (Name->getValue() == "NAME") {
return VarInit::get(TemplateArgName, StringRecTy::get());
}
}
if (CurLocalScope)
if (Init *I = CurLocalScope->getVar(Name->getValue()))
return I;
// If this is in a foreach loop, make sure it's not a loop iterator
for (const auto &L : Loops) {
if (L->IterVar) {
VarInit *IterVar = dyn_cast<VarInit>(L->IterVar);
if (IterVar && IterVar->getNameInit() == Name)
return IterVar;
}
}
if (Mode == ParseNameMode)
return Name;
if (Init *I = Records.getGlobal(Name->getValue()))
return I;
// Allow self-references of concrete defs, but delay the lookup so that we
// get the correct type.
if (CurRec && !CurRec->isClass() && !CurMultiClass &&
CurRec->getNameInit() == Name)
return UnOpInit::get(UnOpInit::CAST, Name, CurRec->getType());
Error(NameLoc, "Variable not defined: '" + Name->getValue() + "'");
return nullptr;
}
/// ParseOperation - Parse an operator. This returns null on error.
///
/// Operation ::= XOperator ['<' Type '>'] '(' Args ')'
///
Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
switch (Lex.getCode()) {
default:
TokError("unknown bang operator");
return nullptr;
case tgtok::XNOT:
case tgtok::XHead:
case tgtok::XTail:
case tgtok::XSize:
case tgtok::XEmpty:
case tgtok::XCast:
case tgtok::XGetDagOp: { // Value ::= !unop '(' Value ')'
UnOpInit::UnaryOp Code;
RecTy *Type = nullptr;
switch (Lex.getCode()) {
default: llvm_unreachable("Unhandled code!");
case tgtok::XCast:
Lex.Lex(); // eat the operation
Code = UnOpInit::CAST;
Type = ParseOperatorType();
if (!Type) {
TokError("did not get type for unary operator");
return nullptr;
}
break;
case tgtok::XNOT:
Lex.Lex(); // eat the operation
Code = UnOpInit::NOT;
Type = IntRecTy::get();
break;
case tgtok::XHead:
Lex.Lex(); // eat the operation
Code = UnOpInit::HEAD;
break;
case tgtok::XTail:
Lex.Lex(); // eat the operation
Code = UnOpInit::TAIL;
break;
case tgtok::XSize:
Lex.Lex();
Code = UnOpInit::SIZE;
Type = IntRecTy::get();
break;
case tgtok::XEmpty:
Lex.Lex(); // eat the operation
Code = UnOpInit::EMPTY;
Type = IntRecTy::get();
break;
case tgtok::XGetDagOp:
Lex.Lex(); // eat the operation
if (Lex.getCode() == tgtok::less) {
// Parse an optional type suffix, so that you can say
// !getdagop<BaseClass>(someDag) as a shorthand for
// !cast<BaseClass>(!getdagop(someDag)).
Type = ParseOperatorType();
if (!Type) {
TokError("did not get type for unary operator");
return nullptr;
}
if (!isa<RecordRecTy>(Type)) {
TokError("type for !getdagop must be a record type");
// but keep parsing, to consume the operand
}
} else {
Type = RecordRecTy::get({});
}
Code = UnOpInit::GETDAGOP;
break;
}
if (!consume(tgtok::l_paren)) {
TokError("expected '(' after unary operator");
return nullptr;
}
Init *LHS = ParseValue(CurRec);
if (!LHS) return nullptr;
if (Code == UnOpInit::EMPTY || Code == UnOpInit::SIZE) {
ListInit *LHSl = dyn_cast<ListInit>(LHS);
StringInit *LHSs = dyn_cast<StringInit>(LHS);
DagInit *LHSd = dyn_cast<DagInit>(LHS);
TypedInit *LHSt = dyn_cast<TypedInit>(LHS);
if (!LHSl && !LHSs && !LHSd && !LHSt) {
TokError("expected string, list, or dag type argument in unary operator");
return nullptr;
}
if (LHSt) {
ListRecTy *LType = dyn_cast<ListRecTy>(LHSt->getType());
StringRecTy *SType = dyn_cast<StringRecTy>(LHSt->getType());
DagRecTy *DType = dyn_cast<DagRecTy>(LHSt->getType());
if (!LType && !SType && !DType) {
TokError("expected string, list, or dag type argument in unary operator");
return nullptr;
}
}
}
if (Code == UnOpInit::HEAD || Code == UnOpInit::TAIL) {
ListInit *LHSl = dyn_cast<ListInit>(LHS);
TypedInit *LHSt = dyn_cast<TypedInit>(LHS);
if (!LHSl && !LHSt) {
TokError("expected list type argument in unary operator");
return nullptr;
}
if (LHSt) {
ListRecTy *LType = dyn_cast<ListRecTy>(LHSt->getType());
if (!LType) {
TokError("expected list type argument in unary operator");
return nullptr;
}
}
if (LHSl && LHSl->empty()) {
TokError("empty list argument in unary operator");
return nullptr;
}
if (LHSl) {
Init *Item = LHSl->getElement(0);
TypedInit *Itemt = dyn_cast<TypedInit>(Item);
if (!Itemt) {
TokError("untyped list element in unary operator");
return nullptr;
}
Type = (Code == UnOpInit::HEAD) ? Itemt->getType()
: ListRecTy::get(Itemt->getType());
} else {
assert(LHSt && "expected list type argument in unary operator");
ListRecTy *LType = dyn_cast<ListRecTy>(LHSt->getType());
Type = (Code == UnOpInit::HEAD) ? LType->getElementType() : LType;
}
}
if (!consume(tgtok::r_paren)) {
TokError("expected ')' in unary operator");
return nullptr;
}
return (UnOpInit::get(Code, LHS, Type))->Fold(CurRec);
}
case tgtok::XIsA: {
// Value ::= !isa '<' Type '>' '(' Value ')'
Lex.Lex(); // eat the operation
RecTy *Type = ParseOperatorType();
if (!Type)
return nullptr;
if (!consume(tgtok::l_paren)) {
TokError("expected '(' after type of !isa");
return nullptr;
}
Init *LHS = ParseValue(CurRec);
if (!LHS)
return nullptr;
if (!consume(tgtok::r_paren)) {
TokError("expected ')' in !isa");
return nullptr;
}
return (IsAOpInit::get(Type, LHS))->Fold();
}
case tgtok::XConcat:
case tgtok::XADD:
case tgtok::XSUB:
case tgtok::XMUL:
case tgtok::XAND:
case tgtok::XOR:
case tgtok::XXOR:
case tgtok::XSRA:
case tgtok::XSRL:
case tgtok::XSHL:
case tgtok::XEq:
case tgtok::XNe:
case tgtok::XLe:
case tgtok::XLt:
case tgtok::XGe:
case tgtok::XGt:
case tgtok::XListConcat:
case tgtok::XListSplat:
case tgtok::XStrConcat:
case tgtok::XInterleave:
case tgtok::XSetDagOp: { // Value ::= !binop '(' Value ',' Value ')'
tgtok::TokKind OpTok = Lex.getCode();
SMLoc OpLoc = Lex.getLoc();
Lex.Lex(); // eat the operation
BinOpInit::BinaryOp Code;
switch (OpTok) {
default: llvm_unreachable("Unhandled code!");
case tgtok::XConcat: Code = BinOpInit::CONCAT; break;
case tgtok::XADD: Code = BinOpInit::ADD; break;
case tgtok::XSUB: Code = BinOpInit::SUB; break;
case tgtok::XMUL: Code = BinOpInit::MUL; break;
case tgtok::XAND: Code = BinOpInit::AND; break;
case tgtok::XOR: Code = BinOpInit::OR; break;
case tgtok::XXOR: Code = BinOpInit::XOR; break;
case tgtok::XSRA: Code = BinOpInit::SRA; break;
case tgtok::XSRL: Code = BinOpInit::SRL; break;
case tgtok::XSHL: Code = BinOpInit::SHL; break;
case tgtok::XEq: Code = BinOpInit::EQ; break;
case tgtok::XNe: Code = BinOpInit::NE; break;
case tgtok::XLe: Code = BinOpInit::LE; break;
case tgtok::XLt: Code = BinOpInit::LT; break;
case tgtok::XGe: Code = BinOpInit::GE; break;
case tgtok::XGt: Code = BinOpInit::GT; break;
case tgtok::XListConcat: Code = BinOpInit::LISTCONCAT; break;
case tgtok::XListSplat: Code = BinOpInit::LISTSPLAT; break;
case tgtok::XStrConcat: Code = BinOpInit::STRCONCAT; break;
case tgtok::XInterleave: Code = BinOpInit::INTERLEAVE; break;
case tgtok::XSetDagOp: Code = BinOpInit::SETDAGOP; break;
}
RecTy *Type = nullptr;
RecTy *ArgType = nullptr;
switch (OpTok) {
default:
llvm_unreachable("Unhandled code!");
case tgtok::XConcat:
case tgtok::XSetDagOp:
Type = DagRecTy::get();
ArgType = DagRecTy::get();
break;
case tgtok::XAND:
case tgtok::XOR:
case tgtok::XXOR:
case tgtok::XSRA:
case tgtok::XSRL:
case tgtok::XSHL:
case tgtok::XADD:
case tgtok::XSUB:
case tgtok::XMUL:
Type = IntRecTy::get();
ArgType = IntRecTy::get();
break;
case tgtok::XEq:
case tgtok::XNe:
case tgtok::XLe:
case tgtok::XLt:
case tgtok::XGe:
case tgtok::XGt:
Type = BitRecTy::get();
// ArgType for the comparison operators is not yet known.
break;
case tgtok::XListConcat:
// We don't know the list type until we parse the first argument
ArgType = ItemType;
break;
case tgtok::XListSplat:
// Can't do any typechecking until we parse the first argument.
break;
case tgtok::XStrConcat:
Type = StringRecTy::get();
ArgType = StringRecTy::get();
break;
case tgtok::XInterleave:
Type = StringRecTy::get();
// The first argument type is not yet known.
}
if (Type && ItemType && !Type->typeIsConvertibleTo(ItemType)) {
Error(OpLoc, Twine("expected value of type '") +
ItemType->getAsString() + "', got '" +
Type->getAsString() + "'");
return nullptr;
}
if (!consume(tgtok::l_paren)) {
TokError("expected '(' after binary operator");
return nullptr;
}
SmallVector<Init*, 2> InitList;
// Note that this loop consumes an arbitrary number of arguments.
// The actual count is checked later.
for (;;) {
SMLoc InitLoc = Lex.getLoc();
InitList.push_back(ParseValue(CurRec, ArgType));
if (!InitList.back()) return nullptr;
TypedInit *InitListBack = dyn_cast<TypedInit>(InitList.back());
if (!InitListBack) {
Error(OpLoc, Twine("expected value to be a typed value, got '" +
InitList.back()->getAsString() + "'"));
return nullptr;
}
RecTy *ListType = InitListBack->getType();
if (!ArgType) {
// Argument type must be determined from the argument itself.
ArgType = ListType;
switch (Code) {
case BinOpInit::LISTCONCAT:
if (!isa<ListRecTy>(ArgType)) {
Error(InitLoc, Twine("expected a list, got value of type '") +
ArgType->getAsString() + "'");
return nullptr;
}
break;
case BinOpInit::LISTSPLAT:
if (ItemType && InitList.size() == 1) {
if (!isa<ListRecTy>(ItemType)) {
Error(OpLoc,
Twine("expected output type to be a list, got type '") +
ItemType->getAsString() + "'");
return nullptr;
}
if (!ArgType->getListTy()->typeIsConvertibleTo(ItemType)) {
Error(OpLoc, Twine("expected first arg type to be '") +
ArgType->getAsString() +
"', got value of type '" +
cast<ListRecTy>(ItemType)
->getElementType()
->getAsString() +
"'");
return nullptr;
}
}
if (InitList.size() == 2 && !isa<IntRecTy>(ArgType)) {
Error(InitLoc, Twine("expected second parameter to be an int, got "
"value of type '") +
ArgType->getAsString() + "'");
return nullptr;
}
ArgType = nullptr; // Broken invariant: types not identical.
break;
case BinOpInit::EQ:
case BinOpInit::NE:
if (!ArgType->typeIsConvertibleTo(IntRecTy::get()) &&
!ArgType->typeIsConvertibleTo(StringRecTy::get()) &&
!ArgType->typeIsConvertibleTo(RecordRecTy::get({}))) {
Error(InitLoc, Twine("expected bit, bits, int, string, or record; "
"got value of type '") + ArgType->getAsString() +
"'");
return nullptr;
}
break;
case BinOpInit::LE:
case BinOpInit::LT:
case BinOpInit::GE:
case BinOpInit::GT:
if (!ArgType->typeIsConvertibleTo(IntRecTy::get()) &&
!ArgType->typeIsConvertibleTo(StringRecTy::get())) {
Error(InitLoc, Twine("expected bit, bits, int, or string; "
"got value of type '") + ArgType->getAsString() +
"'");
return nullptr;
}
break;
case BinOpInit::INTERLEAVE:
switch (InitList.size()) {
case 1: // First argument must be a list of strings or integers.
if (ArgType != StringRecTy::get()->getListTy() &&
!ArgType->typeIsConvertibleTo(IntRecTy::get()->getListTy())) {
Error(InitLoc, Twine("expected list of string, int, bits, or bit; "
"got value of type '") +
ArgType->getAsString() + "'");
return nullptr;
}
break;
case 2: // Second argument must be a string.
if (!isa<StringRecTy>(ArgType)) {
Error(InitLoc, Twine("expected second argument to be a string, "
"got value of type '") +
ArgType->getAsString() + "'");
return nullptr;
}
break;
default: ;
}
ArgType = nullptr; // Broken invariant: types not identical.
break;
default: llvm_unreachable("other ops have fixed argument types");
}
} else {
// Desired argument type is a known and in ArgType.
RecTy *Resolved = resolveTypes(ArgType, ListType);
if (!Resolved) {
Error(InitLoc, Twine("expected value of type '") +
ArgType->getAsString() + "', got '" +
ListType->getAsString() + "'");
return nullptr;
}
if (Code != BinOpInit::ADD && Code != BinOpInit::SUB &&
Code != BinOpInit::AND && Code != BinOpInit::OR &&
Code != BinOpInit::XOR && Code != BinOpInit::SRA &&
Code != BinOpInit::SRL && Code != BinOpInit::SHL &&
Code != BinOpInit::MUL)
ArgType = Resolved;
}
// Deal with BinOps whose arguments have different types, by
// rewriting ArgType in between them.
switch (Code) {
case BinOpInit::SETDAGOP:
// After parsing the first dag argument, switch to expecting
// a record, with no restriction on its superclasses.
ArgType = RecordRecTy::get({});
break;
default:
break;
}
if (!consume(tgtok::comma))
break;
}
if (!consume(tgtok::r_paren)) {
TokError("expected ')' in operator");
return nullptr;
}
// listconcat returns a list with type of the argument.
if (Code == BinOpInit::LISTCONCAT)
Type = ArgType;
// listsplat returns a list of type of the *first* argument.
if (Code == BinOpInit::LISTSPLAT)
Type = cast<TypedInit>(InitList.front())->getType()->getListTy();
// We allow multiple operands to associative operators like !strconcat as
// shorthand for nesting them.
if (Code == BinOpInit::STRCONCAT || Code == BinOpInit::LISTCONCAT ||
Code == BinOpInit::CONCAT || Code == BinOpInit::ADD ||
Code == BinOpInit::AND || Code == BinOpInit::OR ||
Code == BinOpInit::XOR || Code == BinOpInit::MUL) {
while (InitList.size() > 2) {
Init *RHS = InitList.pop_back_val();
RHS = (BinOpInit::get(Code, InitList.back(), RHS, Type))->Fold(CurRec);
InitList.back() = RHS;
}
}
if (InitList.size() == 2)
return (BinOpInit::get(Code, InitList[0], InitList[1], Type))
->Fold(CurRec);
Error(OpLoc, "expected two operands to operator");
return nullptr;
}
case tgtok::XForEach:
case tgtok::XFilter: {
return ParseOperationForEachFilter(CurRec, ItemType);
}
case tgtok::XDag:
case tgtok::XIf:
case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
TernOpInit::TernaryOp Code;
RecTy *Type = nullptr;
tgtok::TokKind LexCode = Lex.getCode();
Lex.Lex(); // eat the operation
switch (LexCode) {
default: llvm_unreachable("Unhandled code!");
case tgtok::XDag:
Code = TernOpInit::DAG;
Type = DagRecTy::get();
ItemType = nullptr;
break;
case tgtok::XIf:
Code = TernOpInit::IF;
break;
case tgtok::XSubst:
Code = TernOpInit::SUBST;
break;
}
if (!consume(tgtok::l_paren)) {
TokError("expected '(' after ternary operator");
return nullptr;
}
Init *LHS = ParseValue(CurRec);
if (!LHS) return nullptr;
if (!consume(tgtok::comma)) {
TokError("expected ',' in ternary operator");
return nullptr;
}
SMLoc MHSLoc = Lex.getLoc();
Init *MHS = ParseValue(CurRec, ItemType);
if (!MHS)
return nullptr;
if (!consume(tgtok::comma)) {
TokError("expected ',' in ternary operator");
return nullptr;
}
SMLoc RHSLoc = Lex.getLoc();
Init *RHS = ParseValue(CurRec, ItemType);
if (!RHS)
return nullptr;
if (!consume(tgtok::r_paren)) {
TokError("expected ')' in binary operator");
return nullptr;
}
switch (LexCode) {
default: llvm_unreachable("Unhandled code!");
case tgtok::XDag: {
TypedInit *MHSt = dyn_cast<TypedInit>(MHS);
if (!MHSt && !isa<UnsetInit>(MHS)) {
Error(MHSLoc, "could not determine type of the child list in !dag");
return nullptr;
}
if (MHSt && !isa<ListRecTy>(MHSt->getType())) {
Error(MHSLoc, Twine("expected list of children, got type '") +
MHSt->getType()->getAsString() + "'");
return nullptr;
}
TypedInit *RHSt = dyn_cast<TypedInit>(RHS);
if (!RHSt && !isa<UnsetInit>(RHS)) {
Error(RHSLoc, "could not determine type of the name list in !dag");
return nullptr;
}
if (RHSt && StringRecTy::get()->getListTy() != RHSt->getType()) {
Error(RHSLoc, Twine("expected list<string>, got type '") +
RHSt->getType()->getAsString() + "'");
return nullptr;
}
if (!MHSt && !RHSt) {
Error(MHSLoc,
"cannot have both unset children and unset names in !dag");
return nullptr;
}
break;
}
case tgtok::XIf: {
RecTy *MHSTy = nullptr;
RecTy *RHSTy = nullptr;
if (TypedInit *MHSt = dyn_cast<TypedInit>(MHS))
MHSTy = MHSt->getType();
if (BitsInit *MHSbits = dyn_cast<BitsInit>(MHS))
MHSTy = BitsRecTy::get(MHSbits->getNumBits());
if (isa<BitInit>(MHS))
MHSTy = BitRecTy::get();
if (TypedInit *RHSt = dyn_cast<TypedInit>(RHS))
RHSTy = RHSt->getType();
if (BitsInit *RHSbits = dyn_cast<BitsInit>(RHS))
RHSTy = BitsRecTy::get(RHSbits->getNumBits());
if (isa<BitInit>(RHS))
RHSTy = BitRecTy::get();
// For UnsetInit, it's typed from the other hand.
if (isa<UnsetInit>(MHS))
MHSTy = RHSTy;
if (isa<UnsetInit>(RHS))
RHSTy = MHSTy;
if (!MHSTy || !RHSTy) {
TokError("could not get type for !if");
return nullptr;
}
Type = resolveTypes(MHSTy, RHSTy);
if (!Type) {
TokError(Twine("inconsistent types '") + MHSTy->getAsString() +
"' and '" + RHSTy->getAsString() + "' for !if");
return nullptr;
}
break;
}
case tgtok::XSubst: {
TypedInit *RHSt = dyn_cast<TypedInit>(RHS);
if (!RHSt) {
TokError("could not get type for !subst");
return nullptr;
}
Type = RHSt->getType();
break;
}
}
return (TernOpInit::get(Code, LHS, MHS, RHS, Type))->Fold(CurRec);
}
case tgtok::XSubstr:
return ParseOperationSubstr(CurRec, ItemType);
case tgtok::XCond:
return ParseOperationCond(CurRec, ItemType);
case tgtok::XFoldl: {
// Value ::= !foldl '(' Value ',' Value ',' Id ',' Id ',' Expr ')'
Lex.Lex(); // eat the operation
if (!consume(tgtok::l_paren)) {
TokError("expected '(' after !foldl");
return nullptr;
}
Init *StartUntyped = ParseValue(CurRec);
if (!StartUntyped)
return nullptr;
TypedInit *Start = dyn_cast<TypedInit>(StartUntyped);
if (!Start) {
TokError(Twine("could not get type of !foldl start: '") +
StartUntyped->getAsString() + "'");
return nullptr;
}
if (!consume(tgtok::comma)) {
TokError("expected ',' in !foldl");
return nullptr;
}
Init *ListUntyped = ParseValue(CurRec);
if (!ListUntyped)
return nullptr;
TypedInit *List = dyn_cast<TypedInit>(ListUntyped);
if (!List) {
TokError(Twine("could not get type of !foldl list: '") +
ListUntyped->getAsString() + "'");
return nullptr;
}
ListRecTy *ListType = dyn_cast<ListRecTy>(List->getType());
if (!ListType) {
TokError(Twine("!foldl list must be a list, but is of type '") +
List->getType()->getAsString());
return nullptr;
}
if (Lex.getCode() != tgtok::comma) {
TokError("expected ',' in !foldl");
return nullptr;
}
if (Lex.Lex() != tgtok::Id) { // eat the ','
TokError("third argument of !foldl must be an identifier");
return nullptr;
}
Init *A = StringInit::get(Lex.getCurStrVal());
if (CurRec && CurRec->getValue(A)) {
TokError((Twine("left !foldl variable '") + A->getAsString() +
"' already defined")
.str());
return nullptr;
}
if (Lex.Lex() != tgtok::comma) { // eat the id
TokError("expected ',' in !foldl");
return nullptr;
}
if (Lex.Lex() != tgtok::Id) { // eat the ','
TokError("fourth argument of !foldl must be an identifier");
return nullptr;
}
Init *B = StringInit::get(Lex.getCurStrVal());
if (CurRec && CurRec->getValue(B)) {
TokError((Twine("right !foldl variable '") + B->getAsString() +
"' already defined")
.str());
return nullptr;
}
if (Lex.Lex() != tgtok::comma) { // eat the id
TokError("expected ',' in !foldl");
return nullptr;
}
Lex.Lex(); // eat the ','
// We need to create a temporary record to provide a scope for the
// two variables.
std::unique_ptr<Record> ParseRecTmp;
Record *ParseRec = CurRec;
if (!ParseRec) {
ParseRecTmp = std::make_unique<Record>(".parse", ArrayRef<SMLoc>{}, Records);
ParseRec = ParseRecTmp.get();
}
ParseRec->addValue(RecordVal(A, Start->getType(), RecordVal::FK_Normal));
ParseRec->addValue(RecordVal(B, ListType->getElementType(),
RecordVal::FK_Normal));
Init *ExprUntyped = ParseValue(ParseRec);
ParseRec->removeValue(A);
ParseRec->removeValue(B);
if (!ExprUntyped)
return nullptr;
TypedInit *Expr = dyn_cast<TypedInit>(ExprUntyped);
if (!Expr) {
TokError("could not get type of !foldl expression");
return nullptr;
}
if (Expr->getType() != Start->getType()) {
TokError(Twine("!foldl expression must be of same type as start (") +
Start->getType()->getAsString() + "), but is of type " +
Expr->getType()->getAsString());
return nullptr;
}
if (!consume(tgtok::r_paren)) {
TokError("expected ')' in fold operator");
return nullptr;
}
return FoldOpInit::get(Start, List, A, B, Expr, Start->getType())
->Fold(CurRec);
}
}
}
/// ParseOperatorType - Parse a type for an operator. This returns
/// null on error.
///
/// OperatorType ::= '<' Type '>'
///
RecTy *TGParser::ParseOperatorType() {
RecTy *Type = nullptr;
if (!consume(tgtok::less)) {
TokError("expected type name for operator");
return nullptr;
}
if (Lex.getCode() == tgtok::Code)
TokError("the 'code' type is not allowed in bang operators; use 'string'");
Type = ParseType();
if (!Type) {
TokError("expected type name for operator");
return nullptr;
}
if (!consume(tgtok::greater)) {
TokError("expected type name for operator");
return nullptr;
}
return Type;
}
/// Parse the !substr operation. Return null on error.
///
/// Substr ::= !substr(string, start-int [, length-int]) => string
Init *TGParser::ParseOperationSubstr(Record *CurRec, RecTy *ItemType) {
TernOpInit::TernaryOp Code = TernOpInit::SUBSTR;
RecTy *Type = StringRecTy::get();
Lex.Lex(); // eat the operation
if (!consume(tgtok::l_paren)) {
TokError("expected '(' after !substr operator");
return nullptr;
}
Init *LHS = ParseValue(CurRec);
if (!LHS)
return nullptr;
if (!consume(tgtok::comma)) {
TokError("expected ',' in !substr operator");
return nullptr;
}
SMLoc MHSLoc = Lex.getLoc();
Init *MHS = ParseValue(CurRec);
if (!MHS)
return nullptr;
SMLoc RHSLoc = Lex.getLoc();
Init *RHS;
if (consume(tgtok::comma)) {
RHSLoc = Lex.getLoc();
RHS = ParseValue(CurRec);
if (!RHS)
return nullptr;
} else {
RHS = IntInit::get(std::numeric_limits<int64_t>::max());
}
if (!consume(tgtok::r_paren)) {
TokError("expected ')' in !substr operator");
return nullptr;
}
if (ItemType && !Type->typeIsConvertibleTo(ItemType)) {
Error(RHSLoc, Twine("expected value of type '") +
ItemType->getAsString() + "', got '" +
Type->getAsString() + "'");
}
TypedInit *LHSt = dyn_cast<TypedInit>(LHS);
if (!LHSt && !isa<UnsetInit>(LHS)) {
TokError("could not determine type of the string in !substr");
return nullptr;
}
if (LHSt && !isa<StringRecTy>(LHSt->getType())) {
TokError(Twine("expected string, got type '") +
LHSt->getType()->getAsString() + "'");
return nullptr;
}
TypedInit *MHSt = dyn_cast<TypedInit>(MHS);
if (!MHSt && !isa<UnsetInit>(MHS)) {
TokError("could not determine type of the start position in !substr");
return nullptr;
}
if (MHSt && !isa<IntRecTy>(MHSt->getType())) {
Error(MHSLoc, Twine("expected int, got type '") +
MHSt->getType()->getAsString() + "'");
return nullptr;
}
if (RHS) {
TypedInit *RHSt = dyn_cast<TypedInit>(RHS);
if (!RHSt && !isa<UnsetInit>(RHS)) {
TokError("could not determine type of the length in !substr");
return nullptr;
}
if (RHSt && !isa<IntRecTy>(RHSt->getType())) {
TokError(Twine("expected int, got type '") +
RHSt->getType()->getAsString() + "'");
return nullptr;
}
}
return (TernOpInit::get(Code, LHS, MHS, RHS, Type))->Fold(CurRec);
}
/// Parse the !foreach and !filter operations. Return null on error.
///
/// ForEach ::= !foreach(ID, list-or-dag, expr) => list<expr type>
/// Filter ::= !foreach(ID, list, predicate) ==> list<list type>
Init *TGParser::ParseOperationForEachFilter(Record *CurRec, RecTy *ItemType) {
SMLoc OpLoc = Lex.getLoc();
tgtok::TokKind Operation = Lex.getCode();
Lex.Lex(); // eat the operation
if (Lex.getCode() != tgtok::l_paren) {
TokError("expected '(' after !foreach/!filter");
return nullptr;
}
if (Lex.Lex() != tgtok::Id) { // eat the '('
TokError("first argument of !foreach/!filter must be an identifier");
return nullptr;
}
Init *LHS = StringInit::get(Lex.getCurStrVal());
Lex.Lex(); // eat the ID.
if (CurRec && CurRec->getValue(LHS)) {
TokError((Twine("iteration variable '") + LHS->getAsString() +
"' is already defined")
.str());
return nullptr;
}
if (!consume(tgtok::comma)) {
TokError("expected ',' in !foreach/!filter");
return nullptr;
}
Init *MHS = ParseValue(CurRec);
if (!MHS)
return nullptr;
if (!consume(tgtok::comma)) {
TokError("expected ',' in !foreach/!filter");
return nullptr;
}
TypedInit *MHSt = dyn_cast<TypedInit>(MHS);
if (!MHSt) {
TokError("could not get type of !foreach/!filter list or dag");
return nullptr;
}
RecTy *InEltType = nullptr;
RecTy *ExprEltType = nullptr;
bool IsDAG = false;
if (ListRecTy *InListTy = dyn_cast<ListRecTy>(MHSt->getType())) {
InEltType = InListTy->getElementType();
if (ItemType) {
if (ListRecTy *OutListTy = dyn_cast<ListRecTy>(ItemType)) {
ExprEltType = (Operation == tgtok::XForEach)
? OutListTy->getElementType()
: IntRecTy::get();
} else {
Error(OpLoc,
"expected value of type '" +
Twine(ItemType->getAsString()) +
"', but got list type");
return nullptr;
}
}
} else if (DagRecTy *InDagTy = dyn_cast<DagRecTy>(MHSt->getType())) {
if (Operation == tgtok::XFilter) {
TokError("!filter must have a list argument");
return nullptr;
}
InEltType = InDagTy;
if (ItemType && !isa<DagRecTy>(ItemType)) {
Error(OpLoc,
"expected value of type '" + Twine(ItemType->getAsString()) +
"', but got dag type");
return nullptr;
}
IsDAG = true;
} else {
if (Operation == tgtok::XForEach)
TokError("!foreach must have a list or dag argument");
else
TokError("!filter must have a list argument");
return nullptr;
}
// We need to create a temporary record to provide a scope for the
// iteration variable.
std::unique_ptr<Record> ParseRecTmp;
Record *ParseRec = CurRec;
if (!ParseRec) {
ParseRecTmp =
std::make_unique<Record>(".parse", ArrayRef<SMLoc>{}, Records);
ParseRec = ParseRecTmp.get();
}
ParseRec->addValue(RecordVal(LHS, InEltType, RecordVal::FK_Normal));
Init *RHS = ParseValue(ParseRec, ExprEltType);
ParseRec->removeValue(LHS);
if (!RHS)
return nullptr;
if (!consume(tgtok::r_paren)) {
TokError("expected ')' in !foreach/!filter");
return nullptr;
}
RecTy *OutType = InEltType;
if (Operation == tgtok::XForEach && !IsDAG) {
TypedInit *RHSt = dyn_cast<TypedInit>(RHS);
if (!RHSt) {
TokError("could not get type of !foreach result expression");
return nullptr;
}
OutType = RHSt->getType()->getListTy();
} else if (Operation == tgtok::XFilter) {
OutType = InEltType->getListTy();
}
return (TernOpInit::get((Operation == tgtok::XForEach) ? TernOpInit::FOREACH
: TernOpInit::FILTER,
LHS, MHS, RHS, OutType))
->Fold(CurRec);
}
Init *TGParser::ParseOperationCond(Record *CurRec, RecTy *ItemType) {
Lex.Lex(); // eat the operation 'cond'
if (!consume(tgtok::l_paren)) {
TokError("expected '(' after !cond operator");
return nullptr;
}
// Parse through '[Case: Val,]+'
SmallVector<Init *, 4> Case;
SmallVector<Init *, 4> Val;
while (true) {
if (consume(tgtok::r_paren))
break;
Init *V = ParseValue(CurRec);
if (!V)
return nullptr;
Case.push_back(V);
if (!consume(tgtok::colon)) {
TokError("expected ':' following a condition in !cond operator");
return nullptr;
}
V = ParseValue(CurRec, ItemType);
if (!V)
return nullptr;
Val.push_back(V);
if (consume(tgtok::r_paren))
break;
if (!consume(tgtok::comma)) {
TokError("expected ',' or ')' following a value in !cond operator");
return nullptr;
}
}
if (Case.size() < 1) {
TokError("there should be at least 1 'condition : value' in the !cond operator");
return nullptr;
}
// resolve type
RecTy *Type = nullptr;
for (Init *V : Val) {
RecTy *VTy = nullptr;
if (TypedInit *Vt = dyn_cast<TypedInit>(V))
VTy = Vt->getType();
if (BitsInit *Vbits = dyn_cast<BitsInit>(V))
VTy = BitsRecTy::get(Vbits->getNumBits());
if (isa<BitInit>(V))
VTy = BitRecTy::get();
if (Type == nullptr) {
if (!isa<UnsetInit>(V))
Type = VTy;
} else {
if (!isa<UnsetInit>(V)) {
RecTy *RType = resolveTypes(Type, VTy);
if (!RType) {
TokError(Twine("inconsistent types '") + Type->getAsString() +
"' and '" + VTy->getAsString() + "' for !cond");
return nullptr;
}
Type = RType;
}
}
}
if (!Type) {
TokError("could not determine type for !cond from its arguments");
return nullptr;
}
return CondOpInit::get(Case, Val, Type)->Fold(CurRec);
}
/// ParseSimpleValue - Parse a tblgen value. This returns null on error.
///
/// SimpleValue ::= IDValue
/// SimpleValue ::= INTVAL
/// SimpleValue ::= STRVAL+
/// SimpleValue ::= CODEFRAGMENT
/// SimpleValue ::= '?'
/// SimpleValue ::= '{' ValueList '}'
/// SimpleValue ::= ID '<' ValueListNE '>'
/// SimpleValue ::= '[' ValueList ']'
/// SimpleValue ::= '(' IDValue DagArgList ')'
/// SimpleValue ::= CONCATTOK '(' Value ',' Value ')'
/// SimpleValue ::= ADDTOK '(' Value ',' Value ')'
/// SimpleValue ::= SUBTOK '(' Value ',' Value ')'
/// SimpleValue ::= SHLTOK '(' Value ',' Value ')'
/// SimpleValue ::= SRATOK '(' Value ',' Value ')'
/// SimpleValue ::= SRLTOK '(' Value ',' Value ')'
/// SimpleValue ::= LISTCONCATTOK '(' Value ',' Value ')'
/// SimpleValue ::= LISTSPLATTOK '(' Value ',' Value ')'
/// SimpleValue ::= STRCONCATTOK '(' Value ',' Value ')'
/// SimpleValue ::= COND '(' [Value ':' Value,]+ ')'
///
Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
IDParseMode Mode) {
Init *R = nullptr;
switch (Lex.getCode()) {
default: TokError("Unknown or reserved token when parsing a value"); break;
case tgtok::TrueVal:
R = IntInit::get(1);
Lex.Lex();
break;
case tgtok::FalseVal:
R = IntInit::get(0);
Lex.Lex();
break;
case tgtok::IntVal:
R = IntInit::get(Lex.getCurIntVal());
Lex.Lex();
break;
case tgtok::BinaryIntVal: {
auto BinaryVal = Lex.getCurBinaryIntVal();
SmallVector<Init*, 16> Bits(BinaryVal.second);
for (unsigned i = 0, e = BinaryVal.second; i != e; ++i)
Bits[i] = BitInit::get(BinaryVal.first & (1LL << i));
R = BitsInit::get(Bits);
Lex.Lex();
break;
}
case tgtok::StrVal: {
std::string Val = Lex.getCurStrVal();
Lex.Lex();
// Handle multiple consecutive concatenated strings.
while (Lex.getCode() == tgtok::StrVal) {
Val += Lex.getCurStrVal();
Lex.Lex();
}
R = StringInit::get(Val);
break;
}
case tgtok::CodeFragment:
R = StringInit::get(Lex.getCurStrVal(), StringInit::SF_Code);
Lex.Lex();
break;
case tgtok::question:
R = UnsetInit::get();
Lex.Lex();
break;
case tgtok::Id: {
SMLoc NameLoc = Lex.getLoc();
StringInit *Name = StringInit::get(Lex.getCurStrVal());
if (Lex.Lex() != tgtok::less) // consume the Id.
return ParseIDValue(CurRec, Name, NameLoc, Mode); // Value ::= IDValue
// Value ::= ID '<' ValueListNE '>'
if (Lex.Lex() == tgtok::greater) {
TokError("expected non-empty value list");
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());
if (!Class) {
Error(NameLoc, "Expected a class name, got '" + Name->getValue() + "'");
return nullptr;
}
SmallVector<Init *, 8> Args;
ParseValueList(Args, CurRec, Class);
if (Args.empty()) return nullptr;
if (!consume(tgtok::greater)) {
TokError("expected '>' at end of value list");
return nullptr;
}
// Typecheck the template arguments list
ArrayRef<Init *> ExpectedArgs = Class->getTemplateArgs();
if (ExpectedArgs.size() < Args.size()) {
Error(NameLoc,
"More template args specified than expected");
return nullptr;
}
for (unsigned i = 0, e = ExpectedArgs.size(); i != e; ++i) {
RecordVal *ExpectedArg = Class->getValue(ExpectedArgs[i]);
if (i < Args.size()) {
if (TypedInit *TI = dyn_cast<TypedInit>(Args[i])) {
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();
}
case tgtok::l_brace: { // Value ::= '{' ValueList '}'
SMLoc BraceLoc = Lex.getLoc();
Lex.Lex(); // eat the '{'
SmallVector<Init*, 16> Vals;
if (Lex.getCode() != tgtok::r_brace) {
ParseValueList(Vals, CurRec);
if (Vals.empty()) return nullptr;
}
if (!consume(tgtok::r_brace)) {
TokError("expected '}' at end of bit list value");
return nullptr;
}
SmallVector<Init *, 16> NewBits;
// As we parse { a, b, ... }, 'a' is the highest bit, but we parse it
// first. We'll first read everything in to a vector, then we can reverse
// it to get the bits in the correct order for the BitsInit value.
for (unsigned i = 0, e = Vals.size(); i != e; ++i) {
// FIXME: The following two loops would not be duplicated
// if the API was a little more orthogonal.
// bits<n> values are allowed to initialize n bits.
if (BitsInit *BI = dyn_cast<BitsInit>(Vals[i])) {
for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i)
NewBits.push_back(BI->getBit((e - i) - 1));
continue;
}
// bits<n> can also come from variable initializers.
if (VarInit *VI = dyn_cast<VarInit>(Vals[i])) {
if (BitsRecTy *BitsRec = dyn_cast<BitsRecTy>(VI->getType())) {
for (unsigned i = 0, e = BitsRec->getNumBits(); i != e; ++i)
NewBits.push_back(VI->getBit((e - i) - 1));
continue;
}
// Fallthrough to try convert this to a bit.
}
// All other values must be convertible to just a single bit.
Init *Bit = Vals[i]->getCastTo(BitRecTy::get());
if (!Bit) {
Error(BraceLoc, "Element #" + Twine(i) + " (" + Vals[i]->getAsString() +
") is not convertable to a bit");
return nullptr;
}
NewBits.push_back(Bit);
}
std::reverse(NewBits.begin(), NewBits.end());
return BitsInit::get(NewBits);
}
case tgtok::l_square: { // Value ::= '[' ValueList ']'
Lex.Lex(); // eat the '['
SmallVector<Init*, 16> Vals;
RecTy *DeducedEltTy = nullptr;
ListRecTy *GivenListTy = nullptr;
if (ItemType) {
ListRecTy *ListType = dyn_cast<ListRecTy>(ItemType);
if (!ListType) {
TokError(Twine("Encountered a list when expecting a ") +
ItemType->getAsString());
return nullptr;
}
GivenListTy = ListType;
}
if (Lex.getCode() != tgtok::r_square) {
ParseValueList(Vals, CurRec, nullptr,
GivenListTy ? GivenListTy->getElementType() : nullptr);
if (Vals.empty()) return nullptr;
}
if (!consume(tgtok::r_square)) {
TokError("expected ']' at end of list value");
return nullptr;
}
RecTy *GivenEltTy = nullptr;
if (consume(tgtok::less)) {
// Optional list element type
GivenEltTy = ParseType();
if (!GivenEltTy) {
// Couldn't parse element type
return nullptr;
}
if (!consume(tgtok::greater)) {
TokError("expected '>' at end of list element type");
return nullptr;
}
}
// Check elements
RecTy *EltTy = nullptr;
for (Init *V : Vals) {
TypedInit *TArg = dyn_cast<TypedInit>(V);
if (TArg) {
if (EltTy) {
EltTy = resolveTypes(EltTy, TArg->getType());
if (!EltTy) {
TokError("Incompatible types in list elements");
return nullptr;
}
} else {
EltTy = TArg->getType();
}
}
}
if (GivenEltTy) {
if (EltTy) {
// Verify consistency
if (!EltTy->typeIsConvertibleTo(GivenEltTy)) {
TokError("Incompatible types in list elements");
return nullptr;
}
}
EltTy = GivenEltTy;
}
if (!EltTy) {
if (!ItemType) {
TokError("No type for list");
return nullptr;
}
DeducedEltTy = GivenListTy->getElementType();
} else {
// Make sure the deduced type is compatible with the given type
if (GivenListTy) {
if (!EltTy->typeIsConvertibleTo(GivenListTy->getElementType())) {
TokError(Twine("Element type mismatch for list: element type '") +
EltTy->getAsString() + "' not convertible to '" +
GivenListTy->getElementType()->getAsString());
return nullptr;
}
}
DeducedEltTy = EltTy;
}
return ListInit::get(Vals, DeducedEltTy);
}
case tgtok::l_paren: { // Value ::= '(' IDValue DagArgList ')'
Lex.Lex(); // eat the '('
if (Lex.getCode() != tgtok::Id && Lex.getCode() != tgtok::XCast &&
Lex.getCode() != tgtok::question && Lex.getCode() != tgtok::XGetDagOp) {
TokError("expected identifier in dag init");
return nullptr;
}
Init *Operator = ParseValue(CurRec);
if (!Operator) return nullptr;
// If the operator name is present, parse it.
StringInit *OperatorName = nullptr;
if (consume(tgtok::colon)) {
if (Lex.getCode() != tgtok::VarName) { // eat the ':'
TokError("expected variable name in dag operator");
return nullptr;
}
OperatorName = StringInit::get(Lex.getCurStrVal());
Lex.Lex(); // eat the VarName.
}
SmallVector<std::pair<llvm::Init*, StringInit*>, 8> DagArgs;
if (Lex.getCode() != tgtok::r_paren) {
ParseDagArgList(DagArgs, CurRec);
if (DagArgs.empty()) return nullptr;
}
if (!consume(tgtok::r_paren)) {
TokError("expected ')' in dag init");
return nullptr;
}
return DagInit::get(Operator, OperatorName, DagArgs);
}
case tgtok::XHead:
case tgtok::XTail:
case tgtok::XSize:
case tgtok::XEmpty:
case tgtok::XCast:
case tgtok::XGetDagOp: // Value ::= !unop '(' Value ')'
case tgtok::XIsA:
case tgtok::XConcat:
case tgtok::XDag:
case tgtok::XADD:
case tgtok::XSUB:
case tgtok::XMUL:
case tgtok::XNOT:
case tgtok::XAND:
case tgtok::XOR:
case tgtok::XXOR:
case tgtok::XSRA:
case tgtok::XSRL:
case tgtok::XSHL:
case tgtok::XEq:
case tgtok::XNe:
case tgtok::XLe:
case tgtok::XLt:
case tgtok::XGe:
case tgtok::XGt:
case tgtok::XListConcat:
case tgtok::XListSplat:
case tgtok::XStrConcat:
case tgtok::XInterleave:
case tgtok::XSetDagOp: // Value ::= !binop '(' Value ',' Value ')'
case tgtok::XIf:
case tgtok::XCond:
case tgtok::XFoldl:
case tgtok::XForEach:
case tgtok::XFilter:
case tgtok::XSubst:
case tgtok::XSubstr: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
return ParseOperation(CurRec, ItemType);
}
}
return R;
}
/// ParseValue - Parse a TableGen value. This returns null on error.
///
/// Value ::= SimpleValue ValueSuffix*
/// ValueSuffix ::= '{' BitList '}'
/// ValueSuffix ::= '[' BitList ']'
/// ValueSuffix ::= '.' ID
///
Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) {
Init *Result = ParseSimpleValue(CurRec, ItemType, Mode);
if (!Result) return nullptr;
// Parse the suffixes now if present.
while (true) {
switch (Lex.getCode()) {
default: return Result;
case tgtok::l_brace: {
if (Mode == ParseNameMode)
// This is the beginning of the object body.
return Result;
SMLoc CurlyLoc = Lex.getLoc();
Lex.Lex(); // eat the '{'
SmallVector<unsigned, 16> Ranges;
ParseRangeList(Ranges);
if (Ranges.empty()) return nullptr;
// Reverse the bitlist.
std::reverse(Ranges.begin(), Ranges.end());
Result = Result->convertInitializerBitRange(Ranges);
if (!Result) {
Error(CurlyLoc, "Invalid bit range for value");
return nullptr;
}
// Eat the '}'.
if (!consume(tgtok::r_brace)) {
TokError("expected '}' at end of bit range list");
return nullptr;
}
break;
}
case tgtok::l_square: {
SMLoc SquareLoc = Lex.getLoc();
Lex.Lex(); // eat the '['
SmallVector<unsigned, 16> Ranges;
ParseRangeList(Ranges);
if (Ranges.empty()) return nullptr;
Result = Result->convertInitListSlice(Ranges);
if (!Result) {
Error(SquareLoc, "Invalid range for list slice");
return nullptr;
}
// Eat the ']'.
if (!consume(tgtok::r_square)) {
TokError("expected ']' at end of list slice");
return nullptr;
}
break;
}
case tgtok::dot: {
if (Lex.Lex() != tgtok::Id) { // eat the .
TokError("expected field identifier after '.'");
return nullptr;
}
StringInit *FieldName = StringInit::get(Lex.getCurStrVal());
if (!Result->getFieldType(FieldName)) {
TokError("Cannot access field '" + Lex.getCurStrVal() + "' of value '" +
Result->getAsString() + "'");
return nullptr;
}
Result = FieldInit::get(Result, FieldName)->Fold(CurRec);
Lex.Lex(); // eat field name
break;
}
case tgtok::paste:
SMLoc PasteLoc = Lex.getLoc();
TypedInit *LHS = dyn_cast<TypedInit>(Result);
if (!LHS) {
Error(PasteLoc, "LHS of paste is not typed!");
return nullptr;
}
// Check if it's a 'listA # listB'
if (isa<ListRecTy>(LHS->getType())) {
Lex.Lex(); // Eat the '#'.
assert(Mode == ParseValueMode && "encountered paste of lists in name");
switch (Lex.getCode()) {
case tgtok::colon:
case tgtok::semi:
case tgtok::l_brace:
Result = LHS; // trailing paste, ignore.
break;
default:
Init *RHSResult = ParseValue(CurRec, ItemType, ParseValueMode);
if (!RHSResult)
return nullptr;
Result = BinOpInit::getListConcat(LHS, RHSResult);
break;
}
break;
}
// Create a !strconcat() operation, first casting each operand to
// a string if necessary.
if (LHS->getType() != StringRecTy::get()) {
auto CastLHS = dyn_cast<TypedInit>(
UnOpInit::get(UnOpInit::CAST, LHS, StringRecTy::get())
->Fold(CurRec));
if (!CastLHS) {
Error(PasteLoc,
Twine("can't cast '") + LHS->getAsString() + "' to string");
return nullptr;
}
LHS = CastLHS;
}
TypedInit *RHS = nullptr;
Lex.Lex(); // Eat the '#'.
switch (Lex.getCode()) {
case tgtok::colon:
case tgtok::semi:
case tgtok::l_brace:
// These are all of the tokens that can begin an object body.
// Some of these can also begin values but we disallow those cases
// because they are unlikely to be useful.
// Trailing paste, concat with an empty string.
RHS = StringInit::get("");
break;
default:
Init *RHSResult = ParseValue(CurRec, nullptr, ParseNameMode);
if (!RHSResult)
return nullptr;
RHS = dyn_cast<TypedInit>(RHSResult);
if (!RHS) {
Error(PasteLoc, "RHS of paste is not typed!");
return nullptr;
}
if (RHS->getType() != StringRecTy::get()) {
auto CastRHS = dyn_cast<TypedInit>(
UnOpInit::get(UnOpInit::CAST, RHS, StringRecTy::get())
->Fold(CurRec));
if (!CastRHS) {
Error(PasteLoc,
Twine("can't cast '") + RHS->getAsString() + "' to string");
return nullptr;
}
RHS = CastRHS;
}
break;
}
Result = BinOpInit::getStrConcat(LHS, RHS);
break;
}
}
}
/// ParseDagArgList - Parse the argument list for a dag literal expression.
///
/// DagArg ::= Value (':' VARNAME)?
/// DagArg ::= VARNAME
/// DagArgList ::= DagArg
/// DagArgList ::= DagArgList ',' DagArg
void TGParser::ParseDagArgList(
SmallVectorImpl<std::pair<llvm::Init*, StringInit*>> &Result,
Record *CurRec) {
while (true) {
// DagArg ::= VARNAME
if (Lex.getCode() == tgtok::VarName) {
// A missing value is treated like '?'.
StringInit *VarName = StringInit::get(Lex.getCurStrVal());
Result.emplace_back(UnsetInit::get(), VarName);
Lex.Lex();
} else {
// DagArg ::= Value (':' VARNAME)?
Init *Val = ParseValue(CurRec);
if (!Val) {
Result.clear();
return;
}
// If the variable name is present, add it.
StringInit *VarName = nullptr;
if (Lex.getCode() == tgtok::colon) {
if (Lex.Lex() != tgtok::VarName) { // eat the ':'
TokError("expected variable name in dag literal");
Result.clear();
return;
}
VarName = StringInit::get(Lex.getCurStrVal());
Lex.Lex(); // eat the VarName.
}
Result.push_back(std::make_pair(Val, VarName));
}
if (!consume(tgtok::comma))
break;
}
}
/// ParseValueList - Parse a comma separated list of values, returning them as 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.
///
/// ValueList ::= Value (',' Value)
///
void TGParser::ParseValueList(SmallVectorImpl<Init*> &Result, Record *CurRec,
Record *ArgsRec, RecTy *EltTy) {
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));
if (!Result.back()) {
Result.clear();
return;
}
while (consume(tgtok::comma)) {
// ignore trailing comma for lists
if (Lex.getCode() == tgtok::r_square)
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));
if (!Result.back()) {
Result.clear();
return;
}
}
}
/// 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,
/// including within a def or in the template args for a def (which which case
/// 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
/// also happen within a def that is within a multiclass, which will set both
/// CurRec and CurMultiClass.
///
/// Declaration ::= FIELD? Type ID ('=' Value)?
///
Init *TGParser::ParseDeclaration(Record *CurRec,
bool ParsingTemplateArgs) {
// Read the field prefix if present.
bool HasField = consume(tgtok::Field);
RecTy *Type = ParseType();
if (!Type) return nullptr;
if (Lex.getCode() != tgtok::Id) {
TokError("Expected identifier in declaration");
return nullptr;
}
std::string Str = Lex.getCurStrVal();
if (Str == "NAME") {
TokError("'" + Str + "' is a reserved variable name");
return nullptr;
}
SMLoc IdLoc = Lex.getLoc();
Init *DeclName = StringInit::get(Str);
Lex.Lex();
if (ParsingTemplateArgs) {
if (CurRec)
DeclName = QualifyName(*CurRec, CurMultiClass, DeclName, ":");
else
assert(CurMultiClass);
if (CurMultiClass)
DeclName = QualifyName(CurMultiClass->Rec, CurMultiClass, DeclName,
"::");
}
// Add the field to the record.
if (AddValue(CurRec, IdLoc, RecordVal(DeclName, IdLoc, Type,
HasField ? RecordVal::FK_NonconcreteOK
: RecordVal::FK_Normal)))
return nullptr;
// If a value is present, parse it.
if (consume(tgtok::equal)) {
SMLoc ValLoc = Lex.getLoc();
Init *Val = ParseValue(CurRec, Type);
if (!Val ||
SetValue(CurRec, ValLoc, DeclName, None, Val))
// Return the name, even if an error is thrown. This is so that we can
// continue to make some progress, even without the value having been
// initialized.
return DeclName;
}
return DeclName;
}
/// ParseForeachDeclaration - Read a foreach declaration, returning
/// the name of the declared object or a NULL Init on error. Return
/// the name of the parsed initializer list through ForeachListName.
///
/// ForeachDeclaration ::= ID '=' '{' RangeList '}'
/// ForeachDeclaration ::= ID '=' RangePiece
/// ForeachDeclaration ::= ID '=' Value
///
VarInit *TGParser::ParseForeachDeclaration(Init *&ForeachListValue) {
if (Lex.getCode() != tgtok::Id) {
TokError("Expected identifier in foreach declaration");
return nullptr;
}
Init *DeclName = StringInit::get(Lex.getCurStrVal());
Lex.Lex();
// If a value is present, parse it.
if (!consume(tgtok::equal)) {
TokError("Expected '=' in foreach declaration");
return nullptr;
}
RecTy *IterType = nullptr;
SmallVector<unsigned, 16> Ranges;
switch (Lex.getCode()) {
case tgtok::l_brace: { // '{' RangeList '}'
Lex.Lex(); // eat the '{'
ParseRangeList(Ranges);
if (!consume(tgtok::r_brace)) {
TokError("expected '}' at end of bit range list");
return nullptr;
}
break;
}
default: {
SMLoc ValueLoc = Lex.getLoc();
Init *I = ParseValue(nullptr);
if (!I)
return nullptr;
TypedInit *TI = dyn_cast<TypedInit>(I);
if (TI && isa<ListRecTy>(TI->getType())) {
ForeachListValue = I;
IterType = cast<ListRecTy>(TI->getType())->getElementType();
break;
}
if (TI) {
if (ParseRangePiece(Ranges, TI))
return nullptr;
break;
}
std::string Type;
if (TI)
Type = (Twine("' of type '") + TI->getType()->getAsString()).str();
Error(ValueLoc, "expected a list, got '" + I->getAsString() + Type + "'");
if (CurMultiClass) {
PrintNote({}, "references to multiclass template arguments cannot be "
"resolved at this time");
}
return nullptr;
}
}
if (!Ranges.empty()) {
assert(!IterType && "Type already initialized?");
IterType = IntRecTy::get();
std::vector<Init*> Values;
for (unsigned R : Ranges)
Values.push_back(IntInit::get(R));
ForeachListValue = ListInit::get(Values, IterType);
}
if (!IterType)
return nullptr;
return VarInit::get(DeclName, IterType);
}
/// ParseTemplateArgList - Read a template argument list, which is a non-empty
/// 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,
/// these are the template args for a multiclass.
///
/// TemplateArgList ::= '<' Declaration (',' Declaration)* '>'
///
bool TGParser::ParseTemplateArgList(Record *CurRec) {
assert(Lex.getCode() == tgtok::less && "Not a template arg list!");
Lex.Lex(); // eat the '<'
Record *TheRecToAddTo = CurRec ? CurRec : &CurMultiClass->Rec;
// Read the first declaration.
Init *TemplArg = ParseDeclaration(CurRec, true/*templateargs*/);
if (!TemplArg)
return true;
TheRecToAddTo->addTemplateArg(TemplArg);
while (consume(tgtok::comma)) {
// Read the following declarations.
SMLoc Loc = Lex.getLoc();
TemplArg = ParseDeclaration(CurRec, true/*templateargs*/);
if (!TemplArg)
return true;
if (TheRecToAddTo->isTemplateArg(TemplArg))
return Error(Loc, "template argument with the same name has already been "
"defined");
TheRecToAddTo->addTemplateArg(TemplArg);
}
if (!consume(tgtok::greater))
return TokError("expected '>' at end of template argument list");
return false;
}
/// ParseBodyItem - Parse a single item within the body of a def or class.
///
/// BodyItem ::= Declaration ';'
/// BodyItem ::= LET ID OptionalBitList '=' Value ';'
/// BodyItem ::= Defvar
/// BodyItem ::= Assert
bool TGParser::ParseBodyItem(Record *CurRec) {
if (Lex.getCode() == tgtok::Assert)
return ParseAssert(nullptr, CurRec);
if (Lex.getCode() == tgtok::Defvar)
return ParseDefvar();
if (Lex.getCode() != tgtok::Let) {
if (!ParseDeclaration(CurRec, false))
return true;
if (!consume(tgtok::semi))
return TokError("expected ';' after declaration");
return false;
}
// LET ID OptionalRangeList '=' Value ';'
if (Lex.Lex() != tgtok::Id)
return TokError("expected field identifier after let");
SMLoc IdLoc = Lex.getLoc();
StringInit *FieldName = StringInit::get(Lex.getCurStrVal());
Lex.Lex(); // eat the field name.
SmallVector<unsigned, 16> BitList;
if (ParseOptionalBitList(BitList))
return true;
std::reverse(BitList.begin(), BitList.end());
if (!consume(tgtok::equal))
return TokError("expected '=' in let expression");
RecordVal *Field = CurRec->getValue(FieldName);
if (!Field)
return TokError("Value '" + FieldName->getValue() + "' unknown!");
RecTy *Type = Field->getType();
if (!BitList.empty() && isa<BitsRecTy>(Type)) {
// When assigning to a subset of a 'bits' object, expect the RHS to have
// the type of that subset instead of the type of the whole object.
Type = BitsRecTy::get(BitList.size());
}
Init *Val = ParseValue(CurRec, Type);
if (!Val) return true;
if (!consume(tgtok::semi))
return TokError("expected ';' after let expression");
return SetValue(CurRec, IdLoc, FieldName, BitList, Val);
}
/// ParseBody - Read the body of a class or def. Return true on error, false on
/// success.
///
/// Body ::= ';'
/// Body ::= '{' BodyList '}'
/// BodyList BodyItem*
///
bool TGParser::ParseBody(Record *CurRec) {
// If this is a null definition, just eat the semi and return.
if (consume(tgtok::semi))
return false;
if (!consume(tgtok::l_brace))
return TokError("Expected '{' to start body or ';' for declaration only");
// An object body introduces a new scope for local variables.
TGLocalVarScope *BodyScope = PushLocalScope();
while (Lex.getCode() != tgtok::r_brace)
if (ParseBodyItem(CurRec))
return true;
PopLocalScope(BodyScope);
// Eat the '}'.
Lex.Lex();
// If we have a semicolon, print a gentle error.
SMLoc SemiLoc = Lex.getLoc();
if (consume(tgtok::semi)) {
PrintError(SemiLoc, "A class or def body should not end with a semicolon");
PrintNote("Semicolon ignored; remove to eliminate this error");
}
return false;
}
/// Apply the current let bindings to \a CurRec.
/// \returns true on error, false otherwise.
bool TGParser::ApplyLetStack(Record *CurRec) {
for (SmallVectorImpl<LetRecord> &LetInfo : LetStack)
for (LetRecord &LR : LetInfo)
if (SetValue(CurRec, LR.Loc, LR.Name, LR.Bits, LR.Value))
return true;
return false;
}
bool TGParser::ApplyLetStack(RecordsEntry &Entry) {
if (Entry.Rec)
return ApplyLetStack(Entry.Rec.get());
for (auto &E : Entry.Loop->Entries) {
if (ApplyLetStack(E))
return true;
}
return false;
}
/// ParseObjectBody - Parse the body of a def or class. This consists of an
/// optional ClassList followed by a Body. CurRec is the current def or class
/// that is being parsed.
///
/// ObjectBody ::= BaseClassList Body
/// BaseClassList ::= /*empty*/
/// BaseClassList ::= ':' BaseClassListNE
/// BaseClassListNE ::= SubClassRef (',' SubClassRef)*
///
bool TGParser::ParseObjectBody(Record *CurRec) {
// If there is a baseclass list, read it.
if (consume(tgtok::colon)) {
// Read all of the subclasses.
SubClassReference SubClass = ParseSubClassReference(CurRec, false);
while (true) {
// Check for error.
if (!SubClass.Rec) return true;
// Add it.
if (AddSubClass(CurRec, SubClass))
return true;
if (!consume(tgtok::comma))
break;
SubClass = ParseSubClassReference(CurRec, false);
}
}
if (ApplyLetStack(CurRec))
return true;
return ParseBody(CurRec);
}
/// ParseDef - Parse and return a top level or multiclass def, return the record
/// corresponding to it. This returns null on error.
///
/// DefInst ::= DEF ObjectName ObjectBody
///
bool TGParser::ParseDef(MultiClass *CurMultiClass) {
SMLoc DefLoc = Lex.getLoc();
assert(Lex.getCode() == tgtok::Def && "Unknown tok");
Lex.Lex(); // Eat the 'def' token.
// Parse ObjectName and make a record for it.
std::unique_ptr<Record> CurRec;
Init *Name = ParseObjectName(CurMultiClass);
if (!Name)
return true;
if (isa<UnsetInit>(Name))
CurRec = std::make_unique<Record>(Records.getNewAnonymousName(), DefLoc, Records,
/*Anonymous=*/true);
else
CurRec = std::make_unique<Record>(Name, DefLoc, Records);
if (ParseObjectBody(CurRec.get()))
return true;
return addEntry(std::move(CurRec));
}
/// ParseDefset - Parse a defset statement.
///
/// Defset ::= DEFSET Type Id '=' '{' ObjectList '}'
///
bool TGParser::ParseDefset() {
assert(Lex.getCode() == tgtok::Defset);
Lex.Lex(); // Eat the 'defset' token
DefsetRecord Defset;
Defset.Loc = Lex.getLoc();
RecTy *Type = ParseType();
if (!Type)
return true;
if (!isa<ListRecTy>(Type))
return Error(Defset.Loc, "expected list type");
Defset.EltTy = cast<ListRecTy>(Type)->getElementType();
if (Lex.getCode() != tgtok::Id)
return TokError("expected identifier");
StringInit *DeclName = StringInit::get(Lex.getCurStrVal());
if (Records.getGlobal(DeclName->getValue()))
return TokError("def or global variable of this name already exists");
if (Lex.Lex() != tgtok::equal) // Eat the identifier
return TokError("expected '='");
if (Lex.Lex() != tgtok::l_brace) // Eat the '='
return TokError("expected '{'");
SMLoc BraceLoc = Lex.getLoc();
Lex.Lex(); // Eat the '{'
Defsets.push_back(&Defset);
bool Err = ParseObjectList(nullptr);
Defsets.pop_back();
if (Err)
return true;
if (!consume(tgtok::r_brace)) {
TokError("expected '}' at end of defset");
return Error(BraceLoc, "to match this '{'");
}
Records.addExtraGlobal(DeclName->getValue(),
ListInit::get(Defset.Elements, Defset.EltTy));
return false;
}
/// ParseDefvar - Parse a defvar statement.
///
/// Defvar ::= DEFVAR Id '=' Value ';'
///
bool TGParser::ParseDefvar() {
assert(Lex.getCode() == tgtok::Defvar);
Lex.Lex(); // Eat the 'defvar' token
if (Lex.getCode() != tgtok::Id)
return TokError("expected identifier");
StringInit *DeclName = StringInit::get(Lex.getCurStrVal());
if (CurLocalScope) {
if (CurLocalScope->varAlreadyDefined(DeclName->getValue()))
return TokError("local variable of this name already exists");
} else {
if (Records.getGlobal(DeclName->getValue()))
return TokError("def or global variable of this name already exists");
}
Lex.Lex();
if (!consume(tgtok::equal))
return TokError("expected '='");
Init *Value = ParseValue(nullptr);
if (!Value)
return true;
if (!consume(tgtok::semi))
return TokError("expected ';'");
if (CurLocalScope)
CurLocalScope->addVar(DeclName->getValue(), Value);
else
Records.addExtraGlobal(DeclName->getValue(), Value);
return false;
}
/// ParseForeach - Parse a for statement. Return the record corresponding
/// to it. This returns true on error.
///
/// Foreach ::= FOREACH Declaration IN '{ ObjectList '}'
/// Foreach ::= FOREACH Declaration IN Object
///
bool TGParser::ParseForeach(MultiClass *CurMultiClass) {
SMLoc Loc = Lex.getLoc();
assert(Lex.getCode() == tgtok::Foreach && "Unknown tok");
Lex.Lex(); // Eat the 'for' token.
// Make a temporary object to record items associated with the for
// loop.
Init *ListValue = nullptr;
VarInit *IterName = ParseForeachDeclaration(ListValue);
if (!IterName)
return TokError("expected declaration in for");
if (!consume(tgtok::In))
return TokError("Unknown tok");
// Create a loop object and remember it.
Loops.push_back(std::make_unique<ForeachLoop>(Loc, IterName, ListValue));
// A foreach loop introduces a new scope for local variables.
TGLocalVarScope *ForeachScope = PushLocalScope();
if (Lex.getCode() != tgtok::l_brace) {
// FOREACH Declaration IN Object
if (ParseObject(CurMultiClass))
return true;
} else {
SMLoc BraceLoc = Lex.getLoc();
// Otherwise, this is a group foreach.
Lex.Lex(); // eat the '{'.
// Parse the object list.
if (ParseObjectList(CurMultiClass))
return true;
if (!consume(tgtok::r_brace)) {
TokError("expected '}' at end of foreach command");
return Error(BraceLoc, "to match this '{'");
}
}
PopLocalScope(ForeachScope);
// Resolve the loop or store it for later resolution.
std::unique_ptr<ForeachLoop> Loop = std::move(Loops.back());
Loops.pop_back();
return addEntry(std::move(Loop));
}
/// ParseIf - Parse an if statement.
///
/// If ::= IF Value THEN IfBody
/// If ::= IF Value THEN IfBody ELSE IfBody
///
bool TGParser::ParseIf(MultiClass *CurMultiClass) {
SMLoc Loc = Lex.getLoc();
assert(Lex.getCode() == tgtok::If && "Unknown tok");
Lex.Lex(); // Eat the 'if' token.
// Make a temporary object to record items associated with the for
// loop.
Init *Condition = ParseValue(nullptr);
if (!Condition)
return true;
if (!consume(tgtok::Then))
return TokError("Unknown tok");
// We have to be able to save if statements to execute later, and they have
// to live on the same stack as foreach loops. The simplest implementation
// technique is to convert each 'then' or 'else' clause *into* a foreach
// loop, over a list of length 0 or 1 depending on the condition, and with no
// iteration variable being assigned.
ListInit *EmptyList = ListInit::get({}, BitRecTy::get());
ListInit *SingletonList = ListInit::get({BitInit::get(1)}, BitRecTy::get());
RecTy *BitListTy = ListRecTy::get(BitRecTy::get());
// The foreach containing the then-clause selects SingletonList if
// the condition is true.
Init *ThenClauseList =
TernOpInit::get(TernOpInit::IF, Condition, SingletonList, EmptyList,
BitListTy)
->Fold(nullptr);
Loops.push_back(std::make_unique<ForeachLoop>(Loc, nullptr, ThenClauseList));
if (ParseIfBody(CurMultiClass, "then"))
return true;
std::unique_ptr<ForeachLoop> Loop = std::move(Loops.back());
Loops.pop_back();
if (addEntry(std::move(Loop)))
return true;
// Now look for an optional else clause. The if-else syntax has the usual
// dangling-else ambiguity, and by greedily matching an else here if we can,
// we implement the usual resolution of pairing with the innermost unmatched
// if.
if (consume(tgtok::ElseKW)) {
// The foreach containing the else-clause uses the same pair of lists as
// above, but this time, selects SingletonList if the condition is *false*.
Init *ElseClauseList =
TernOpInit::get(TernOpInit::IF, Condition, EmptyList, SingletonList,
BitListTy)
->Fold(nullptr);
Loops.push_back(
std::make_unique<ForeachLoop>(Loc, nullptr, ElseClauseList));
if (ParseIfBody(CurMultiClass, "else"))
return true;
Loop = std::move(Loops.back());
Loops.pop_back();
if (addEntry(std::move(Loop)))
return true;
}
return false;
}
/// ParseIfBody - Parse the then-clause or else-clause of an if statement.
///
/// IfBody ::= Object
/// IfBody ::= '{' ObjectList '}'
///
bool TGParser::ParseIfBody(MultiClass *CurMultiClass, StringRef Kind) {
TGLocalVarScope *BodyScope = PushLocalScope();
if (Lex.getCode() != tgtok::l_brace) {
// A single object.
if (ParseObject(CurMultiClass))
return true;
} else {
SMLoc BraceLoc = Lex.getLoc();
// A braced block.
Lex.Lex(); // eat the '{'.
// Parse the object list.
if (ParseObjectList(CurMultiClass))
return true;
if (!consume(tgtok::r_brace)) {
TokError("expected '}' at end of '" + Kind + "' clause");
return Error(BraceLoc, "to match this '{'");
}
}
PopLocalScope(BodyScope);
return false;
}
/// ParseAssert - Parse an assert statement.
///
/// Assert ::= ASSERT condition , message ;
bool TGParser::ParseAssert(MultiClass *CurMultiClass, Record *CurRec) {
assert(Lex.getCode() == tgtok::Assert && "Unknown tok");
Lex.Lex(); // Eat the 'assert' token.
SMLoc ConditionLoc = Lex.getLoc();
Init *Condition = ParseValue(CurRec);
if (!Condition)
return true;
if (!consume(tgtok::comma)) {
TokError("expected ',' in assert statement");
return true;
}
Init *Message = ParseValue(CurRec);
if (!Message)
return true;
if (!consume(tgtok::semi))
return TokError("expected ';'");
if (CurMultiClass) {
assert(false && "assert in multiclass not yet supported");
} else if (CurRec) {
CurRec->addAssertion(ConditionLoc, Condition, Message);
} else { // at top level
CheckAssert(ConditionLoc, Condition, Message);
}
return false;
}
/// ParseClass - Parse a tblgen class definition.
///
/// ClassInst ::= CLASS ID TemplateArgList? ObjectBody
///
bool TGParser::ParseClass() {
assert(Lex.getCode() == tgtok::Class && "Unexpected token!");
Lex.Lex();
if (Lex.getCode() != tgtok::Id)
return TokError("expected class name after 'class' keyword");
Record *CurRec = Records.getClass(Lex.getCurStrVal());
if (CurRec) {
// If the body was previously defined, this is an error.
if (!CurRec->getValues().empty() ||
!CurRec->getSuperClasses().empty() ||
!CurRec->getTemplateArgs().empty())
return TokError("Class '" + CurRec->getNameInitAsString() +
"' already defined");
} else {
// If this is the first reference to this class, create and add it.
auto NewRec =
std::make_unique<Record>(Lex.getCurStrVal(), Lex.getLoc(), Records,
/*Class=*/true);
CurRec = NewRec.get();
Records.addClass(std::move(NewRec));
}
Lex.Lex(); // eat the name.
// If there are template args, parse them.
if (Lex.getCode() == tgtok::less)
if (ParseTemplateArgList(CurRec))
return true;
return ParseObjectBody(CurRec);
}
/// ParseLetList - Parse a non-empty list of assignment expressions into a list
/// of LetRecords.
///
/// LetList ::= LetItem (',' LetItem)*
/// LetItem ::= ID OptionalRangeList '=' Value
///
void TGParser::ParseLetList(SmallVectorImpl<LetRecord> &Result) {
do {
if (Lex.getCode() != tgtok::Id) {
TokError("expected identifier in let definition");
Result.clear();
return;
}
StringInit *Name = StringInit::get(Lex.getCurStrVal());
SMLoc NameLoc = Lex.getLoc();
Lex.Lex(); // Eat the identifier.
// Check for an optional RangeList.
SmallVector<unsigned, 16> Bits;
if (ParseOptionalRangeList(Bits)) {
Result.clear();
return;
}
std::reverse(Bits.begin(), Bits.end());
if (!consume(tgtok::equal)) {
TokError("expected '=' in let expression");
Result.clear();
return;
}
Init *Val = ParseValue(nullptr);
if (!Val) {
Result.clear();
return;
}
// Now that we have everything, add the record.
Result.emplace_back(Name, Bits, Val, NameLoc);
} while (consume(tgtok::comma));
}
/// ParseTopLevelLet - Parse a 'let' at top level. This can be a couple of
/// different related productions. This works inside multiclasses too.
///
/// Object ::= LET LetList IN '{' ObjectList '}'
/// Object ::= LET LetList IN Object
///
bool TGParser::ParseTopLevelLet(MultiClass *CurMultiClass) {
assert(Lex.getCode() == tgtok::Let && "Unexpected token");
Lex.Lex();
// Add this entry to the let stack.
SmallVector<LetRecord, 8> LetInfo;
ParseLetList(LetInfo);
if (LetInfo.empty()) return true;
LetStack.push_back(std::move(LetInfo));
if (!consume(tgtok::In))
return TokError("expected 'in' at end of top-level 'let'");
TGLocalVarScope *LetScope = PushLocalScope();
// If this is a scalar let, just handle it now
if (Lex.getCode() != tgtok::l_brace) {
// LET LetList IN Object
if (ParseObject(CurMultiClass))
return true;
} else { // Object ::= LETCommand '{' ObjectList '}'
SMLoc BraceLoc = Lex.getLoc();
// Otherwise, this is a group let.
Lex.Lex(); // eat the '{'.
// Parse the object list.
if (ParseObjectList(CurMultiClass))
return true;
if (!consume(tgtok::r_brace)) {
TokError("expected '}' at end of top level let command");
return Error(BraceLoc, "to match this '{'");
}
}
PopLocalScope(LetScope);
// Outside this let scope, this let block is not active.
LetStack.pop_back();
return false;
}
/// ParseMultiClass - Parse a multiclass definition.
///
/// MultiClassInst ::= MULTICLASS ID TemplateArgList?
/// ':' BaseMultiClassList '{' MultiClassObject+ '}'
/// MultiClassObject ::= DefInst
/// MultiClassObject ::= MultiClassInst
/// MultiClassObject ::= DefMInst
/// MultiClassObject ::= LETCommand '{' ObjectList '}'
/// MultiClassObject ::= LETCommand Object
///
bool TGParser::ParseMultiClass() {
assert(Lex.getCode() == tgtok::MultiClass && "Unexpected token");
Lex.Lex(); // Eat the multiclass token.
if (Lex.getCode() != tgtok::Id)
return TokError("expected identifier after multiclass for name");
std::string Name = Lex.getCurStrVal();
auto Result =
MultiClasses.insert(std::make_pair(Name,
std::make_unique<MultiClass>(Name, Lex.getLoc(),Records)));
if (!Result.second)
return TokError("multiclass '" + Name + "' already defined");
CurMultiClass = Result.first->second.get();
Lex.Lex(); // Eat the identifier.
// If there are template args, parse them.
if (Lex.getCode() == tgtok::less)
if (ParseTemplateArgList(nullptr))
return true;
bool inherits = false;
// If there are submulticlasses, parse them.
if (consume(tgtok::colon)) {
inherits = true;
// Read all of the submulticlasses.
SubMultiClassReference SubMultiClass =
ParseSubMultiClassReference(CurMultiClass);
while (true) {
// Check for error.
if (!SubMultiClass.MC) return true;
// Add it.
if (AddSubMultiClass(CurMultiClass, SubMultiClass))
return true;
if (!consume(tgtok::comma))
break;
SubMultiClass = ParseSubMultiClassReference(CurMultiClass);
}
}
if (Lex.getCode() != tgtok::l_brace) {
if (!inherits)
return TokError("expected '{' in multiclass definition");
if (!consume(tgtok::semi))
return TokError("expected ';' in multiclass definition");
} else {
if (Lex.Lex() == tgtok::r_brace) // eat the '{'.
return TokError("multiclass must contain at least one def");
// A multiclass body introduces a new scope for local variables.
TGLocalVarScope *MulticlassScope = PushLocalScope();
while (Lex.getCode() != tgtok::r_brace) {
switch (Lex.getCode()) {
default:
return TokError("expected 'assert', 'def', 'defm', 'defvar', "
"'foreach', 'if', or 'let' in multiclass body");
case tgtok::Assert:
return TokError("an assert statement in a multiclass is not yet supported");
case tgtok::Def:
case tgtok::Defm:
case tgtok::Defvar:
case tgtok::Foreach:
case tgtok::If:
case tgtok::Let:
if (ParseObject(CurMultiClass))
return true;
break;
}
}
Lex.Lex(); // eat the '}'.
// If we have a semicolon, print a gentle error.
SMLoc SemiLoc = Lex.getLoc();
if (consume(tgtok::semi)) {
PrintError(SemiLoc, "A multiclass body should not end with a semicolon");
PrintNote("Semicolon ignored; remove to eliminate this error");
}
PopLocalScope(MulticlassScope);
}
CurMultiClass = nullptr;
return false;
}
/// ParseDefm - Parse the instantiation of a multiclass.
///
/// DefMInst ::= DEFM ID ':' DefmSubClassRef ';'
///
bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
assert(Lex.getCode() == tgtok::Defm && "Unexpected token!");
Lex.Lex(); // eat the defm
Init *DefmName = ParseObjectName(CurMultiClass);
if (!DefmName)
return true;
if (isa<UnsetInit>(DefmName)) {
DefmName = Records.getNewAnonymousName();
if (CurMultiClass)
DefmName = BinOpInit::getStrConcat(
VarInit::get(QualifiedNameOfImplicitName(CurMultiClass),
StringRecTy::get()),
DefmName);
}
if (Lex.getCode() != tgtok::colon)
return TokError("expected ':' after defm identifier");
// Keep track of the new generated record definitions.
std::vector<RecordsEntry> NewEntries;
// This record also inherits from a regular class (non-multiclass)?
bool InheritFromClass = false;
// eat the colon.
Lex.Lex();
SMLoc SubClassLoc = Lex.getLoc();
SubClassReference Ref = ParseSubClassReference(nullptr, true);
while (true) {
if (!Ref.Rec) return true;
// To instantiate a multiclass, we need to first get the multiclass, then
// instantiate each def contained in the multiclass with the SubClassRef
// template parameters.
MultiClass *MC = MultiClasses[std::string(Ref.Rec->getName())].get();
assert(MC && "Didn't lookup multiclass correctly?");
ArrayRef<Init*> TemplateVals = Ref.TemplateArgs;
// Verify that the correct number of template arguments were specified.
ArrayRef<Init *> TArgs = MC->Rec.getTemplateArgs();
if (TArgs.size() < TemplateVals.size())
return Error(SubClassLoc,
"more template args specified than multiclass expects");
SubstStack Substs;
for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
if (i < TemplateVals.size()) {
Substs.emplace_back(TArgs[i], TemplateVals[i]);
} else {
Init *Default = MC->Rec.getValue(TArgs[i])->getValue();
if (!Default->isComplete()) {
return Error(SubClassLoc,
"value not specified for template argument #" +
Twine(i) + " (" + TArgs[i]->getAsUnquotedString() +
") of multiclass '" + MC->Rec.getNameInitAsString() +
"'");
}
Substs.emplace_back(TArgs[i], Default);
}
}
Substs.emplace_back(QualifiedNameOfImplicitName(MC), DefmName);
if (resolve(MC->Entries, Substs, !CurMultiClass && Loops.empty(),
&NewEntries, &SubClassLoc))
return true;
if (!consume(tgtok::comma))
break;
if (Lex.getCode() != tgtok::Id)
return TokError("expected identifier");
SubClassLoc = Lex.getLoc();
// A defm can inherit from regular classes (non-multiclass) as
// long as they come in the end of the inheritance list.
InheritFromClass = (Records.getClass(Lex.getCurStrVal()) != nullptr);
if (InheritFromClass)
break;
Ref = ParseSubClassReference(nullptr, true);
}
if (InheritFromClass) {
// Process all the classes to inherit as if they were part of a
// regular 'def' and inherit all record values.
SubClassReference SubClass = ParseSubClassReference(nullptr, false);
while (true) {
// Check for error.
if (!SubClass.Rec) return true;
// Get the expanded definition prototypes and teach them about
// the record values the current class to inherit has
for (auto &E : NewEntries) {
// Add it.
if (AddSubClass(E, SubClass))
return true;
}
if (!consume(tgtok::comma))
break;
SubClass = ParseSubClassReference(nullptr, false);
}
}
for (auto &E : NewEntries) {
if (ApplyLetStack(E))
return true;
addEntry(std::move(E));
}
if (!consume(tgtok::semi))
return TokError("expected ';' at end of defm");
return false;
}
/// ParseObject
/// Object ::= ClassInst
/// Object ::= DefInst
/// Object ::= MultiClassInst
/// Object ::= DefMInst
/// Object ::= LETCommand '{' ObjectList '}'
/// Object ::= LETCommand Object
/// Object ::= Defset
/// Object ::= Defvar
/// Object ::= Assert
bool TGParser::ParseObject(MultiClass *MC) {
switch (Lex.getCode()) {
default:
return TokError(
"Expected assert, class, def, defm, defset, foreach, if, or let");
case tgtok::Assert: return ParseAssert(MC, nullptr);
case tgtok::Def: return ParseDef(MC);
case tgtok::Defm: return ParseDefm(MC);
case tgtok::Defvar: return ParseDefvar();
case tgtok::Foreach: return ParseForeach(MC);
case tgtok::If: return ParseIf(MC);
case tgtok::Let: return ParseTopLevelLet(MC);
case tgtok::Defset:
if (MC)
return TokError("defset is not allowed inside multiclass");
return ParseDefset();
case tgtok::Class:
if (MC)
return TokError("class is not allowed inside multiclass");
if (!Loops.empty())
return TokError("class is not allowed inside foreach loop");
return ParseClass();
case tgtok::MultiClass:
if (!Loops.empty())
return TokError("multiclass is not allowed inside foreach loop");
return ParseMultiClass();
}
}
/// ParseObjectList
/// ObjectList :== Object*
bool TGParser::ParseObjectList(MultiClass *MC) {
while (isObjectStart(Lex.getCode())) {
if (ParseObject(MC))
return true;
}
return false;
}
bool TGParser::ParseFile() {
Lex.Lex(); // Prime the lexer.
if (ParseObjectList()) return true;
// If we have unread input at the end of the file, report it.
if (Lex.getCode() == tgtok::Eof)
return false;
return TokError("Unexpected token at top level");
}
// Check an assertion: Obtain the condition value and be sure it is true.
// If not, print a nonfatal error along with the message.
void TGParser::CheckAssert(SMLoc Loc, Init *Condition, Init *Message) {
auto *CondValue = dyn_cast_or_null<IntInit>(
Condition->convertInitializerTo(IntRecTy::get()));
if (CondValue) {
if (!CondValue->getValue()) {
PrintError(Loc, "assertion failed");
if (auto *MessageInit = dyn_cast<StringInit>(Message))
PrintNote(MessageInit->getValue());
else
PrintNote("(assert message is not a string)");
}
} else {
PrintError(Loc, "assert condition must of type bit, bits, or int.");
}
}
// Check all record assertions: For each one, resolve the condition
// and message, then call CheckAssert().
void TGParser::CheckRecordAsserts(Record &Rec) {
RecordResolver R(Rec);
R.setFinal(true);
for (auto Assertion : Rec.getAssertions()) {
Init *Condition = std::get<1>(Assertion)->resolveReferences(R);
Init *Message = std::get<2>(Assertion)->resolveReferences(R);
CheckAssert(std::get<0>(Assertion), Condition, Message);
}
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void RecordsEntry::dump() const {
if (Loop)
Loop->dump();
if (Rec)
Rec->dump();
}
LLVM_DUMP_METHOD void ForeachLoop::dump() const {
errs() << "foreach " << IterVar->getAsString() << " = "
<< ListValue->getAsString() << " in {\n";
for (const auto &E : Entries)
E.dump();
errs() << "}\n";
}
LLVM_DUMP_METHOD void MultiClass::dump() const {
errs() << "Record:\n";
Rec.dump();
errs() << "Defs:\n";
for (const auto &E : Entries)
E.dump();
}
#endif