//===- 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/DenseMapInfo.h" #include "llvm/ADT/None.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 #include #include #include using namespace llvm; //===----------------------------------------------------------------------===// // Support Code for the Semantic Actions. //===----------------------------------------------------------------------===// namespace llvm { struct SubClassReference { SMRange RefRange; Record *Rec; SmallVector TemplateArgs; SubClassReference() : Rec(nullptr) {} bool isInvalid() const { return Rec == nullptr; } }; struct SubMultiClassReference { SMRange RefRange; MultiClass *MC; SmallVector 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(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(Bit)) { if (auto VI = dyn_cast(VBI->getBitVar())) { if (R.getValue(VI->getName())) IsReference = true; } } else if (isa(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(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(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 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(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(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 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(V)) InitType = (Twine("' of type bit initializer with length ") + Twine(BI->getNumBits())).str(); else if (TypedInit *TI = dyn_cast(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; MapResolver R(CurRec); // Loop over all the subclass record's fields. Add template arguments // to the resolver map. Add regular fields to the new record. for (const RecordVal &Field : SC->getValues()) { if (Field.isTemplateArg()) { R.set(Field.getNameInit(), Field.getValue()); } else { if (AddValue(CurRec, SubClass.RefRange.Start, Field)) return true; } } ArrayRef TArgs = SC->getTemplateArgs(); assert(SubClass.TemplateArgs.size() <= TArgs.size() && "Too many template arguments allowed"); // Loop over the template argument names. If a value was specified, // reset the map value. If not and there was no default, complain. for (unsigned I = 0, E = TArgs.size(); I != E; ++I) { if (I < SubClass.TemplateArgs.size()) R.set(TArgs[I], SubClass.TemplateArgs[I]); else if (!R.isComplete(TArgs[I])) return Error(SubClass.RefRange.Start, "Value not specified for template argument '" + TArgs[I]->getAsUnquotedString() + "' (#" + Twine(I) + ") of parent class '" + SC->getNameInitAsString() + "'"); } // Copy the subclass record's assertions to the new record. CurRec->appendAssertions(SC); 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> 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); if (Entry.Assertion) return false; 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 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, foreach loop, or assertion to the current context. bool TGParser::addEntry(RecordsEntry E) { assert((!!E.Rec + !!E.Loop + !!E.Assertion) == 1 && "RecordsEntry has invalid number of items"); // If we are parsing a loop, add it to the loop's entries. if (!Loops.empty()) { Loops.back()->Entries.push_back(std::move(E)); return false; } // If it is a loop, then resolve and perform the loop. if (E.Loop) { SubstStack Stack; return resolve(*E.Loop, Stack, CurMultiClass == nullptr, CurMultiClass ? &CurMultiClass->Entries : nullptr); } // If we are parsing a multiclass, add it to the multiclass's entries. if (CurMultiClass) { CurMultiClass->Entries.push_back(std::move(E)); return false; } // If it is an assertion, then it's a top-level one, so check it. if (E.Assertion) { CheckAssert(E.Assertion->Loc, E.Assertion->Condition, E.Assertion->Message); return false; } // It must be a record, so finish it off. 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 *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(List); if (!LI) { if (!Final) { Dest->emplace_back(std::make_unique(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 &Source, SubstStack &Substs, bool Final, std::vector *Dest, SMLoc *Loc) { bool Error = false; for (auto &E : Source) { if (E.Loop) { Error = resolve(*E.Loop, Substs, Final, Dest); } else if (E.Assertion) { MapResolver R; for (const auto &S : Substs) R.set(S.first, S.second); Init *Condition = E.Assertion->Condition->resolveReferences(R); Init *Message = E.Assertion->Message->resolveReferences(R); if (Dest) Dest->push_back(std::make_unique( E.Assertion->Loc, Condition, Message)); else CheckAssert(E.Assertion->Loc, Condition, Message); } else { auto Rec = std::make_unique(*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 Rec) { Init *NewName = nullptr; 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; } NewName = Records.getNewAnonymousName(); } Rec->resolveReferences(NewName); checkConcrete(*Rec); if (!isa(Rec->getNameInit())) { PrintError(Rec->getLoc(), Twine("record name '") + Rec->getNameInit()->getAsString() + "' could not be fully resolved"); return true; } // Check the assertions. Rec->checkRecordAssertions(); // 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 a /// multiclass. 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 (ParseTemplateArgValueList(Result.TemplateArgs, CurRec, Result.Rec)) { Result.Rec = nullptr; // Error parsing value list. return Result; } if (CheckTemplateArgValues(Result.TemplateArgs, Result.RefRange.Start, Result.Rec)) { Result.Rec = nullptr; // Error checking value list. 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 (ParseTemplateArgValueList(Result.TemplateArgs, &CurMC->Rec, &Result.MC->Rec)) { Result.MC = nullptr; // Error parsing value list. 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 &Ranges, TypedInit *FirstItem) { Init *CurVal = FirstItem; if (!CurVal) CurVal = ParseValue(nullptr); IntInit *II = dyn_cast_or_null(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(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 &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 &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 &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 type /// Type ::= INT // int type /// Type ::= LIST '<' Type '>' // list 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 type"); return nullptr; } uint64_t Val = Lex.getCurIntVal(); if (Lex.Lex() != tgtok::greater) { // Eat count. TokError("expected '>' at end of bits 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 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)) { RecordVal *RV = TemplateRec->getValue(TemplateArgName); assert(RV && "Template arg doesn't exist??"); RV->setUsed(true); 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(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(someDag) as a shorthand for // !cast(!getdagop(someDag)). Type = ParseOperatorType(); if (!Type) { TokError("did not get type for unary operator"); return nullptr; } if (!isa(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(LHS); StringInit *LHSs = dyn_cast(LHS); DagInit *LHSd = dyn_cast(LHS); TypedInit *LHSt = dyn_cast(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(LHSt->getType()); StringRecTy *SType = dyn_cast(LHSt->getType()); DagRecTy *DType = dyn_cast(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(LHS); TypedInit *LHSt = dyn_cast(LHS); if (!LHSl && !LHSt) { TokError("expected list type argument in unary operator"); return nullptr; } if (LHSt) { ListRecTy *LType = dyn_cast(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(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(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 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(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(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(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(ItemType) ->getElementType() ->getAsString() + "'"); return nullptr; } } if (InitList.size() == 2 && !isa(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(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(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(MHS); if (!MHSt && !isa(MHS)) { Error(MHSLoc, "could not determine type of the child list in !dag"); return nullptr; } if (MHSt && !isa(MHSt->getType())) { Error(MHSLoc, Twine("expected list of children, got type '") + MHSt->getType()->getAsString() + "'"); return nullptr; } TypedInit *RHSt = dyn_cast(RHS); if (!RHSt && !isa(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, 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(MHS)) MHSTy = MHSt->getType(); if (BitsInit *MHSbits = dyn_cast(MHS)) MHSTy = BitsRecTy::get(MHSbits->getNumBits()); if (isa(MHS)) MHSTy = BitRecTy::get(); if (TypedInit *RHSt = dyn_cast(RHS)) RHSTy = RHSt->getType(); if (BitsInit *RHSbits = dyn_cast(RHS)) RHSTy = BitsRecTy::get(RHSbits->getNumBits()); if (isa(RHS)) RHSTy = BitRecTy::get(); // For UnsetInit, it's typed from the other hand. if (isa(MHS)) MHSTy = RHSTy; if (isa(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(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::XFind: return ParseOperationFind(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(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(ListUntyped); if (!List) { TokError(Twine("could not get type of !foldl list: '") + ListUntyped->getAsString() + "'"); return nullptr; } ListRecTy *ListType = dyn_cast(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 ParseRecTmp; Record *ParseRec = CurRec; if (!ParseRec) { ParseRecTmp = std::make_unique(".parse", ArrayRef{}, 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(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::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(LHS); if (!LHSt && !isa(LHS)) { TokError("could not determine type of the string in !substr"); return nullptr; } if (LHSt && !isa(LHSt->getType())) { TokError(Twine("expected string, got type '") + LHSt->getType()->getAsString() + "'"); return nullptr; } TypedInit *MHSt = dyn_cast(MHS); if (!MHSt && !isa(MHS)) { TokError("could not determine type of the start position in !substr"); return nullptr; } if (MHSt && !isa(MHSt->getType())) { Error(MHSLoc, Twine("expected int, got type '") + MHSt->getType()->getAsString() + "'"); return nullptr; } if (RHS) { TypedInit *RHSt = dyn_cast(RHS); if (!RHSt && !isa(RHS)) { TokError("could not determine type of the length in !substr"); return nullptr; } if (RHSt && !isa(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 !find operation. Return null on error. /// /// Substr ::= !find(string, string [, start-int]) => int Init *TGParser::ParseOperationFind(Record *CurRec, RecTy *ItemType) { TernOpInit::TernaryOp Code = TernOpInit::FIND; RecTy *Type = IntRecTy::get(); Lex.Lex(); // eat the operation if (!consume(tgtok::l_paren)) { TokError("expected '(' after !find operator"); return nullptr; } Init *LHS = ParseValue(CurRec); if (!LHS) return nullptr; if (!consume(tgtok::comma)) { TokError("expected ',' in !find 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(0); } if (!consume(tgtok::r_paren)) { TokError("expected ')' in !find operator"); return nullptr; } if (ItemType && !Type->typeIsConvertibleTo(ItemType)) { Error(RHSLoc, Twine("expected value of type '") + ItemType->getAsString() + "', got '" + Type->getAsString() + "'"); } TypedInit *LHSt = dyn_cast(LHS); if (!LHSt && !isa(LHS)) { TokError("could not determine type of the source string in !find"); return nullptr; } if (LHSt && !isa(LHSt->getType())) { TokError(Twine("expected string, got type '") + LHSt->getType()->getAsString() + "'"); return nullptr; } TypedInit *MHSt = dyn_cast(MHS); if (!MHSt && !isa(MHS)) { TokError("could not determine type of the target string in !find"); return nullptr; } if (MHSt && !isa(MHSt->getType())) { Error(MHSLoc, Twine("expected string, got type '") + MHSt->getType()->getAsString() + "'"); return nullptr; } if (RHS) { TypedInit *RHSt = dyn_cast(RHS); if (!RHSt && !isa(RHS)) { TokError("could not determine type of the start position in !find"); return nullptr; } if (RHSt && !isa(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 /// Filter ::= !foreach(ID, list, predicate) ==> list 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(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(MHSt->getType())) { InEltType = InListTy->getElementType(); if (ItemType) { if (ListRecTy *OutListTy = dyn_cast(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(MHSt->getType())) { if (Operation == tgtok::XFilter) { TokError("!filter must have a list argument"); return nullptr; } InEltType = InDagTy; if (ItemType && !isa(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 ParseRecTmp; Record *ParseRec = CurRec; if (!ParseRec) { ParseRecTmp = std::make_unique(".parse", ArrayRef{}, 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(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 Case; SmallVector 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(V)) VTy = Vt->getType(); if (BitsInit *Vbits = dyn_cast(V)) VTy = BitsRecTy::get(Vbits->getNumBits()); if (isa(V)) VTy = BitRecTy::get(); if (Type == nullptr) { if (!isa(V)) Type = VTy; } else { if (!isa(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 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 ::= CLASSID '<' ValueListNE '>' (CLASSID has been consumed) // This is supposed to synthesize a new anonymous definition, deriving // from the class with the template arguments, but no body. Record *Class = Records.getClass(Name->getValue()); if (!Class) { Error(NameLoc, "Expected a class name, got '" + Name->getValue() + "'"); return nullptr; } SmallVector Args; Lex.Lex(); // consume the < if (ParseTemplateArgValueList(Args, CurRec, Class)) return nullptr; // Error parsing value list. if (CheckTemplateArgValues(Args, NameLoc, Class)) return nullptr; // Error checking template argument values. // Loop through the arguments that were not specified and make sure // they have a complete value. ArrayRef TArgs = Class->getTemplateArgs(); for (unsigned I = Args.size(), E = TArgs.size(); I < E; ++I) { RecordVal *Arg = Class->getValue(TArgs[I]); if (!Arg->getValue()->isComplete()) Error(NameLoc, "Value not specified for template argument '" + TArgs[I]->getAsUnquotedString() + "' (#" + Twine(I) + ") of parent class '" + Class->getNameInitAsString() + "'"); } return VarDefInit::get(Class, Args)->Fold(); } case tgtok::l_brace: { // Value ::= '{' ValueList '}' SMLoc BraceLoc = Lex.getLoc(); Lex.Lex(); // eat the '{' SmallVector 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 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 values are allowed to initialize n bits. if (BitsInit *BI = dyn_cast(Vals[i])) { for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i) NewBits.push_back(BI->getBit((e - i) - 1)); continue; } // bits can also come from variable initializers. if (VarInit *VI = dyn_cast(Vals[i])) { if (BitsRecTy *BitsRec = dyn_cast(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 Vals; RecTy *DeducedEltTy = nullptr; ListRecTy *GivenListTy = nullptr; if (ItemType) { ListRecTy *ListType = dyn_cast(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, 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(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, 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: case tgtok::XFind: { // 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 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 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(Result); if (!LHS) { Error(PasteLoc, "LHS of paste is not typed!"); return nullptr; } // Check if it's a 'listA # listB' if (isa(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( 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(RHSResult); if (!RHS) { Error(PasteLoc, "RHS of paste is not typed!"); return nullptr; } if (RHS->getType() != StringRecTy::get()) { auto CastRHS = dyn_cast( 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> &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 /// in a vector. Note that this always expects to be able to parse at least one /// value. It returns an empty list if this is not possible. /// /// ValueList ::= Value (',' Value) /// void TGParser::ParseValueList(SmallVectorImpl &Result, Record *CurRec, RecTy *ItemType) { 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; Result.push_back(ParseValue(CurRec, ItemType)); if (!Result.back()) { Result.clear(); return; } } } // ParseTemplateArgValueList - Parse a template argument list with the syntax // shown, filling in the Result vector. The open angle has been consumed. // An empty argument list is allowed. Return false if okay, true if an // error was detected. // // TemplateArgList ::= '<' [Value {',' Value}*] '>' bool TGParser::ParseTemplateArgValueList(SmallVectorImpl &Result, Record *CurRec, Record *ArgsRec) { assert(Result.empty() && "Result vector is not empty"); ArrayRef TArgs = ArgsRec->getTemplateArgs(); unsigned ArgIndex = 0; RecTy *ItemType; if (consume(tgtok::greater)) // empty value list return false; while (true) { if (ArgIndex >= TArgs.size()) { TokError("Too many template arguments: " + utostr(ArgIndex + 1)); return true; } const RecordVal *Arg = ArgsRec->getValue(TArgs[ArgIndex]); assert(Arg && "Template argument record not found"); ItemType = Arg->getType(); Init *Value = ParseValue(CurRec, ItemType); if (!Value) return true; Result.push_back(Value); if (consume(tgtok::greater)) // end of argument list? return false; if (!consume(tgtok::comma)) return TokError("Expected comma before next argument"); ++ArgIndex; } } /// ParseDeclaration - Read a declaration, returning the name of field ID, or an /// empty string on error. This can happen in a number of different contexts, /// including within a def or in the template args for a class (in which case /// CurRec will be non-null) and within the template args for a multiclass (in /// 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(); bool BadField; if (!ParsingTemplateArgs) { // def, possibly in a multiclass BadField = AddValue(CurRec, IdLoc, RecordVal(DeclName, IdLoc, Type, HasField ? RecordVal::FK_NonconcreteOK : RecordVal::FK_Normal)); } else if (CurRec) { // class template argument DeclName = QualifyName(*CurRec, CurMultiClass, DeclName, ":"); BadField = AddValue(CurRec, IdLoc, RecordVal(DeclName, IdLoc, Type, RecordVal::FK_TemplateArg)); } else { // multiclass template argument assert(CurMultiClass && "invalid context for template argument"); DeclName = QualifyName(CurMultiClass->Rec, CurMultiClass, DeclName, "::"); BadField = AddValue(CurRec, IdLoc, RecordVal(DeclName, IdLoc, Type, RecordVal::FK_TemplateArg)); } if (BadField) return nullptr; // If a value is present, parse it and set new field's value. 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 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(I); if (TI && isa(TI->getType())) { ForeachListValue = I; IterType = cast(TI->getType())->getElementType(); break; } if (TI) { if (ParseRangePiece(Ranges, TI)) return nullptr; break; } Error(ValueLoc, "expected a list, got '" + I->getAsString() + "'"); 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 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 class. 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 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(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 &LetInfo : LetStack) for (LetRecord &LR : LetInfo) if (SetValue(CurRec, LR.Loc, LR.Name, LR.Bits, LR.Value)) return true; return false; } /// Apply the current let bindings to the RecordsEntry. bool TGParser::ApplyLetStack(RecordsEntry &Entry) { if (Entry.Rec) return ApplyLetStack(Entry.Rec.get()); // Let bindings are not applied to assertions. if (Entry.Assertion) return false; 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 record definition. /// Return false if okay, true if 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 CurRec; Init *Name = ParseObjectName(CurMultiClass); if (!Name) return true; if (isa(Name)) CurRec = std::make_unique(Records.getNewAnonymousName(), DefLoc, Records, /*Anonymous=*/true); else CurRec = std::make_unique(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(Type)) return Error(Defset.Loc, "expected list type"); Defset.EltTy = cast(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(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 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(true)}, 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(Loc, nullptr, ThenClauseList)); if (ParseIfBody(CurMultiClass, "then")) return true; std::unique_ptr 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(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 (CurRec) CurRec->addAssertion(ConditionLoc, Condition, Message); else addEntry(std::make_unique(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(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; if (ParseObjectBody(CurRec)) return true; if (!NoWarnOnUnusedTemplateArgs) CurRec->checkUnusedTemplateArgs(); return false; } /// 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 &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 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 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 ::= Assert /// MultiClassObject ::= DefInst /// MultiClassObject ::= DefMInst /// MultiClassObject ::= Defvar /// MultiClassObject ::= Foreach /// MultiClassObject ::= If /// 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(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: 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); } if (!NoWarnOnUnusedTemplateArgs) CurMultiClass->Rec.checkUnusedTemplateArgs(); 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(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 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 get the multiclass and then loop // through its template argument names. Substs contains a substitution // value for each argument, either the value specified or the default. // Then we can resolve the template arguments. MultiClass *MC = MultiClasses[std::string(Ref.Rec->getName())].get(); assert(MC && "Didn't lookup multiclass correctly?"); ArrayRef TemplateVals = Ref.TemplateArgs; ArrayRef TArgs = MC->Rec.getTemplateArgs(); 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 '" + TArgs[i]->getAsUnquotedString() + "' (#" + Twine(i) + ") 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-multiclasses) 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); 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 the types of the template argument values for a class // inheritance, multiclass invocation, or anonymous class invocation. // If necessary, replace an argument with a cast to the required type. // The argument count has already been checked. bool TGParser::CheckTemplateArgValues(SmallVectorImpl &Values, SMLoc Loc, Record *ArgsRec) { ArrayRef TArgs = ArgsRec->getTemplateArgs(); for (unsigned I = 0, E = Values.size(); I < E; ++I) { RecordVal *Arg = ArgsRec->getValue(TArgs[I]); RecTy *ArgType = Arg->getType(); auto *Value = Values[I]; if (TypedInit *ArgValue = dyn_cast(Value)) { auto *CastValue = ArgValue->getCastTo(ArgType); if (CastValue) { assert((!isa(CastValue) || cast(CastValue)->getType()->typeIsA(ArgType)) && "result of template arg value cast has wrong type"); Values[I] = CastValue; } else { PrintFatalError(Loc, "Value specified for template argument '" + Arg->getNameInitAsString() + "' (#" + Twine(I) + ") is of type " + ArgValue->getType()->getAsString() + "; expected type " + ArgType->getAsString() + ": " + ArgValue->getAsString()); } } } return false; } #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