diff options
Diffstat (limited to 'contrib/llvm/lib/TableGen')
-rw-r--r-- | contrib/llvm/lib/TableGen/Error.cpp | 9 | ||||
-rw-r--r-- | contrib/llvm/lib/TableGen/JSONBackend.cpp | 189 | ||||
-rw-r--r-- | contrib/llvm/lib/TableGen/Main.cpp | 2 | ||||
-rw-r--r-- | contrib/llvm/lib/TableGen/Record.cpp | 1400 | ||||
-rw-r--r-- | contrib/llvm/lib/TableGen/TGLexer.cpp | 60 | ||||
-rw-r--r-- | contrib/llvm/lib/TableGen/TGLexer.h | 23 | ||||
-rw-r--r-- | contrib/llvm/lib/TableGen/TGParser.cpp | 1586 | ||||
-rw-r--r-- | contrib/llvm/lib/TableGen/TGParser.h | 89 |
8 files changed, 2131 insertions, 1227 deletions
diff --git a/contrib/llvm/lib/TableGen/Error.cpp b/contrib/llvm/lib/TableGen/Error.cpp index b4830178a269..e6171c71efc0 100644 --- a/contrib/llvm/lib/TableGen/Error.cpp +++ b/contrib/llvm/lib/TableGen/Error.cpp @@ -15,6 +15,7 @@ #include "llvm/TableGen/Error.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" #include <cstdlib> @@ -51,9 +52,7 @@ void PrintWarning(const char *Loc, const Twine &Msg) { SrcMgr.PrintMessage(SMLoc::getFromPointer(Loc), SourceMgr::DK_Warning, Msg); } -void PrintWarning(const Twine &Msg) { - errs() << "warning:" << Msg << "\n"; -} +void PrintWarning(const Twine &Msg) { WithColor::warning() << Msg << "\n"; } void PrintError(ArrayRef<SMLoc> ErrorLoc, const Twine &Msg) { PrintMessage(ErrorLoc, SourceMgr::DK_Error, Msg); @@ -63,9 +62,7 @@ void PrintError(const char *Loc, const Twine &Msg) { SrcMgr.PrintMessage(SMLoc::getFromPointer(Loc), SourceMgr::DK_Error, Msg); } -void PrintError(const Twine &Msg) { - errs() << "error:" << Msg << "\n"; -} +void PrintError(const Twine &Msg) { WithColor::error() << Msg << "\n"; } void PrintFatalError(const Twine &Msg) { PrintError(Msg); diff --git a/contrib/llvm/lib/TableGen/JSONBackend.cpp b/contrib/llvm/lib/TableGen/JSONBackend.cpp new file mode 100644 index 000000000000..36cb2208a294 --- /dev/null +++ b/contrib/llvm/lib/TableGen/JSONBackend.cpp @@ -0,0 +1,189 @@ +//===- JSONBackend.cpp - Generate a JSON dump of all records. -*- C++ -*-=====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This TableGen back end generates a machine-readable representation +// of all the classes and records defined by the input, in JSON format. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/BitVector.h" +#include "llvm/Support/Debug.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include "llvm/Support/JSON.h" + +#define DEBUG_TYPE "json-emitter" + +using namespace llvm; + +namespace { + +class JSONEmitter { +private: + RecordKeeper &Records; + + json::Value translateInit(const Init &I); + json::Array listSuperclasses(const Record &R); + +public: + JSONEmitter(RecordKeeper &R); + + void run(raw_ostream &OS); +}; + +} // end anonymous namespace + +JSONEmitter::JSONEmitter(RecordKeeper &R) : Records(R) {} + +json::Value JSONEmitter::translateInit(const Init &I) { + + // Init subclasses that we return as JSON primitive values of one + // kind or another. + + if (isa<UnsetInit>(&I)) { + return nullptr; + } else if (auto *Bit = dyn_cast<BitInit>(&I)) { + return Bit->getValue() ? 1 : 0; + } else if (auto *Bits = dyn_cast<BitsInit>(&I)) { + json::Array array; + for (unsigned i = 0, limit = Bits->getNumBits(); i < limit; i++) + array.push_back(translateInit(*Bits->getBit(i))); + return std::move(array); + } else if (auto *Int = dyn_cast<IntInit>(&I)) { + return Int->getValue(); + } else if (auto *Str = dyn_cast<StringInit>(&I)) { + return Str->getValue(); + } else if (auto *Code = dyn_cast<CodeInit>(&I)) { + return Code->getValue(); + } else if (auto *List = dyn_cast<ListInit>(&I)) { + json::Array array; + for (auto val : *List) + array.push_back(translateInit(*val)); + return std::move(array); + } + + // Init subclasses that we return as JSON objects containing a + // 'kind' discriminator. For these, we also provide the same + // translation back into TableGen input syntax that -print-records + // would give. + + json::Object obj; + obj["printable"] = I.getAsString(); + + if (auto *Def = dyn_cast<DefInit>(&I)) { + obj["kind"] = "def"; + obj["def"] = Def->getDef()->getName(); + return std::move(obj); + } else if (auto *Var = dyn_cast<VarInit>(&I)) { + obj["kind"] = "var"; + obj["var"] = Var->getName(); + return std::move(obj); + } else if (auto *VarBit = dyn_cast<VarBitInit>(&I)) { + if (auto *Var = dyn_cast<VarInit>(VarBit->getBitVar())) { + obj["kind"] = "varbit"; + obj["var"] = Var->getName(); + obj["index"] = VarBit->getBitNum(); + return std::move(obj); + } + } else if (auto *Dag = dyn_cast<DagInit>(&I)) { + obj["kind"] = "dag"; + obj["operator"] = translateInit(*Dag->getOperator()); + if (auto name = Dag->getName()) + obj["name"] = name->getAsUnquotedString(); + json::Array args; + for (unsigned i = 0, limit = Dag->getNumArgs(); i < limit; ++i) { + json::Array arg; + arg.push_back(translateInit(*Dag->getArg(i))); + if (auto argname = Dag->getArgName(i)) + arg.push_back(argname->getAsUnquotedString()); + else + arg.push_back(nullptr); + args.push_back(std::move(arg)); + } + obj["args"] = std::move(args); + return std::move(obj); + } + + // Final fallback: anything that gets past here is simply given a + // kind field of 'complex', and the only other field is the standard + // 'printable' representation. + + assert(!I.isConcrete()); + obj["kind"] = "complex"; + return std::move(obj); +} + +void JSONEmitter::run(raw_ostream &OS) { + json::Object root; + + root["!tablegen_json_version"] = 1; + + // Prepare the arrays that will list the instances of every class. + // We mostly fill those in by iterating over the superclasses of + // each def, but we also want to ensure we store an empty list for a + // class with no instances at all, so we do a preliminary iteration + // over the classes, invoking std::map::operator[] to default- + // construct the array for each one. + std::map<std::string, json::Array> instance_lists; + for (const auto &C : Records.getClasses()) { + auto &Name = C.second->getNameInitAsString(); + (void)instance_lists[Name]; + } + + // Main iteration over the defs. + for (const auto &D : Records.getDefs()) { + auto &Name = D.second->getNameInitAsString(); + auto &Def = *D.second; + + json::Object obj; + json::Array fields; + + for (const RecordVal &RV : Def.getValues()) { + if (!Def.isTemplateArg(RV.getNameInit())) { + auto Name = RV.getNameInitAsString(); + if (RV.getPrefix()) + fields.push_back(Name); + obj[Name] = translateInit(*RV.getValue()); + } + } + + obj["!fields"] = std::move(fields); + + json::Array superclasses; + for (const auto &SuperPair : Def.getSuperClasses()) + superclasses.push_back(SuperPair.first->getNameInitAsString()); + obj["!superclasses"] = std::move(superclasses); + + obj["!name"] = Name; + obj["!anonymous"] = Def.isAnonymous(); + + root[Name] = std::move(obj); + + // Add this def to the instance list for each of its superclasses. + for (const auto &SuperPair : Def.getSuperClasses()) { + auto SuperName = SuperPair.first->getNameInitAsString(); + instance_lists[SuperName].push_back(Name); + } + } + + // Make a JSON object from the std::map of instance lists. + json::Object instanceof; + for (auto kv: instance_lists) + instanceof[kv.first] = std::move(kv.second); + root["!instanceof"] = std::move(instanceof); + + // Done. Write the output. + OS << json::Value(std::move(root)) << "\n"; +} + +namespace llvm { + +void EmitJSON(RecordKeeper &RK, raw_ostream &OS) { JSONEmitter(RK).run(OS); } +} // end namespace llvm diff --git a/contrib/llvm/lib/TableGen/Main.cpp b/contrib/llvm/lib/TableGen/Main.cpp index be35f894cccd..3a0701626089 100644 --- a/contrib/llvm/lib/TableGen/Main.cpp +++ b/contrib/llvm/lib/TableGen/Main.cpp @@ -52,7 +52,7 @@ static int reportError(const char *ProgName, Twine Msg) { return 1; } -/// \brief Create a dependency file for `-d` option. +/// Create a dependency file for `-d` option. /// /// This functionality is really only for the benefit of the build system. /// It is similar to GCC's `-M*` family of options. diff --git a/contrib/llvm/lib/TableGen/Record.cpp b/contrib/llvm/lib/TableGen/Record.cpp index 2c5b745433b8..43d178caef30 100644 --- a/contrib/llvm/lib/TableGen/Record.cpp +++ b/contrib/llvm/lib/TableGen/Record.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" @@ -63,6 +64,8 @@ bool RecTy::typeIsConvertibleTo(const RecTy *RHS) const { return Kind == RHS->getRecTyKind(); } +bool RecTy::typeIsA(const RecTy *RHS) const { return this == RHS; } + bool BitRecTy::typeIsConvertibleTo(const RecTy *RHS) const{ if (RecTy::typeIsConvertibleTo(RHS) || RHS->getRecTyKind() == IntRecTyKind) return true; @@ -92,15 +95,31 @@ bool BitsRecTy::typeIsConvertibleTo(const RecTy *RHS) const { return (kind == BitRecTyKind && Size == 1) || (kind == IntRecTyKind); } +bool BitsRecTy::typeIsA(const RecTy *RHS) const { + if (const BitsRecTy *RHSb = dyn_cast<BitsRecTy>(RHS)) + return RHSb->Size == Size; + return false; +} + bool IntRecTy::typeIsConvertibleTo(const RecTy *RHS) const { RecTyKind kind = RHS->getRecTyKind(); return kind==BitRecTyKind || kind==BitsRecTyKind || kind==IntRecTyKind; } +bool CodeRecTy::typeIsConvertibleTo(const RecTy *RHS) const { + RecTyKind Kind = RHS->getRecTyKind(); + return Kind == CodeRecTyKind || Kind == StringRecTyKind; +} + std::string StringRecTy::getAsString() const { return "string"; } +bool StringRecTy::typeIsConvertibleTo(const RecTy *RHS) const { + RecTyKind Kind = RHS->getRecTyKind(); + return Kind == StringRecTyKind || Kind == CodeRecTyKind; +} + std::string ListRecTy::getAsString() const { return "list<" + Ty->getAsString() + ">"; } @@ -111,58 +130,152 @@ bool ListRecTy::typeIsConvertibleTo(const RecTy *RHS) const { return false; } +bool ListRecTy::typeIsA(const RecTy *RHS) const { + if (const ListRecTy *RHSl = dyn_cast<ListRecTy>(RHS)) + return getElementType()->typeIsA(RHSl->getElementType()); + return false; +} + std::string DagRecTy::getAsString() const { return "dag"; } -RecordRecTy *RecordRecTy::get(Record *R) { - return dyn_cast<RecordRecTy>(R->getDefInit()->getType()); +static void ProfileRecordRecTy(FoldingSetNodeID &ID, + ArrayRef<Record *> Classes) { + ID.AddInteger(Classes.size()); + for (Record *R : Classes) + ID.AddPointer(R); +} + +RecordRecTy *RecordRecTy::get(ArrayRef<Record *> UnsortedClasses) { + if (UnsortedClasses.empty()) { + static RecordRecTy AnyRecord(0); + return &AnyRecord; + } + + FoldingSet<RecordRecTy> &ThePool = + UnsortedClasses[0]->getRecords().RecordTypePool; + + SmallVector<Record *, 4> Classes(UnsortedClasses.begin(), + UnsortedClasses.end()); + llvm::sort(Classes.begin(), Classes.end(), + [](Record *LHS, Record *RHS) { + return LHS->getNameInitAsString() < RHS->getNameInitAsString(); + }); + + FoldingSetNodeID ID; + ProfileRecordRecTy(ID, Classes); + + void *IP = nullptr; + if (RecordRecTy *Ty = ThePool.FindNodeOrInsertPos(ID, IP)) + return Ty; + +#ifndef NDEBUG + // Check for redundancy. + for (unsigned i = 0; i < Classes.size(); ++i) { + for (unsigned j = 0; j < Classes.size(); ++j) { + assert(i == j || !Classes[i]->isSubClassOf(Classes[j])); + } + assert(&Classes[0]->getRecords() == &Classes[i]->getRecords()); + } +#endif + + void *Mem = Allocator.Allocate(totalSizeToAlloc<Record *>(Classes.size()), + alignof(RecordRecTy)); + RecordRecTy *Ty = new(Mem) RecordRecTy(Classes.size()); + std::uninitialized_copy(Classes.begin(), Classes.end(), + Ty->getTrailingObjects<Record *>()); + ThePool.InsertNode(Ty, IP); + return Ty; +} + +void RecordRecTy::Profile(FoldingSetNodeID &ID) const { + ProfileRecordRecTy(ID, getClasses()); } std::string RecordRecTy::getAsString() const { - return Rec->getName(); + if (NumClasses == 1) + return getClasses()[0]->getNameInitAsString(); + + std::string Str = "{"; + bool First = true; + for (Record *R : getClasses()) { + if (!First) + Str += ", "; + First = false; + Str += R->getNameInitAsString(); + } + Str += "}"; + return Str; +} + +bool RecordRecTy::isSubClassOf(Record *Class) const { + return llvm::any_of(getClasses(), [Class](Record *MySuperClass) { + return MySuperClass == Class || + MySuperClass->isSubClassOf(Class); + }); } bool RecordRecTy::typeIsConvertibleTo(const RecTy *RHS) const { + if (this == RHS) + return true; + const RecordRecTy *RTy = dyn_cast<RecordRecTy>(RHS); if (!RTy) return false; - if (RTy->getRecord() == Rec || Rec->isSubClassOf(RTy->getRecord())) - return true; + return llvm::all_of(RTy->getClasses(), [this](Record *TargetClass) { + return isSubClassOf(TargetClass); + }); +} - for (const auto &SCPair : RTy->getRecord()->getSuperClasses()) - if (Rec->isSubClassOf(SCPair.first)) - return true; +bool RecordRecTy::typeIsA(const RecTy *RHS) const { + return typeIsConvertibleTo(RHS); +} - return false; +static RecordRecTy *resolveRecordTypes(RecordRecTy *T1, RecordRecTy *T2) { + SmallVector<Record *, 4> CommonSuperClasses; + SmallVector<Record *, 4> Stack; + + Stack.insert(Stack.end(), T1->classes_begin(), T1->classes_end()); + + while (!Stack.empty()) { + Record *R = Stack.back(); + Stack.pop_back(); + + if (T2->isSubClassOf(R)) { + CommonSuperClasses.push_back(R); + } else { + R->getDirectSuperClasses(Stack); + } + } + + return RecordRecTy::get(CommonSuperClasses); } RecTy *llvm::resolveTypes(RecTy *T1, RecTy *T2) { + if (T1 == T2) + return T1; + + if (RecordRecTy *RecTy1 = dyn_cast<RecordRecTy>(T1)) { + if (RecordRecTy *RecTy2 = dyn_cast<RecordRecTy>(T2)) + return resolveRecordTypes(RecTy1, RecTy2); + } + if (T1->typeIsConvertibleTo(T2)) return T2; if (T2->typeIsConvertibleTo(T1)) return T1; - // If one is a Record type, check superclasses - if (RecordRecTy *RecTy1 = dyn_cast<RecordRecTy>(T1)) { - // See if T2 inherits from a type T1 also inherits from - for (const auto &SuperPair1 : RecTy1->getRecord()->getSuperClasses()) { - RecordRecTy *SuperRecTy1 = RecordRecTy::get(SuperPair1.first); - RecTy *NewType1 = resolveTypes(SuperRecTy1, T2); - if (NewType1) - return NewType1; - } - } - if (RecordRecTy *RecTy2 = dyn_cast<RecordRecTy>(T2)) { - // See if T1 inherits from a type T2 also inherits from - for (const auto &SuperPair2 : RecTy2->getRecord()->getSuperClasses()) { - RecordRecTy *SuperRecTy2 = RecordRecTy::get(SuperPair2.first); - RecTy *NewType2 = resolveTypes(T1, SuperRecTy2); - if (NewType2) - return NewType2; + if (ListRecTy *ListTy1 = dyn_cast<ListRecTy>(T1)) { + if (ListRecTy *ListTy2 = dyn_cast<ListRecTy>(T2)) { + RecTy* NewType = resolveTypes(ListTy1->getElementType(), + ListTy2->getElementType()); + if (NewType) + return NewType->getListTy(); } } + return nullptr; } @@ -181,17 +294,11 @@ UnsetInit *UnsetInit::get() { return &TheInit; } -Init *UnsetInit::convertInitializerTo(RecTy *Ty) const { - if (auto *BRT = dyn_cast<BitsRecTy>(Ty)) { - SmallVector<Init *, 16> NewBits(BRT->getNumBits()); - - for (unsigned i = 0; i != BRT->getNumBits(); ++i) - NewBits[i] = UnsetInit::get(); - - return BitsInit::get(NewBits); - } +Init *UnsetInit::getCastTo(RecTy *Ty) const { + return const_cast<UnsetInit *>(this); +} - // All other types can just be returned. +Init *UnsetInit::convertInitializerTo(RecTy *Ty) const { return const_cast<UnsetInit *>(this); } @@ -287,6 +394,14 @@ BitsInit::convertInitializerBitRange(ArrayRef<unsigned> Bits) const { return BitsInit::get(NewBits); } +bool BitsInit::isConcrete() const { + for (unsigned i = 0, e = getNumBits(); i != e; ++i) { + if (!getBit(i)->isConcrete()) + return false; + } + return true; +} + std::string BitsInit::getAsString() const { std::string Result = "{ "; for (unsigned i = 0, e = getNumBits(); i != e; ++i) { @@ -299,54 +414,35 @@ std::string BitsInit::getAsString() const { return Result + " }"; } -// Fix bit initializer to preserve the behavior that bit reference from a unset -// bits initializer will resolve into VarBitInit to keep the field name and bit -// number used in targets with fixed insn length. -static Init *fixBitInit(const RecordVal *RV, Init *Before, Init *After) { - if (RV || !isa<UnsetInit>(After)) - return After; - return Before; -} - // resolveReferences - If there are any field references that refer to fields // that have been filled in, we can propagate the values now. -Init *BitsInit::resolveReferences(Record &R, const RecordVal *RV) const { +Init *BitsInit::resolveReferences(Resolver &R) const { bool Changed = false; SmallVector<Init *, 16> NewBits(getNumBits()); - Init *CachedInit = nullptr; - Init *CachedBitVar = nullptr; - bool CachedBitVarChanged = false; + Init *CachedBitVarRef = nullptr; + Init *CachedBitVarResolved = nullptr; for (unsigned i = 0, e = getNumBits(); i != e; ++i) { Init *CurBit = getBit(i); - Init *CurBitVar = CurBit->getBitVar(); - - NewBits[i] = CurBit; + Init *NewBit = CurBit; - if (CurBitVar == CachedBitVar) { - if (CachedBitVarChanged) { - Init *Bit = CachedInit->getBit(CurBit->getBitNum()); - NewBits[i] = fixBitInit(RV, CurBit, Bit); + if (VarBitInit *CurBitVar = dyn_cast<VarBitInit>(CurBit)) { + if (CurBitVar->getBitVar() != CachedBitVarRef) { + CachedBitVarRef = CurBitVar->getBitVar(); + CachedBitVarResolved = CachedBitVarRef->resolveReferences(R); } - continue; - } - CachedBitVar = CurBitVar; - CachedBitVarChanged = false; - - Init *B; - do { - B = CurBitVar; - CurBitVar = CurBitVar->resolveReferences(R, RV); - CachedBitVarChanged |= B != CurBitVar; - Changed |= B != CurBitVar; - } while (B != CurBitVar); - CachedInit = CurBitVar; - - if (CachedBitVarChanged) { - Init *Bit = CurBitVar->getBit(CurBit->getBitNum()); - NewBits[i] = fixBitInit(RV, CurBit, Bit); + + NewBit = CachedBitVarResolved->getBit(CurBitVar->getBitNum()); + } else { + // getBit(0) implicitly converts int and bits<1> values to bit. + NewBit = CurBit->resolveReferences(R)->getBit(0); } + + if (isa<UnsetInit>(NewBit) && R.keepUnsetBits()) + NewBit = CurBit; + NewBits[i] = NewBit; + Changed |= CurBit != NewBit; } if (Changed) @@ -433,6 +529,8 @@ StringInit *StringInit::get(StringRef V) { Init *StringInit::convertInitializerTo(RecTy *Ty) const { if (isa<StringRecTy>(Ty)) return const_cast<StringInit *>(this); + if (isa<CodeRecTy>(Ty)) + return CodeInit::get(getValue()); return nullptr; } @@ -440,6 +538,8 @@ Init *StringInit::convertInitializerTo(RecTy *Ty) const { Init *CodeInit::convertInitializerTo(RecTy *Ty) const { if (isa<CodeRecTy>(Ty)) return const_cast<CodeInit *>(this); + if (isa<StringRecTy>(Ty)) + return StringInit::get(getValue()); return nullptr; } @@ -464,6 +564,9 @@ ListInit *ListInit::get(ArrayRef<Init *> Range, RecTy *EltTy) { if (ListInit *I = ThePool.FindNodeOrInsertPos(ID, IP)) return I; + assert(Range.empty() || !isa<TypedInit>(Range[0]) || + cast<TypedInit>(Range[0])->getType()->typeIsConvertibleTo(EltTy)); + void *Mem = Allocator.Allocate(totalSizeToAlloc<Init *>(Range.size()), alignof(ListInit)); ListInit *I = new(Mem) ListInit(Range.size(), EltTy); @@ -501,7 +604,7 @@ Init *ListInit::convertInitializerTo(RecTy *Ty) const { if (!Changed) return const_cast<ListInit*>(this); - return ListInit::get(Elements, Ty); + return ListInit::get(Elements, ElementType); } return nullptr; @@ -515,7 +618,7 @@ Init *ListInit::convertInitListSlice(ArrayRef<unsigned> Elements) const { return nullptr; Vals.push_back(getElement(Element)); } - return ListInit::get(Vals, getType()); + return ListInit::get(Vals, getElementType()); } Record *ListInit::getElementAsRecord(unsigned i) const { @@ -526,38 +629,28 @@ Record *ListInit::getElementAsRecord(unsigned i) const { return DI->getDef(); } -Init *ListInit::resolveReferences(Record &R, const RecordVal *RV) const { +Init *ListInit::resolveReferences(Resolver &R) const { SmallVector<Init*, 8> Resolved; Resolved.reserve(size()); bool Changed = false; for (Init *CurElt : getValues()) { - Init *E; - - do { - E = CurElt; - CurElt = CurElt->resolveReferences(R, RV); - Changed |= E != CurElt; - } while (E != CurElt); + Init *E = CurElt->resolveReferences(R); + Changed |= E != CurElt; Resolved.push_back(E); } if (Changed) - return ListInit::get(Resolved, getType()); + return ListInit::get(Resolved, getElementType()); return const_cast<ListInit *>(this); } -Init *ListInit::resolveListElementReference(Record &R, const RecordVal *IRV, - unsigned Elt) const { - if (Elt >= size()) - return nullptr; // Out of range reference. - Init *E = getElement(Elt); - // If the element is set to some value, or if we are resolving a reference - // to a specific variable and that variable is explicitly unset, then - // replace the VarListElementInit with it. - if (IRV || !isa<UnsetInit>(E)) - return E; - return nullptr; +bool ListInit::isConcrete() const { + for (Init *Element : *this) { + if (!Element->isConcrete()) + return false; + } + return true; } std::string ListInit::getAsString() const { @@ -571,24 +664,6 @@ std::string ListInit::getAsString() const { return Result + "]"; } -Init *OpInit::resolveListElementReference(Record &R, const RecordVal *IRV, - unsigned Elt) const { - Init *Resolved = resolveReferences(R, IRV); - OpInit *OResolved = dyn_cast<OpInit>(Resolved); - if (OResolved) { - Resolved = OResolved->Fold(&R, nullptr); - } - - if (Resolved != this) { - TypedInit *Typed = cast<TypedInit>(Resolved); - if (Init *New = Typed->resolveListElementReference(R, IRV, Elt)) - return New; - return VarListElementInit::get(Typed, Elt); - } - - return nullptr; -} - Init *OpInit::getBit(unsigned Bit) const { if (getType() == BitRecTy::get()) return const_cast<OpInit*>(this); @@ -621,7 +696,7 @@ void UnOpInit::Profile(FoldingSetNodeID &ID) const { ProfileUnOpInit(ID, getOpcode(), getOperand(), getType()); } -Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const { +Init *UnOpInit::Fold(Record *CurRec, bool IsFinal) const { switch (getOpcode()) { case CAST: if (isa<StringRecTy>(getType())) { @@ -633,60 +708,42 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const { if (IntInit *LHSi = dyn_cast<IntInit>(LHS)) return StringInit::get(LHSi->getAsString()); - } else { + } else if (isa<RecordRecTy>(getType())) { if (StringInit *Name = dyn_cast<StringInit>(LHS)) { - // From TGParser::ParseIDValue - if (CurRec) { - if (const RecordVal *RV = CurRec->getValue(Name)) { - if (RV->getType() != getType()) - PrintFatalError("type mismatch in cast"); - return VarInit::get(Name, RV->getType()); - } - - Init *TemplateArgName = QualifyName(*CurRec, CurMultiClass, Name, - ":"); - - if (CurRec->isTemplateArg(TemplateArgName)) { - const RecordVal *RV = CurRec->getValue(TemplateArgName); - assert(RV && "Template arg doesn't exist??"); - - if (RV->getType() != getType()) - PrintFatalError("type mismatch in cast"); - - return VarInit::get(TemplateArgName, RV->getType()); - } - } - - if (CurMultiClass) { - Init *MCName = QualifyName(CurMultiClass->Rec, CurMultiClass, Name, - "::"); - - if (CurMultiClass->Rec.isTemplateArg(MCName)) { - const RecordVal *RV = CurMultiClass->Rec.getValue(MCName); - assert(RV && "Template arg doesn't exist??"); - - if (RV->getType() != getType()) - PrintFatalError("type mismatch in cast"); - - return VarInit::get(MCName, RV->getType()); + assert(CurRec && "NULL pointer"); + Record *D; + + // Self-references are allowed, but their resolution is delayed until + // the final resolve to ensure that we get the correct type for them. + if (Name == CurRec->getNameInit()) { + if (!IsFinal) + break; + D = CurRec; + } else { + D = CurRec->getRecords().getDef(Name->getValue()); + if (!D) { + if (IsFinal) + PrintFatalError(CurRec->getLoc(), + Twine("Undefined reference to record: '") + + Name->getValue() + "'\n"); + break; } } - assert(CurRec && "NULL pointer"); - if (Record *D = (CurRec->getRecords()).getDef(Name->getValue())) - return DefInit::get(D); - - PrintFatalError(CurRec->getLoc(), - "Undefined reference:'" + Name->getValue() + "'\n"); - } - if (isa<IntRecTy>(getType())) { - if (BitsInit *BI = dyn_cast<BitsInit>(LHS)) { - if (Init *NewInit = BI->convertInitializerTo(IntRecTy::get())) - return NewInit; - break; + DefInit *DI = DefInit::get(D); + if (!DI->getType()->typeIsA(getType())) { + PrintFatalError(CurRec->getLoc(), + Twine("Expected type '") + + getType()->getAsString() + "', got '" + + DI->getType()->getAsString() + "' in: " + + getAsString() + "\n"); } + return DI; } } + + if (Init *NewInit = LHS->convertInitializerTo(getType())) + return NewInit; break; case HEAD: @@ -701,10 +758,15 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const { assert(!LHSl->empty() && "Empty list in tail"); // Note the +1. We can't just pass the result of getValues() // directly. - return ListInit::get(LHSl->getValues().slice(1), LHSl->getType()); + return ListInit::get(LHSl->getValues().slice(1), LHSl->getElementType()); } break; + case SIZE: + if (ListInit *LHSl = dyn_cast<ListInit>(LHS)) + return IntInit::get(LHSl->size()); + break; + case EMPTY: if (ListInit *LHSl = dyn_cast<ListInit>(LHS)) return IntInit::get(LHSl->empty()); @@ -715,12 +777,13 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const { return const_cast<UnOpInit *>(this); } -Init *UnOpInit::resolveReferences(Record &R, const RecordVal *RV) const { - Init *lhs = LHS->resolveReferences(R, RV); +Init *UnOpInit::resolveReferences(Resolver &R) const { + Init *lhs = LHS->resolveReferences(R); - if (LHS != lhs) - return (UnOpInit::get(getOpcode(), lhs, getType()))->Fold(&R, nullptr); - return Fold(&R, nullptr); + if (LHS != lhs || (R.isFinal() && getOpcode() == CAST)) + return (UnOpInit::get(getOpcode(), lhs, getType())) + ->Fold(R.getCurrentRecord(), R.isFinal()); + return const_cast<UnOpInit *>(this); } std::string UnOpInit::getAsString() const { @@ -729,6 +792,7 @@ std::string UnOpInit::getAsString() const { case CAST: Result = "!cast<" + getType()->getAsString() + ">"; break; case HEAD: Result = "!head"; break; case TAIL: Result = "!tail"; break; + case SIZE: Result = "!size"; break; case EMPTY: Result = "!empty"; break; } return Result + "(" + LHS->getAsString() + ")"; @@ -770,7 +834,15 @@ static StringInit *ConcatStringInits(const StringInit *I0, return StringInit::get(Concat); } -Init *BinOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const { +Init *BinOpInit::getStrConcat(Init *I0, Init *I1) { + // Shortcut for the common case of concatenating two strings. + if (const StringInit *I0s = dyn_cast<StringInit>(I0)) + if (const StringInit *I1s = dyn_cast<StringInit>(I1)) + return ConcatStringInits(I0s, I1s); + return BinOpInit::get(BinOpInit::STRCONCAT, I0, I1, StringRecTy::get()); +} + +Init *BinOpInit::Fold(Record *CurRec) const { switch (getOpcode()) { case CONCAT: { DagInit *LHSs = dyn_cast<DagInit>(LHS); @@ -778,8 +850,13 @@ Init *BinOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const { if (LHSs && RHSs) { DefInit *LOp = dyn_cast<DefInit>(LHSs->getOperator()); DefInit *ROp = dyn_cast<DefInit>(RHSs->getOperator()); - if (!LOp || !ROp || LOp->getDef() != ROp->getDef()) - PrintFatalError("Concated Dag operators do not match!"); + if (!LOp || !ROp) + break; + if (LOp->getDef() != ROp->getDef()) { + PrintFatalError(Twine("Concatenated Dag operators do not match: '") + + LHSs->getAsString() + "' vs. '" + RHSs->getAsString() + + "'"); + } SmallVector<Init*, 8> Args; SmallVector<StringInit*, 8> ArgNames; for (unsigned i = 0, e = LHSs->getNumArgs(); i != e; ++i) { @@ -801,8 +878,7 @@ Init *BinOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const { SmallVector<Init *, 8> Args; Args.insert(Args.end(), LHSs->begin(), LHSs->end()); Args.insert(Args.end(), RHSs->begin(), RHSs->end()); - return ListInit::get( - Args, cast<ListRecTy>(LHSs->getType())->getElementType()); + return ListInit::get(Args, LHSs->getElementType()); } break; } @@ -813,23 +889,43 @@ Init *BinOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const { return ConcatStringInits(LHSs, RHSs); break; } - case EQ: { + case EQ: + case NE: + case LE: + case LT: + case GE: + case GT: { // try to fold eq comparison for 'bit' and 'int', otherwise fallback // to string objects. IntInit *L = - dyn_cast_or_null<IntInit>(LHS->convertInitializerTo(IntRecTy::get())); + dyn_cast_or_null<IntInit>(LHS->convertInitializerTo(IntRecTy::get())); IntInit *R = - dyn_cast_or_null<IntInit>(RHS->convertInitializerTo(IntRecTy::get())); + dyn_cast_or_null<IntInit>(RHS->convertInitializerTo(IntRecTy::get())); - if (L && R) - return IntInit::get(L->getValue() == R->getValue()); + if (L && R) { + bool Result; + switch (getOpcode()) { + case EQ: Result = L->getValue() == R->getValue(); break; + case NE: Result = L->getValue() != R->getValue(); break; + case LE: Result = L->getValue() <= R->getValue(); break; + case LT: Result = L->getValue() < R->getValue(); break; + case GE: Result = L->getValue() >= R->getValue(); break; + case GT: Result = L->getValue() > R->getValue(); break; + default: llvm_unreachable("unhandled comparison"); + } + return BitInit::get(Result); + } - StringInit *LHSs = dyn_cast<StringInit>(LHS); - StringInit *RHSs = dyn_cast<StringInit>(RHS); + if (getOpcode() == EQ || getOpcode() == NE) { + StringInit *LHSs = dyn_cast<StringInit>(LHS); + StringInit *RHSs = dyn_cast<StringInit>(RHS); - // Make sure we've resolved - if (LHSs && RHSs) - return IntInit::get(LHSs->getValue() == RHSs->getValue()); + // Make sure we've resolved + if (LHSs && RHSs) { + bool Equal = LHSs->getValue() == RHSs->getValue(); + return BitInit::get(getOpcode() == EQ ? Equal : !Equal); + } + } break; } @@ -863,13 +959,14 @@ Init *BinOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const { return const_cast<BinOpInit *>(this); } -Init *BinOpInit::resolveReferences(Record &R, const RecordVal *RV) const { - Init *lhs = LHS->resolveReferences(R, RV); - Init *rhs = RHS->resolveReferences(R, RV); +Init *BinOpInit::resolveReferences(Resolver &R) const { + Init *lhs = LHS->resolveReferences(R); + Init *rhs = RHS->resolveReferences(R); if (LHS != lhs || RHS != rhs) - return (BinOpInit::get(getOpcode(), lhs, rhs, getType()))->Fold(&R,nullptr); - return Fold(&R, nullptr); + return (BinOpInit::get(getOpcode(), lhs, rhs, getType())) + ->Fold(R.getCurrentRecord()); + return const_cast<BinOpInit *>(this); } std::string BinOpInit::getAsString() const { @@ -883,6 +980,11 @@ std::string BinOpInit::getAsString() const { case SRA: Result = "!sra"; break; case SRL: Result = "!srl"; break; case EQ: Result = "!eq"; break; + case NE: Result = "!ne"; break; + case LE: Result = "!le"; break; + case LT: Result = "!lt"; break; + case GE: Result = "!ge"; break; + case GT: Result = "!gt"; break; case LISTCONCAT: Result = "!listconcat"; break; case STRCONCAT: Result = "!strconcat"; break; } @@ -919,102 +1021,61 @@ void TernOpInit::Profile(FoldingSetNodeID &ID) const { ProfileTernOpInit(ID, getOpcode(), getLHS(), getMHS(), getRHS(), getType()); } -static Init *ForeachHelper(Init *LHS, Init *MHS, Init *RHS, RecTy *Type, - Record *CurRec, MultiClass *CurMultiClass); - -static Init *EvaluateOperation(OpInit *RHSo, Init *LHS, Init *Arg, - RecTy *Type, Record *CurRec, - MultiClass *CurMultiClass) { - // If this is a dag, recurse - if (auto *TArg = dyn_cast<TypedInit>(Arg)) - if (isa<DagRecTy>(TArg->getType())) - return ForeachHelper(LHS, Arg, RHSo, Type, CurRec, CurMultiClass); - - SmallVector<Init *, 8> NewOperands; - NewOperands.reserve(RHSo->getNumOperands()); - for (unsigned i = 0, e = RHSo->getNumOperands(); i < e; ++i) { - if (auto *RHSoo = dyn_cast<OpInit>(RHSo->getOperand(i))) { - if (Init *Result = EvaluateOperation(RHSoo, LHS, Arg, - Type, CurRec, CurMultiClass)) - NewOperands.push_back(Result); - else - NewOperands.push_back(Arg); - } else if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) { - NewOperands.push_back(Arg); - } else { - NewOperands.push_back(RHSo->getOperand(i)); - } - } - - // Now run the operator and use its result as the new leaf - const OpInit *NewOp = RHSo->clone(NewOperands); - Init *NewVal = NewOp->Fold(CurRec, CurMultiClass); - return (NewVal != NewOp) ? NewVal : nullptr; +static Init *ForeachApply(Init *LHS, Init *MHSe, Init *RHS, Record *CurRec) { + MapResolver R(CurRec); + R.set(LHS, MHSe); + return RHS->resolveReferences(R); } -static Init *ForeachHelper(Init *LHS, Init *MHS, Init *RHS, RecTy *Type, - Record *CurRec, MultiClass *CurMultiClass) { - OpInit *RHSo = dyn_cast<OpInit>(RHS); - - if (!RHSo) - PrintFatalError(CurRec->getLoc(), "!foreach requires an operator\n"); +static Init *ForeachDagApply(Init *LHS, DagInit *MHSd, Init *RHS, + Record *CurRec) { + bool Change = false; + Init *Val = ForeachApply(LHS, MHSd->getOperator(), RHS, CurRec); + if (Val != MHSd->getOperator()) + Change = true; - TypedInit *LHSt = dyn_cast<TypedInit>(LHS); + SmallVector<std::pair<Init *, StringInit *>, 8> NewArgs; + for (unsigned int i = 0; i < MHSd->getNumArgs(); ++i) { + Init *Arg = MHSd->getArg(i); + Init *NewArg; + StringInit *ArgName = MHSd->getArgName(i); - if (!LHSt) - PrintFatalError(CurRec->getLoc(), "!foreach requires typed variable\n"); - - DagInit *MHSd = dyn_cast<DagInit>(MHS); - if (MHSd && isa<DagRecTy>(Type)) { - Init *Val = MHSd->getOperator(); - if (Init *Result = EvaluateOperation(RHSo, LHS, Val, - Type, CurRec, CurMultiClass)) - Val = Result; - - SmallVector<std::pair<Init *, StringInit*>, 8> args; - for (unsigned int i = 0; i < MHSd->getNumArgs(); ++i) { - Init *Arg = MHSd->getArg(i); - StringInit *ArgName = MHSd->getArgName(i); + if (DagInit *Argd = dyn_cast<DagInit>(Arg)) + NewArg = ForeachDagApply(LHS, Argd, RHS, CurRec); + else + NewArg = ForeachApply(LHS, Arg, RHS, CurRec); - // Process args - if (Init *Result = EvaluateOperation(RHSo, LHS, Arg, Type, - CurRec, CurMultiClass)) - Arg = Result; + NewArgs.push_back(std::make_pair(NewArg, ArgName)); + if (Arg != NewArg) + Change = true; + } - // TODO: Process arg names - args.push_back(std::make_pair(Arg, ArgName)); - } + if (Change) + return DagInit::get(Val, nullptr, NewArgs); + return MHSd; +} - return DagInit::get(Val, nullptr, args); - } +// Applies RHS to all elements of MHS, using LHS as a temp variable. +static Init *ForeachHelper(Init *LHS, Init *MHS, Init *RHS, RecTy *Type, + Record *CurRec) { + if (DagInit *MHSd = dyn_cast<DagInit>(MHS)) + return ForeachDagApply(LHS, MHSd, RHS, CurRec); - ListInit *MHSl = dyn_cast<ListInit>(MHS); - if (MHSl && isa<ListRecTy>(Type)) { - SmallVector<Init *, 8> NewOperands; + if (ListInit *MHSl = dyn_cast<ListInit>(MHS)) { SmallVector<Init *, 8> NewList(MHSl->begin(), MHSl->end()); for (Init *&Item : NewList) { - NewOperands.clear(); - for(unsigned i = 0; i < RHSo->getNumOperands(); ++i) { - // First, replace the foreach variable with the list item - if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) - NewOperands.push_back(Item); - else - NewOperands.push_back(RHSo->getOperand(i)); - } - - // Now run the operator and use its result as the new list item - const OpInit *NewOp = RHSo->clone(NewOperands); - Init *NewItem = NewOp->Fold(CurRec, CurMultiClass); - if (NewItem != NewOp) + Init *NewItem = ForeachApply(LHS, Item, RHS, CurRec); + if (NewItem != Item) Item = NewItem; } - return ListInit::get(NewList, MHSl->getType()); + return ListInit::get(NewList, cast<ListRecTy>(Type)->getElementType()); } + return nullptr; } -Init *TernOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const { +Init *TernOpInit::Fold(Record *CurRec) const { switch (getOpcode()) { case SUBST: { DefInit *LHSd = dyn_cast<DefInit>(LHS); @@ -1060,154 +1121,244 @@ Init *TernOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const { } case FOREACH: { - if (Init *Result = ForeachHelper(LHS, MHS, RHS, getType(), - CurRec, CurMultiClass)) + if (Init *Result = ForeachHelper(LHS, MHS, RHS, getType(), CurRec)) return Result; break; } case IF: { - IntInit *LHSi = dyn_cast<IntInit>(LHS); - if (Init *I = LHS->convertInitializerTo(IntRecTy::get())) - LHSi = dyn_cast<IntInit>(I); - if (LHSi) { + if (IntInit *LHSi = dyn_cast_or_null<IntInit>( + LHS->convertInitializerTo(IntRecTy::get()))) { if (LHSi->getValue()) return MHS; return RHS; } break; } + + case DAG: { + ListInit *MHSl = dyn_cast<ListInit>(MHS); + ListInit *RHSl = dyn_cast<ListInit>(RHS); + bool MHSok = MHSl || isa<UnsetInit>(MHS); + bool RHSok = RHSl || isa<UnsetInit>(RHS); + + if (isa<UnsetInit>(MHS) && isa<UnsetInit>(RHS)) + break; // Typically prevented by the parser, but might happen with template args + + if (MHSok && RHSok && (!MHSl || !RHSl || MHSl->size() == RHSl->size())) { + SmallVector<std::pair<Init *, StringInit *>, 8> Children; + unsigned Size = MHSl ? MHSl->size() : RHSl->size(); + for (unsigned i = 0; i != Size; ++i) { + Init *Node = MHSl ? MHSl->getElement(i) : UnsetInit::get(); + Init *Name = RHSl ? RHSl->getElement(i) : UnsetInit::get(); + if (!isa<StringInit>(Name) && !isa<UnsetInit>(Name)) + return const_cast<TernOpInit *>(this); + Children.emplace_back(Node, dyn_cast<StringInit>(Name)); + } + return DagInit::get(LHS, nullptr, Children); + } + break; + } } return const_cast<TernOpInit *>(this); } -Init *TernOpInit::resolveReferences(Record &R, - const RecordVal *RV) const { - Init *lhs = LHS->resolveReferences(R, RV); +Init *TernOpInit::resolveReferences(Resolver &R) const { + Init *lhs = LHS->resolveReferences(R); if (getOpcode() == IF && lhs != LHS) { - IntInit *Value = dyn_cast<IntInit>(lhs); - if (Init *I = lhs->convertInitializerTo(IntRecTy::get())) - Value = dyn_cast<IntInit>(I); - if (Value) { + if (IntInit *Value = dyn_cast_or_null<IntInit>( + lhs->convertInitializerTo(IntRecTy::get()))) { // Short-circuit - if (Value->getValue()) { - Init *mhs = MHS->resolveReferences(R, RV); - return (TernOpInit::get(getOpcode(), lhs, mhs, - RHS, getType()))->Fold(&R, nullptr); - } - Init *rhs = RHS->resolveReferences(R, RV); - return (TernOpInit::get(getOpcode(), lhs, MHS, - rhs, getType()))->Fold(&R, nullptr); + if (Value->getValue()) + return MHS->resolveReferences(R); + return RHS->resolveReferences(R); } } - Init *mhs = MHS->resolveReferences(R, RV); - Init *rhs = RHS->resolveReferences(R, RV); + Init *mhs = MHS->resolveReferences(R); + Init *rhs; + + if (getOpcode() == FOREACH) { + ShadowResolver SR(R); + SR.addShadow(lhs); + rhs = RHS->resolveReferences(SR); + } else { + rhs = RHS->resolveReferences(R); + } if (LHS != lhs || MHS != mhs || RHS != rhs) - return (TernOpInit::get(getOpcode(), lhs, mhs, rhs, - getType()))->Fold(&R, nullptr); - return Fold(&R, nullptr); + return (TernOpInit::get(getOpcode(), lhs, mhs, rhs, getType())) + ->Fold(R.getCurrentRecord()); + return const_cast<TernOpInit *>(this); } std::string TernOpInit::getAsString() const { std::string Result; + bool UnquotedLHS = false; switch (getOpcode()) { case SUBST: Result = "!subst"; break; - case FOREACH: Result = "!foreach"; break; + case FOREACH: Result = "!foreach"; UnquotedLHS = true; break; case IF: Result = "!if"; break; + case DAG: Result = "!dag"; break; } - return Result + "(" + LHS->getAsString() + ", " + MHS->getAsString() + ", " + - RHS->getAsString() + ")"; + return (Result + "(" + + (UnquotedLHS ? LHS->getAsUnquotedString() : LHS->getAsString()) + + ", " + MHS->getAsString() + ", " + RHS->getAsString() + ")"); +} + +static void ProfileFoldOpInit(FoldingSetNodeID &ID, Init *A, Init *B, + Init *Start, Init *List, Init *Expr, + RecTy *Type) { + ID.AddPointer(Start); + ID.AddPointer(List); + ID.AddPointer(A); + ID.AddPointer(B); + ID.AddPointer(Expr); + ID.AddPointer(Type); } -RecTy *TypedInit::getFieldType(StringInit *FieldName) const { - if (RecordRecTy *RecordType = dyn_cast<RecordRecTy>(getType())) - if (RecordVal *Field = RecordType->getRecord()->getValue(FieldName)) - return Field->getType(); - return nullptr; -} +FoldOpInit *FoldOpInit::get(Init *Start, Init *List, Init *A, Init *B, + Init *Expr, RecTy *Type) { + static FoldingSet<FoldOpInit> ThePool; -Init * -TypedInit::convertInitializerTo(RecTy *Ty) const { - if (isa<IntRecTy>(Ty)) { - if (getType()->typeIsConvertibleTo(Ty)) - return const_cast<TypedInit *>(this); - return nullptr; - } + FoldingSetNodeID ID; + ProfileFoldOpInit(ID, Start, List, A, B, Expr, Type); - if (isa<StringRecTy>(Ty)) { - if (isa<StringRecTy>(getType())) - return const_cast<TypedInit *>(this); - return nullptr; - } + void *IP = nullptr; + if (FoldOpInit *I = ThePool.FindNodeOrInsertPos(ID, IP)) + return I; - if (isa<CodeRecTy>(Ty)) { - if (isa<CodeRecTy>(getType())) - return const_cast<TypedInit *>(this); - return nullptr; - } + FoldOpInit *I = new (Allocator) FoldOpInit(Start, List, A, B, Expr, Type); + ThePool.InsertNode(I, IP); + return I; +} - if (isa<BitRecTy>(Ty)) { - // Accept variable if it is already of bit type! - if (isa<BitRecTy>(getType())) - return const_cast<TypedInit *>(this); - if (auto *BitsTy = dyn_cast<BitsRecTy>(getType())) { - // Accept only bits<1> expression. - if (BitsTy->getNumBits() == 1) - return const_cast<TypedInit *>(this); - return nullptr; - } - // Ternary !if can be converted to bit, but only if both sides are - // convertible to a bit. - if (const auto *TOI = dyn_cast<TernOpInit>(this)) { - if (TOI->getOpcode() == TernOpInit::TernaryOp::IF && - TOI->getMHS()->convertInitializerTo(BitRecTy::get()) && - TOI->getRHS()->convertInitializerTo(BitRecTy::get())) - return const_cast<TypedInit *>(this); - return nullptr; +void FoldOpInit::Profile(FoldingSetNodeID &ID) const { + ProfileFoldOpInit(ID, Start, List, A, B, Expr, getType()); +} + +Init *FoldOpInit::Fold(Record *CurRec) const { + if (ListInit *LI = dyn_cast<ListInit>(List)) { + Init *Accum = Start; + for (Init *Elt : *LI) { + MapResolver R(CurRec); + R.set(A, Accum); + R.set(B, Elt); + Accum = Expr->resolveReferences(R); } - return nullptr; + return Accum; } + return const_cast<FoldOpInit *>(this); +} - if (auto *BRT = dyn_cast<BitsRecTy>(Ty)) { - if (BRT->getNumBits() == 1 && isa<BitRecTy>(getType())) - return BitsInit::get(const_cast<TypedInit *>(this)); +Init *FoldOpInit::resolveReferences(Resolver &R) const { + Init *NewStart = Start->resolveReferences(R); + Init *NewList = List->resolveReferences(R); + ShadowResolver SR(R); + SR.addShadow(A); + SR.addShadow(B); + Init *NewExpr = Expr->resolveReferences(SR); - if (getType()->typeIsConvertibleTo(BRT)) { - SmallVector<Init *, 16> NewBits(BRT->getNumBits()); + if (Start == NewStart && List == NewList && Expr == NewExpr) + return const_cast<FoldOpInit *>(this); - for (unsigned i = 0; i != BRT->getNumBits(); ++i) - NewBits[i] = VarBitInit::get(const_cast<TypedInit *>(this), i); - return BitsInit::get(NewBits); - } + return get(NewStart, NewList, A, B, NewExpr, getType()) + ->Fold(R.getCurrentRecord()); +} - return nullptr; - } +Init *FoldOpInit::getBit(unsigned Bit) const { + return VarBitInit::get(const_cast<FoldOpInit *>(this), Bit); +} - if (auto *DLRT = dyn_cast<ListRecTy>(Ty)) { - if (auto *SLRT = dyn_cast<ListRecTy>(getType())) - if (SLRT->getElementType()->typeIsConvertibleTo(DLRT->getElementType())) - return const_cast<TypedInit *>(this); - return nullptr; - } +std::string FoldOpInit::getAsString() const { + return (Twine("!foldl(") + Start->getAsString() + ", " + List->getAsString() + + ", " + A->getAsUnquotedString() + ", " + B->getAsUnquotedString() + + ", " + Expr->getAsString() + ")") + .str(); +} - if (auto *DRT = dyn_cast<DagRecTy>(Ty)) { - if (getType()->typeIsConvertibleTo(DRT)) - return const_cast<TypedInit *>(this); - return nullptr; +static void ProfileIsAOpInit(FoldingSetNodeID &ID, RecTy *CheckType, + Init *Expr) { + ID.AddPointer(CheckType); + ID.AddPointer(Expr); +} + +IsAOpInit *IsAOpInit::get(RecTy *CheckType, Init *Expr) { + static FoldingSet<IsAOpInit> ThePool; + + FoldingSetNodeID ID; + ProfileIsAOpInit(ID, CheckType, Expr); + + void *IP = nullptr; + if (IsAOpInit *I = ThePool.FindNodeOrInsertPos(ID, IP)) + return I; + + IsAOpInit *I = new (Allocator) IsAOpInit(CheckType, Expr); + ThePool.InsertNode(I, IP); + return I; +} + +void IsAOpInit::Profile(FoldingSetNodeID &ID) const { + ProfileIsAOpInit(ID, CheckType, Expr); +} + +Init *IsAOpInit::Fold() const { + if (TypedInit *TI = dyn_cast<TypedInit>(Expr)) { + // Is the expression type known to be (a subclass of) the desired type? + if (TI->getType()->typeIsConvertibleTo(CheckType)) + return IntInit::get(1); + + if (isa<RecordRecTy>(CheckType)) { + // If the target type is not a subclass of the expression type, or if + // the expression has fully resolved to a record, we know that it can't + // be of the required type. + if (!CheckType->typeIsConvertibleTo(TI->getType()) || isa<DefInit>(Expr)) + return IntInit::get(0); + } else { + // We treat non-record types as not castable. + return IntInit::get(0); + } } + return const_cast<IsAOpInit *>(this); +} - if (auto *SRRT = dyn_cast<RecordRecTy>(Ty)) { - // Ensure that this is compatible with Rec. - if (RecordRecTy *DRRT = dyn_cast<RecordRecTy>(getType())) - if (DRRT->getRecord()->isSubClassOf(SRRT->getRecord()) || - DRRT->getRecord() == SRRT->getRecord()) - return const_cast<TypedInit *>(this); - return nullptr; +Init *IsAOpInit::resolveReferences(Resolver &R) const { + Init *NewExpr = Expr->resolveReferences(R); + if (Expr != NewExpr) + return get(CheckType, NewExpr)->Fold(); + return const_cast<IsAOpInit *>(this); +} + +Init *IsAOpInit::getBit(unsigned Bit) const { + return VarBitInit::get(const_cast<IsAOpInit *>(this), Bit); +} + +std::string IsAOpInit::getAsString() const { + return (Twine("!isa<") + CheckType->getAsString() + ">(" + + Expr->getAsString() + ")") + .str(); +} + +RecTy *TypedInit::getFieldType(StringInit *FieldName) const { + if (RecordRecTy *RecordType = dyn_cast<RecordRecTy>(getType())) { + for (Record *Rec : RecordType->getClasses()) { + if (RecordVal *Field = Rec->getValue(FieldName)) + return Field->getType(); + } } + return nullptr; +} + +Init * +TypedInit::convertInitializerTo(RecTy *Ty) const { + if (getType() == Ty || getType()->typeIsA(Ty)) + return const_cast<TypedInit *>(this); + + if (isa<BitRecTy>(getType()) && isa<BitsRecTy>(Ty) && + cast<BitsRecTy>(Ty)->getNumBits() == 1) + return BitsInit::get({const_cast<TypedInit *>(this)}); return nullptr; } @@ -1228,6 +1379,24 @@ Init *TypedInit::convertInitializerBitRange(ArrayRef<unsigned> Bits) const { return BitsInit::get(NewBits); } +Init *TypedInit::getCastTo(RecTy *Ty) const { + // Handle the common case quickly + if (getType() == Ty || getType()->typeIsA(Ty)) + return const_cast<TypedInit *>(this); + + if (Init *Converted = convertInitializerTo(Ty)) { + assert(!isa<TypedInit>(Converted) || + cast<TypedInit>(Converted)->getType()->typeIsA(Ty)); + return Converted; + } + + if (!getType()->typeIsConvertibleTo(Ty)) + return nullptr; + + return UnOpInit::get(UnOpInit::CAST, const_cast<TypedInit *>(this), Ty) + ->Fold(nullptr); +} + Init *TypedInit::convertInitListSlice(ArrayRef<unsigned> Elements) const { ListRecTy *T = dyn_cast<ListRecTy>(getType()); if (!T) return nullptr; // Cannot subscript a non-list variable. @@ -1240,7 +1409,7 @@ Init *TypedInit::convertInitListSlice(ArrayRef<unsigned> Elements) const { for (unsigned Element : Elements) ListInits.push_back(VarListElementInit::get(const_cast<TypedInit *>(this), Element)); - return ListInit::get(ListInits, T); + return ListInit::get(ListInits, T->getElementType()); } @@ -1272,55 +1441,9 @@ Init *VarInit::getBit(unsigned Bit) const { return VarBitInit::get(const_cast<VarInit*>(this), Bit); } -Init *VarInit::resolveListElementReference(Record &R, - const RecordVal *IRV, - unsigned Elt) const { - if (R.isTemplateArg(getNameInit())) return nullptr; - if (IRV && IRV->getNameInit() != getNameInit()) return nullptr; - - RecordVal *RV = R.getValue(getNameInit()); - assert(RV && "Reference to a non-existent variable?"); - ListInit *LI = dyn_cast<ListInit>(RV->getValue()); - if (!LI) - return VarListElementInit::get(cast<TypedInit>(RV->getValue()), Elt); - - if (Elt >= LI->size()) - return nullptr; // Out of range reference. - Init *E = LI->getElement(Elt); - // If the element is set to some value, or if we are resolving a reference - // to a specific variable and that variable is explicitly unset, then - // replace the VarListElementInit with it. - if (IRV || !isa<UnsetInit>(E)) - return E; - return nullptr; -} - -RecTy *VarInit::getFieldType(StringInit *FieldName) const { - if (RecordRecTy *RTy = dyn_cast<RecordRecTy>(getType())) - if (const RecordVal *RV = RTy->getRecord()->getValue(FieldName)) - return RV->getType(); - return nullptr; -} - -Init *VarInit::getFieldInit(Record &R, const RecordVal *RV, - StringInit *FieldName) const { - if (isa<RecordRecTy>(getType())) - if (const RecordVal *Val = R.getValue(VarName)) { - if (RV != Val && (RV || isa<UnsetInit>(Val->getValue()))) - return nullptr; - Init *TheInit = Val->getValue(); - assert(TheInit != this && "Infinite loop detected!"); - if (Init *I = TheInit->getFieldInit(R, RV, FieldName)) - return I; - return nullptr; - } - return nullptr; -} - -Init *VarInit::resolveReferences(Record &R, const RecordVal *RV) const { - if (RecordVal *Val = R.getValue(VarName)) - if (RV == Val || (!RV && !isa<UnsetInit>(Val->getValue()))) - return Val->getValue(); +Init *VarInit::resolveReferences(Resolver &R) const { + if (Init *Val = R.resolve(VarName)) + return Val; return const_cast<VarInit *>(this); } @@ -1336,19 +1459,12 @@ VarBitInit *VarBitInit::get(TypedInit *T, unsigned B) { return I; } -Init *VarBitInit::convertInitializerTo(RecTy *Ty) const { - if (isa<BitRecTy>(Ty)) - return const_cast<VarBitInit *>(this); - - return nullptr; -} - std::string VarBitInit::getAsString() const { return TI->getAsString() + "{" + utostr(Bit) + "}"; } -Init *VarBitInit::resolveReferences(Record &R, const RecordVal *RV) const { - Init *I = TI->resolveReferences(R, RV); +Init *VarBitInit::resolveReferences(Resolver &R) const { + Init *I = TI->resolveReferences(R); if (TI != I) return I->getBit(getBitNum()); @@ -1371,11 +1487,16 @@ std::string VarListElementInit::getAsString() const { return TI->getAsString() + "[" + utostr(Element) + "]"; } -Init * -VarListElementInit::resolveReferences(Record &R, const RecordVal *RV) const { - if (Init *I = getVariable()->resolveListElementReference(R, RV, - getElementNum())) - return I; +Init *VarListElementInit::resolveReferences(Resolver &R) const { + Init *NewTI = TI->resolveReferences(R); + if (ListInit *List = dyn_cast<ListInit>(NewTI)) { + // Leave out-of-bounds array references as-is. This can happen without + // being an error, e.g. in the untaken "branch" of an !if expression. + if (getElementNum() < List->size()) + return List->getElement(getElementNum()); + } + if (NewTI != TI && isa<TypedInit>(NewTI)) + return VarListElementInit::get(cast<TypedInit>(NewTI), getElementNum()); return const_cast<VarListElementInit *>(this); } @@ -1385,20 +1506,8 @@ Init *VarListElementInit::getBit(unsigned Bit) const { return VarBitInit::get(const_cast<VarListElementInit*>(this), Bit); } -Init *VarListElementInit:: resolveListElementReference(Record &R, - const RecordVal *RV, - unsigned Elt) const { - if (Init *Result = TI->resolveListElementReference(R, RV, Element)) { - if (TypedInit *TInit = dyn_cast<TypedInit>(Result)) { - if (Init *Result2 = TInit->resolveListElementReference(R, RV, Elt)) - return Result2; - return VarListElementInit::get(TInit, Elt); - } - return Result; - } - - return nullptr; -} +DefInit::DefInit(Record *D) + : TypedInit(IK_DefInit, D->getType()), Def(D) {} DefInit *DefInit::get(Record *R) { return R->getDefInit(); @@ -1406,7 +1515,7 @@ DefInit *DefInit::get(Record *R) { Init *DefInit::convertInitializerTo(RecTy *Ty) const { if (auto *RRT = dyn_cast<RecordRecTy>(Ty)) - if (getDef()->isSubClassOf(RRT->getRecord())) + if (getType()->typeIsConvertibleTo(RRT)) return const_cast<DefInit *>(this); return nullptr; } @@ -1417,15 +1526,134 @@ RecTy *DefInit::getFieldType(StringInit *FieldName) const { return nullptr; } -Init *DefInit::getFieldInit(Record &R, const RecordVal *RV, - StringInit *FieldName) const { - return Def->getValue(FieldName)->getValue(); -} - std::string DefInit::getAsString() const { return Def->getName(); } +static void ProfileVarDefInit(FoldingSetNodeID &ID, + Record *Class, + ArrayRef<Init *> Args) { + ID.AddInteger(Args.size()); + ID.AddPointer(Class); + + for (Init *I : Args) + ID.AddPointer(I); +} + +VarDefInit *VarDefInit::get(Record *Class, ArrayRef<Init *> Args) { + static FoldingSet<VarDefInit> ThePool; + + FoldingSetNodeID ID; + ProfileVarDefInit(ID, Class, Args); + + void *IP = nullptr; + if (VarDefInit *I = ThePool.FindNodeOrInsertPos(ID, IP)) + return I; + + void *Mem = Allocator.Allocate(totalSizeToAlloc<Init *>(Args.size()), + alignof(VarDefInit)); + VarDefInit *I = new(Mem) VarDefInit(Class, Args.size()); + std::uninitialized_copy(Args.begin(), Args.end(), + I->getTrailingObjects<Init *>()); + ThePool.InsertNode(I, IP); + return I; +} + +void VarDefInit::Profile(FoldingSetNodeID &ID) const { + ProfileVarDefInit(ID, Class, args()); +} + +DefInit *VarDefInit::instantiate() { + if (!Def) { + RecordKeeper &Records = Class->getRecords(); + auto NewRecOwner = make_unique<Record>(Records.getNewAnonymousName(), + Class->getLoc(), Records, + /*IsAnonymous=*/true); + Record *NewRec = NewRecOwner.get(); + + // Copy values from class to instance + for (const RecordVal &Val : Class->getValues()) + NewRec->addValue(Val); + + // Substitute and resolve template arguments + ArrayRef<Init *> TArgs = Class->getTemplateArgs(); + MapResolver R(NewRec); + + for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { + if (i < args_size()) + R.set(TArgs[i], getArg(i)); + else + R.set(TArgs[i], NewRec->getValue(TArgs[i])->getValue()); + + NewRec->removeValue(TArgs[i]); + } + + NewRec->resolveReferences(R); + + // Add superclasses. + ArrayRef<std::pair<Record *, SMRange>> SCs = Class->getSuperClasses(); + for (const auto &SCPair : SCs) + NewRec->addSuperClass(SCPair.first, SCPair.second); + + NewRec->addSuperClass(Class, + SMRange(Class->getLoc().back(), + Class->getLoc().back())); + + // Resolve internal references and store in record keeper + NewRec->resolveReferences(); + Records.addDef(std::move(NewRecOwner)); + + Def = DefInit::get(NewRec); + } + + return Def; +} + +Init *VarDefInit::resolveReferences(Resolver &R) const { + TrackUnresolvedResolver UR(&R); + bool Changed = false; + SmallVector<Init *, 8> NewArgs; + NewArgs.reserve(args_size()); + + for (Init *Arg : args()) { + Init *NewArg = Arg->resolveReferences(UR); + NewArgs.push_back(NewArg); + Changed |= NewArg != Arg; + } + + if (Changed) { + auto New = VarDefInit::get(Class, NewArgs); + if (!UR.foundUnresolved()) + return New->instantiate(); + return New; + } + return const_cast<VarDefInit *>(this); +} + +Init *VarDefInit::Fold() const { + if (Def) + return Def; + + TrackUnresolvedResolver R; + for (Init *Arg : args()) + Arg->resolveReferences(R); + + if (!R.foundUnresolved()) + return const_cast<VarDefInit *>(this)->instantiate(); + return const_cast<VarDefInit *>(this); +} + +std::string VarDefInit::getAsString() const { + std::string Result = Class->getNameInitAsString() + "<"; + const char *sep = ""; + for (Init *Arg : args()) { + Result += sep; + sep = ", "; + Result += Arg->getAsString(); + } + return Result + ">"; +} + FieldInit *FieldInit::get(Init *R, StringInit *FN) { using Key = std::pair<Init *, StringInit *>; static DenseMap<Key, FieldInit*> ThePool; @@ -1443,32 +1671,25 @@ Init *FieldInit::getBit(unsigned Bit) const { return VarBitInit::get(const_cast<FieldInit*>(this), Bit); } -Init *FieldInit::resolveListElementReference(Record &R, const RecordVal *RV, - unsigned Elt) const { - if (Init *ListVal = Rec->getFieldInit(R, RV, FieldName)) - if (ListInit *LI = dyn_cast<ListInit>(ListVal)) { - if (Elt >= LI->size()) return nullptr; - Init *E = LI->getElement(Elt); - - // If the element is set to some value, or if we are resolving a - // reference to a specific variable and that variable is explicitly - // unset, then replace the VarListElementInit with it. - if (RV || !isa<UnsetInit>(E)) - return E; - } - return nullptr; +Init *FieldInit::resolveReferences(Resolver &R) const { + Init *NewRec = Rec->resolveReferences(R); + if (NewRec != Rec) + return FieldInit::get(NewRec, FieldName)->Fold(R.getCurrentRecord()); + return const_cast<FieldInit *>(this); } -Init *FieldInit::resolveReferences(Record &R, const RecordVal *RV) const { - Init *NewRec = RV ? Rec->resolveReferences(R, RV) : Rec; - - if (Init *BitsVal = NewRec->getFieldInit(R, RV, FieldName)) { - Init *BVR = BitsVal->resolveReferences(R, RV); - return BVR->isComplete() ? BVR : const_cast<FieldInit *>(this); +Init *FieldInit::Fold(Record *CurRec) const { + if (DefInit *DI = dyn_cast<DefInit>(Rec)) { + Record *Def = DI->getDef(); + if (Def == CurRec) + PrintFatalError(CurRec->getLoc(), + Twine("Attempting to access field '") + + FieldName->getAsUnquotedString() + "' of '" + + Rec->getAsString() + "' is a forbidden self-reference"); + Init *FieldVal = Def->getValue(FieldName)->getValue(); + if (FieldVal->isComplete()) + return FieldVal; } - - if (NewRec != Rec) - return FieldInit::get(NewRec, FieldName); return const_cast<FieldInit *>(this); } @@ -1528,30 +1749,33 @@ void DagInit::Profile(FoldingSetNodeID &ID) const { ProfileDagInit(ID, Val, ValName, makeArrayRef(getTrailingObjects<Init *>(), NumArgs), makeArrayRef(getTrailingObjects<StringInit *>(), NumArgNames)); } -Init *DagInit::convertInitializerTo(RecTy *Ty) const { - if (isa<DagRecTy>(Ty)) - return const_cast<DagInit *>(this); - - return nullptr; -} - -Init *DagInit::resolveReferences(Record &R, const RecordVal *RV) const { +Init *DagInit::resolveReferences(Resolver &R) const { SmallVector<Init*, 8> NewArgs; NewArgs.reserve(arg_size()); bool ArgsChanged = false; for (const Init *Arg : getArgs()) { - Init *NewArg = Arg->resolveReferences(R, RV); + Init *NewArg = Arg->resolveReferences(R); NewArgs.push_back(NewArg); ArgsChanged |= NewArg != Arg; } - Init *Op = Val->resolveReferences(R, RV); + Init *Op = Val->resolveReferences(R); if (Op != Val || ArgsChanged) return DagInit::get(Op, ValName, NewArgs, getArgNames()); return const_cast<DagInit *>(this); } +bool DagInit::isConcrete() const { + if (!Val->isConcrete()) + return false; + for (const Init *Elt : getArgs()) { + if (!Elt->isConcrete()) + return false; + } + return true; +} + std::string DagInit::getAsString() const { std::string Result = "(" + Val->getAsString(); if (ValName) @@ -1573,7 +1797,7 @@ std::string DagInit::getAsString() const { RecordVal::RecordVal(Init *N, RecTy *T, bool P) : Name(N), TyAndPrefix(T, P) { - Value = UnsetInit::get()->convertInitializerTo(T); + setValue(UnsetInit::get()); assert(Value && "Cannot create unset value for current type!"); } @@ -1581,6 +1805,28 @@ StringRef RecordVal::getName() const { return cast<StringInit>(getNameInit())->getValue(); } +bool RecordVal::setValue(Init *V) { + if (V) { + Value = V->getCastTo(getType()); + if (Value) { + assert(!isa<TypedInit>(Value) || + cast<TypedInit>(Value)->getType()->typeIsA(getType())); + if (BitsRecTy *BTy = dyn_cast<BitsRecTy>(getType())) { + if (!isa<BitsInit>(Value)) { + SmallVector<Init *, 64> Bits; + Bits.reserve(BTy->getNumBits()); + for (unsigned i = 0, e = BTy->getNumBits(); i < e; ++i) + Bits.push_back(Value->getBit(i)); + Value = BitsInit::get(Bits); + } + } + } + return Value == nullptr; + } + Value = nullptr; + return false; +} + #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void RecordVal::dump() const { errs() << *this; } #endif @@ -1597,31 +1843,26 @@ void RecordVal::print(raw_ostream &OS, bool PrintSem) const { unsigned Record::LastID = 0; -void Record::init() { - checkName(); - - // Every record potentially has a def at the top. This value is - // replaced with the top-level def name at instantiation time. - addValue(RecordVal(StringInit::get("NAME"), StringRecTy::get(), false)); -} - void Record::checkName() { // Ensure the record name has string type. const TypedInit *TypedName = cast<const TypedInit>(Name); if (!isa<StringRecTy>(TypedName->getType())) - PrintFatalError(getLoc(), "Record name is not a string!"); + PrintFatalError(getLoc(), Twine("Record name '") + Name->getAsString() + + "' is not a string!"); +} + +RecordRecTy *Record::getType() { + SmallVector<Record *, 4> DirectSCs; + getDirectSuperClasses(DirectSCs); + return RecordRecTy::get(DirectSCs); } DefInit *Record::getDefInit() { if (!TheInit) - TheInit = new(Allocator) DefInit(this, new(Allocator) RecordRecTy(this)); + TheInit = new(Allocator) DefInit(this); return TheInit; } -StringRef Record::getName() const { - return cast<StringInit>(Name)->getValue(); -} - void Record::setName(Init *NewName) { Name = NewName; checkName(); @@ -1638,28 +1879,57 @@ void Record::setName(Init *NewName) { // this. See TGParser::ParseDef and TGParser::ParseDefm. } -void Record::resolveReferencesTo(const RecordVal *RV) { +void Record::getDirectSuperClasses(SmallVectorImpl<Record *> &Classes) const { + ArrayRef<std::pair<Record *, SMRange>> SCs = getSuperClasses(); + while (!SCs.empty()) { + // Superclasses are in reverse preorder, so 'back' is a direct superclass, + // and its transitive superclasses are directly preceding it. + Record *SC = SCs.back().first; + SCs = SCs.drop_back(1 + SC->getSuperClasses().size()); + Classes.push_back(SC); + } +} + +void Record::resolveReferences(Resolver &R, const RecordVal *SkipVal) { for (RecordVal &Value : Values) { - if (RV == &Value) // Skip resolve the same field as the given one + if (SkipVal == &Value) // Skip resolve the same field as the given one continue; - if (Init *V = Value.getValue()) - if (Value.setValue(V->resolveReferences(*this, RV))) - PrintFatalError(getLoc(), "Invalid value is found when setting '" + - Value.getNameInitAsString() + - "' after resolving references" + - (RV ? " against '" + RV->getNameInitAsString() + - "' of (" + RV->getValue()->getAsUnquotedString() + - ")" - : "") + "\n"); + if (Init *V = Value.getValue()) { + Init *VR = V->resolveReferences(R); + if (Value.setValue(VR)) { + std::string Type; + if (TypedInit *VRT = dyn_cast<TypedInit>(VR)) + Type = + (Twine("of type '") + VRT->getType()->getAsString() + "' ").str(); + PrintFatalError(getLoc(), Twine("Invalid value ") + Type + + "is found when setting '" + + Value.getNameInitAsString() + + "' of type '" + + Value.getType()->getAsString() + + "' after resolving references: " + + VR->getAsUnquotedString() + "\n"); + } + } } Init *OldName = getNameInit(); - Init *NewName = Name->resolveReferences(*this, RV); + Init *NewName = Name->resolveReferences(R); if (NewName != OldName) { // Re-register with RecordKeeper. setName(NewName); } } +void Record::resolveReferences() { + RecordResolver R(*this); + R.setFinal(true); + resolveReferences(R); +} + +void Record::resolveReferencesTo(const RecordVal *RV) { + RecordValResolver R(*this, RV); + resolveReferences(R, RV); +} + #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void Record::dump() const { errs() << *this; } #endif @@ -1769,8 +2039,10 @@ int64_t Record::getValueAsInt(StringRef FieldName) const { if (IntInit *II = dyn_cast<IntInit>(R->getValue())) return II->getValue(); - PrintFatalError(getLoc(), "Record `" + getName() + "', field `" + - FieldName + "' does not have an int initializer!"); + PrintFatalError(getLoc(), Twine("Record `") + getName() + "', field `" + + FieldName + + "' does not have an int initializer: " + + R->getValue()->getAsString()); } std::vector<int64_t> @@ -1781,8 +2053,10 @@ Record::getValueAsListOfInts(StringRef FieldName) const { if (IntInit *II = dyn_cast<IntInit>(I)) Ints.push_back(II->getValue()); else - PrintFatalError(getLoc(), "Record `" + getName() + "', field `" + - FieldName + "' does not have a list of ints initializer!"); + PrintFatalError(getLoc(), + Twine("Record `") + getName() + "', field `" + FieldName + + "' does not have a list of ints initializer: " + + I->getAsString()); } return Ints; } @@ -1795,8 +2069,10 @@ Record::getValueAsListOfStrings(StringRef FieldName) const { if (StringInit *SI = dyn_cast<StringInit>(I)) Strings.push_back(SI->getValue()); else - PrintFatalError(getLoc(), "Record `" + getName() + "', field `" + - FieldName + "' does not have a list of strings initializer!"); + PrintFatalError(getLoc(), + Twine("Record `") + getName() + "', field `" + FieldName + + "' does not have a list of strings initializer: " + + I->getAsString()); } return Strings; } @@ -1855,15 +2131,6 @@ DagInit *Record::getValueAsDag(StringRef FieldName) const { } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -LLVM_DUMP_METHOD void MultiClass::dump() const { - errs() << "Record:\n"; - Rec.dump(); - - errs() << "Defs:\n"; - for (const auto &Proto : DefPrototypes) - Proto->dump(); -} - LLVM_DUMP_METHOD void RecordKeeper::dump() const { errs() << *this; } #endif @@ -1878,6 +2145,12 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const RecordKeeper &RK) { return OS; } +/// GetNewAnonymousName - Generate a unique anonymous name that can be used as +/// an identifier. +Init *RecordKeeper::getNewAnonymousName() { + return StringInit::get("anonymous_" + utostr(AnonCounter++)); +} + std::vector<Record *> RecordKeeper::getAllDerivedDefinitions(StringRef ClassName) const { Record *Class = getClass(ClassName); @@ -1892,25 +2165,70 @@ RecordKeeper::getAllDerivedDefinitions(StringRef ClassName) const { return Defs; } -static Init *GetStrConcat(Init *I0, Init *I1) { - // Shortcut for the common case of concatenating two strings. - if (const StringInit *I0s = dyn_cast<StringInit>(I0)) - if (const StringInit *I1s = dyn_cast<StringInit>(I1)) - return ConcatStringInits(I0s, I1s); - return BinOpInit::get(BinOpInit::STRCONCAT, I0, I1, StringRecTy::get()); +Init *MapResolver::resolve(Init *VarName) { + auto It = Map.find(VarName); + if (It == Map.end()) + return nullptr; + + Init *I = It->second.V; + + if (!It->second.Resolved && Map.size() > 1) { + // Resolve mutual references among the mapped variables, but prevent + // infinite recursion. + Map.erase(It); + I = I->resolveReferences(*this); + Map[VarName] = {I, true}; + } + + return I; +} + +Init *RecordResolver::resolve(Init *VarName) { + Init *Val = Cache.lookup(VarName); + if (Val) + return Val; + + for (Init *S : Stack) { + if (S == VarName) + return nullptr; // prevent infinite recursion + } + + if (RecordVal *RV = getCurrentRecord()->getValue(VarName)) { + if (!isa<UnsetInit>(RV->getValue())) { + Val = RV->getValue(); + Stack.push_back(VarName); + Val = Val->resolveReferences(*this); + Stack.pop_back(); + } + } + + Cache[VarName] = Val; + return Val; } -Init *llvm::QualifyName(Record &CurRec, MultiClass *CurMultiClass, - Init *Name, StringRef Scoper) { - Init *NewName = GetStrConcat(CurRec.getNameInit(), StringInit::get(Scoper)); - NewName = GetStrConcat(NewName, Name); - if (CurMultiClass && Scoper != "::") { - Init *Prefix = GetStrConcat(CurMultiClass->Rec.getNameInit(), - StringInit::get("::")); - NewName = GetStrConcat(Prefix, NewName); +Init *TrackUnresolvedResolver::resolve(Init *VarName) { + Init *I = nullptr; + + if (R) { + I = R->resolve(VarName); + if (I && !FoundUnresolved) { + // Do not recurse into the resolved initializer, as that would change + // the behavior of the resolver we're delegating, but do check to see + // if there are unresolved variables remaining. + TrackUnresolvedResolver Sub; + I->resolveReferences(Sub); + FoundUnresolved |= Sub.FoundUnresolved; + } } - if (BinOpInit *BinOp = dyn_cast<BinOpInit>(NewName)) - NewName = BinOp->Fold(&CurRec, CurMultiClass); - return NewName; + if (!I) + FoundUnresolved = true; + return I; +} + +Init *HasReferenceResolver::resolve(Init *VarName) +{ + if (VarName == VarNameToTrack) + Found = true; + return nullptr; } diff --git a/contrib/llvm/lib/TableGen/TGLexer.cpp b/contrib/llvm/lib/TableGen/TGLexer.cpp index 5d6f7c23e0b6..652be6e8dbbf 100644 --- a/contrib/llvm/lib/TableGen/TGLexer.cpp +++ b/contrib/llvm/lib/TableGen/TGLexer.cpp @@ -56,7 +56,7 @@ int TGLexer::getNextChar() { // a random nul in the file. Disambiguate that here. if (CurPtr-1 != CurBuf.end()) return 0; // Just whitespace. - + // If this is the end of an included file, pop the parent file off the // include stack. SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer); @@ -66,9 +66,9 @@ int TGLexer::getNextChar() { CurPtr = ParentIncludeLoc.getPointer(); return getNextChar(); } - + // Otherwise, return end of file. - --CurPtr; // Another call to lex will return EOF again. + --CurPtr; // Another call to lex will return EOF again. return EOF; } case '\n': @@ -80,7 +80,7 @@ int TGLexer::getNextChar() { *CurPtr != CurChar) ++CurPtr; // Eat the two char newline sequence. return '\n'; - } + } } int TGLexer::peekNextChar(int Index) { @@ -115,7 +115,7 @@ tgtok::TokKind TGLexer::LexToken() { case '=': return tgtok::equal; case '?': return tgtok::question; case '#': return tgtok::paste; - + case 0: case ' ': case '\t': @@ -154,7 +154,7 @@ tgtok::TokKind TGLexer::LexToken() { switch (NextNextChar) { default: break; - case '0': case '1': + case '0': case '1': if (NextChar == 'b') return LexNumber(); LLVM_FALLTHROUGH; @@ -184,24 +184,24 @@ tgtok::TokKind TGLexer::LexToken() { /// LexString - Lex "[^"]*" tgtok::TokKind TGLexer::LexString() { const char *StrStart = CurPtr; - + CurStrVal = ""; - + while (*CurPtr != '"') { // If we hit the end of the buffer, report an error. if (*CurPtr == 0 && CurPtr == CurBuf.end()) return ReturnError(StrStart, "End of file in string literal"); - + if (*CurPtr == '\n' || *CurPtr == '\r') return ReturnError(StrStart, "End of line in string literal"); - + if (*CurPtr != '\\') { CurStrVal += *CurPtr++; continue; } ++CurPtr; - + switch (*CurPtr) { case '\\': case '\'': case '"': // These turn into their literal character. @@ -215,7 +215,7 @@ tgtok::TokKind TGLexer::LexString() { CurStrVal += '\n'; ++CurPtr; break; - + case '\n': case '\r': return ReturnError(CurPtr, "escaped newlines not supported in tblgen"); @@ -229,7 +229,7 @@ tgtok::TokKind TGLexer::LexString() { return ReturnError(CurPtr, "invalid escape in string literal"); } } - + ++CurPtr; return tgtok::StrVal; } @@ -237,10 +237,10 @@ tgtok::TokKind TGLexer::LexString() { tgtok::TokKind TGLexer::LexVarName() { if (!isalpha(CurPtr[0]) && CurPtr[0] != '_') return ReturnError(TokStart, "Invalid variable name"); - + // Otherwise, we're ok, consume the rest of the characters. const char *VarNameStart = CurPtr++; - + while (isalpha(*CurPtr) || isdigit(*CurPtr) || *CurPtr == '_') ++CurPtr; @@ -276,6 +276,7 @@ tgtok::TokKind TGLexer::LexIdentifier() { .Case("def", tgtok::Def) .Case("foreach", tgtok::Foreach) .Case("defm", tgtok::Defm) + .Case("defset", tgtok::Defset) .Case("multiclass", tgtok::MultiClass) .Case("field", tgtok::Field) .Case("let", tgtok::Let) @@ -308,7 +309,7 @@ bool TGLexer::LexInclude() { PrintError(getLoc(), "Could not find include file '" + Filename + "'"); return true; } - + DependenciesMapTy::const_iterator Found = Dependencies.find(IncludedFile); if (Found != Dependencies.end()) { PrintError(getLoc(), @@ -347,7 +348,7 @@ void TGLexer::SkipBCPLComment() { bool TGLexer::SkipCComment() { ++CurPtr; // skip the star. unsigned CommentDepth = 1; - + while (true) { int CurChar = getNextChar(); switch (CurChar) { @@ -357,7 +358,7 @@ bool TGLexer::SkipCComment() { case '*': // End of the comment? if (CurPtr[0] != '/') break; - + ++CurPtr; // End the */. if (--CommentDepth == 0) return false; @@ -383,7 +384,7 @@ tgtok::TokKind TGLexer::LexNumber() { const char *NumStart = CurPtr; while (isxdigit(CurPtr[0])) ++CurPtr; - + // Requires at least one hex digit. if (CurPtr == NumStart) return ReturnError(TokStart, "Invalid hexadecimal number"); @@ -422,7 +423,7 @@ tgtok::TokKind TGLexer::LexNumber() { else if (CurPtr[-1] == '+') return tgtok::plus; } - + while (isdigit(CurPtr[0])) ++CurPtr; CurIntVal = strtoll(TokStart, nullptr, 10); @@ -439,9 +440,9 @@ tgtok::TokKind TGLexer::LexBracket() { while (true) { int Char = getNextChar(); if (Char == EOF) break; - + if (Char != '}') continue; - + Char = getNextChar(); if (Char == EOF) break; if (Char == ']') { @@ -449,7 +450,7 @@ tgtok::TokKind TGLexer::LexBracket() { return tgtok::CodeFragment; } } - + return ReturnError(CodeStart-2, "Unterminated Code Block"); } @@ -457,19 +458,27 @@ tgtok::TokKind TGLexer::LexBracket() { tgtok::TokKind TGLexer::LexExclaim() { if (!isalpha(*CurPtr)) return ReturnError(CurPtr - 1, "Invalid \"!operator\""); - + const char *Start = CurPtr++; while (isalpha(*CurPtr)) ++CurPtr; - + // Check to see which operator this is. tgtok::TokKind Kind = StringSwitch<tgtok::TokKind>(StringRef(Start, CurPtr - Start)) .Case("eq", tgtok::XEq) + .Case("ne", tgtok::XNe) + .Case("le", tgtok::XLe) + .Case("lt", tgtok::XLt) + .Case("ge", tgtok::XGe) + .Case("gt", tgtok::XGt) .Case("if", tgtok::XIf) + .Case("isa", tgtok::XIsA) .Case("head", tgtok::XHead) .Case("tail", tgtok::XTail) + .Case("size", tgtok::XSize) .Case("con", tgtok::XConcat) + .Case("dag", tgtok::XDag) .Case("add", tgtok::XADD) .Case("and", tgtok::XAND) .Case("or", tgtok::XOR) @@ -479,6 +488,7 @@ tgtok::TokKind TGLexer::LexExclaim() { .Case("cast", tgtok::XCast) .Case("empty", tgtok::XEmpty) .Case("subst", tgtok::XSubst) + .Case("foldl", tgtok::XFoldl) .Case("foreach", tgtok::XForEach) .Case("listconcat", tgtok::XListConcat) .Case("strconcat", tgtok::XStrConcat) diff --git a/contrib/llvm/lib/TableGen/TGLexer.h b/contrib/llvm/lib/TableGen/TGLexer.h index b5b58161878b..2c80743e3a68 100644 --- a/contrib/llvm/lib/TableGen/TGLexer.h +++ b/contrib/llvm/lib/TableGen/TGLexer.h @@ -30,7 +30,7 @@ namespace tgtok { enum TokKind { // Markers Eof, Error, - + // Tokens with no info. minus, plus, // - + l_square, r_square, // [ ] @@ -44,11 +44,12 @@ namespace tgtok { // Keywords. Bit, Bits, Class, Code, Dag, Def, Foreach, Defm, Field, In, Int, Let, List, - MultiClass, String, + MultiClass, String, Defset, // !keywords. XConcat, XADD, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XStrConcat, XCast, - XSubst, XForEach, XHead, XTail, XEmpty, XIf, XEq, + XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty, XIf, XEq, XIsA, XDag, + XNe, XLe, XLt, XGe, XGt, // Integer value. IntVal, @@ -56,7 +57,7 @@ namespace tgtok { // Binary constant. Note that these are sized according to the number of // bits given. BinaryIntVal, - + // String valued tokens. Id, StrVal, VarName, CodeFragment }; @@ -65,7 +66,7 @@ namespace tgtok { /// TGLexer - TableGen Lexer class. class TGLexer { SourceMgr &SrcMgr; - + const char *CurPtr; StringRef CurBuf; @@ -95,11 +96,11 @@ public: const DependenciesMapTy &getDependencies() const { return Dependencies; } - + tgtok::TokKind getCode() const { return CurCode; } const std::string &getCurStrVal() const { - assert((CurCode == tgtok::Id || CurCode == tgtok::StrVal || + assert((CurCode == tgtok::Id || CurCode == tgtok::StrVal || CurCode == tgtok::VarName || CurCode == tgtok::CodeFragment) && "This token doesn't have a string value"); return CurStrVal; @@ -115,13 +116,13 @@ public: } SMLoc getLoc() const; - + private: /// LexToken - Read the next token and return its code. tgtok::TokKind LexToken(); - + tgtok::TokKind ReturnError(const char *Loc, const Twine &Msg); - + int getNextChar(); int peekNextChar(int Index); void SkipBCPLComment(); @@ -134,7 +135,7 @@ private: tgtok::TokKind LexBracket(); tgtok::TokKind LexExclaim(); }; - + } // end namespace llvm #endif diff --git a/contrib/llvm/lib/TableGen/TGParser.cpp b/contrib/llvm/lib/TableGen/TGParser.cpp index b492cf9495c0..1d1f3603c83c 100644 --- a/contrib/llvm/lib/TableGen/TGParser.cpp +++ b/contrib/llvm/lib/TableGen/TGParser.cpp @@ -16,6 +16,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" @@ -68,6 +69,75 @@ LLVM_DUMP_METHOD void SubMultiClassReference::dump() const { } // end namespace llvm +static bool checkBitsConcrete(Record &R, const RecordVal &RV) { + BitsInit *BV = cast<BitsInit>(RV.getValue()); + for (unsigned i = 0, e = BV->getNumBits(); i != e; ++i) { + Init *Bit = BV->getBit(i); + bool IsReference = false; + if (auto VBI = dyn_cast<VarBitInit>(Bit)) { + if (auto VI = dyn_cast<VarInit>(VBI->getBitVar())) { + if (R.getValue(VI->getName())) + IsReference = true; + } + } else if (isa<VarInit>(Bit)) { + IsReference = true; + } + if (!(IsReference || Bit->isConcrete())) + return false; + } + return true; +} + +static void checkConcrete(Record &R) { + for (const RecordVal &RV : R.getValues()) { + // HACK: Disable this check for variables declared with 'field'. This is + // done merely because existing targets have legitimate cases of + // non-concrete variables in helper defs. Ideally, we'd introduce a + // 'maybe' or 'optional' modifier instead of this. + if (RV.getPrefix()) + continue; + + if (Init *V = RV.getValue()) { + bool Ok = isa<BitsInit>(V) ? checkBitsConcrete(R, RV) : V->isConcrete(); + if (!Ok) { + PrintError(R.getLoc(), + Twine("Initializer of '") + RV.getNameInitAsString() + + "' in '" + R.getNameInitAsString() + + "' could not be fully resolved: " + + RV.getValue()->getAsString()); + } + } + } +} + +/// Return an Init with a qualifier prefix referring +/// to CurRec's name. +static Init *QualifyName(Record &CurRec, MultiClass *CurMultiClass, + Init *Name, StringRef Scoper) { + Init *NewName = + BinOpInit::getStrConcat(CurRec.getNameInit(), StringInit::get(Scoper)); + NewName = BinOpInit::getStrConcat(NewName, Name); + if (CurMultiClass && Scoper != "::") { + Init *Prefix = BinOpInit::getStrConcat(CurMultiClass->Rec.getNameInit(), + StringInit::get("::")); + NewName = BinOpInit::getStrConcat(Prefix, NewName); + } + + if (BinOpInit *BinOp = dyn_cast<BinOpInit>(NewName)) + NewName = BinOp->Fold(&CurRec); + return NewName; +} + +/// Return the qualified version of the implicit 'NAME' template argument. +static Init *QualifiedNameOfImplicitName(Record &Rec, + MultiClass *MC = nullptr) { + return QualifyName(Rec, MC, StringInit::get("NAME"), MC ? "::" : ":"); +} + +static Init *QualifiedNameOfImplicitName(MultiClass *MC) { + return QualifiedNameOfImplicitName(MC->Rec, MC); +} + bool TGParser::AddValue(Record *CurRec, SMLoc Loc, const RecordVal &RV) { if (!CurRec) CurRec = &CurMultiClass->Rec; @@ -104,7 +174,7 @@ bool TGParser::SetValue(Record *CurRec, SMLoc Loc, Init *ValName, if (BitList.empty()) if (VarInit *VI = dyn_cast<VarInit>(V)) if (VI->getNameInit() == ValName && !AllowSelfAssignment) - return true; + 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 @@ -117,13 +187,10 @@ bool TGParser::SetValue(Record *CurRec, SMLoc Loc, Init *ValName, "' is not a bits type"); // Convert the incoming value to a bits type of the appropriate size... - Init *BI = V->convertInitializerTo(BitsRecTy::get(BitList.size())); + Init *BI = V->getCastTo(BitsRecTy::get(BitList.size())); if (!BI) return Error(Loc, "Initializer is not compatible with bit range"); - // We should have a BitsInit type now. - BitsInit *BInit = cast<BitsInit>(BI); - SmallVector<Init *, 16> NewBits(CurVal->getNumBits()); // Loop over bits, assigning values as appropriate. @@ -132,7 +199,7 @@ bool TGParser::SetValue(Record *CurRec, SMLoc Loc, Init *ValName, if (NewBits[Bit]) return Error(Loc, "Cannot set bit #" + Twine(Bit) + " of value '" + ValName->getAsUnquotedString() + "' more than once"); - NewBits[Bit] = BInit->getBit(i); + NewBits[Bit] = BI->getBit(i); } for (unsigned i = 0, e = CurVal->getNumBits(); i != e; ++i) @@ -147,10 +214,12 @@ bool TGParser::SetValue(Record *CurRec, SMLoc Loc, Init *ValName, if (BitsInit *BI = dyn_cast<BitsInit>(V)) InitType = (Twine("' of type bit initializer with length ") + Twine(BI->getNumBits())).str(); + else if (TypedInit *TI = dyn_cast<TypedInit>(V)) + InitType = (Twine("' of type '") + TI->getType()->getAsString()).str(); return Error(Loc, "Value '" + ValName->getAsUnquotedString() + - "' of type '" + RV->getType()->getAsString() + - "' is incompatible with initializer '" + V->getAsString() + - InitType + "'"); + "' of type '" + RV->getType()->getAsString() + + "' is incompatible with initializer '" + + V->getAsString() + InitType + "'"); } return false; } @@ -173,27 +242,36 @@ bool TGParser::AddSubClass(Record *CurRec, SubClassReference &SubClass) { // Loop over all of the template arguments, setting them to the specified // value or leaving them as the default if necessary. + MapResolver R(CurRec); + for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { if (i < SubClass.TemplateArgs.size()) { // If a value is specified for this template arg, set it now. if (SetValue(CurRec, SubClass.RefRange.Start, TArgs[i], None, SubClass.TemplateArgs[i])) return true; - - // Resolve it next. - CurRec->resolveReferencesTo(CurRec->getValue(TArgs[i])); - - // Now remove it. - CurRec->removeValue(TArgs[i]); - } else if (!CurRec->getValue(TArgs[i])->getValue()->isComplete()) { return Error(SubClass.RefRange.Start, "Value not specified for template argument #" + Twine(i) + " (" + TArgs[i]->getAsUnquotedString() + ") of subclass '" + SC->getNameInitAsString() + "'!"); } + + R.set(TArgs[i], CurRec->getValue(TArgs[i])->getValue()); + + CurRec->removeValue(TArgs[i]); } + Init *Name; + if (CurRec->isClass()) + Name = + VarInit::get(QualifiedNameOfImplicitName(*CurRec), StringRecTy::get()); + else + Name = CurRec->getNameInit(); + R.set(QualifiedNameOfImplicitName(*SC), Name); + + CurRec->resolveReferences(R); + // Since everything went well, we can now set the "superclass" list for the // current record. ArrayRef<std::pair<Record *, SMRange>> SCs = SC->getSuperClasses(); @@ -211,157 +289,189 @@ bool TGParser::AddSubClass(Record *CurRec, SubClassReference &SubClass) { return false; } +bool TGParser::AddSubClass(RecordsEntry &Entry, SubClassReference &SubClass) { + if (Entry.Rec) + return AddSubClass(Entry.Rec.get(), SubClass); + + for (auto &E : Entry.Loop->Entries) { + if (AddSubClass(E, SubClass)) + return true; + } + + return false; +} + /// AddSubMultiClass - Add SubMultiClass as a subclass to /// CurMC, resolving its template args as SubMultiClass's /// template arguments. bool TGParser::AddSubMultiClass(MultiClass *CurMC, SubMultiClassReference &SubMultiClass) { MultiClass *SMC = SubMultiClass.MC; - Record *CurRec = &CurMC->Rec; - - // Add all of the values in the subclass into the current class. - for (const auto &SMCVal : SMC->Rec.getValues()) - if (AddValue(CurRec, SubMultiClass.RefRange.Start, SMCVal)) - return true; - - unsigned newDefStart = CurMC->DefPrototypes.size(); - - // Add all of the defs in the subclass into the current multiclass. - for (const std::unique_ptr<Record> &R : SMC->DefPrototypes) { - // Clone the def and add it to the current multiclass - auto NewDef = make_unique<Record>(*R); - - // Add all of the values in the superclass into the current def. - for (const auto &MCVal : CurRec->getValues()) - if (AddValue(NewDef.get(), SubMultiClass.RefRange.Start, MCVal)) - return true; - - CurMC->DefPrototypes.push_back(std::move(NewDef)); - } ArrayRef<Init *> SMCTArgs = SMC->Rec.getTemplateArgs(); - - // Ensure that an appropriate number of template arguments are - // specified. if (SMCTArgs.size() < SubMultiClass.TemplateArgs.size()) return Error(SubMultiClass.RefRange.Start, "More template args specified than expected"); - // Loop over all of the template arguments, setting them to the specified - // value or leaving them as the default if necessary. + // 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()) { - // If a value is specified for this template arg, set it in the - // superclass now. - if (SetValue(CurRec, SubMultiClass.RefRange.Start, SMCTArgs[i], - None, SubMultiClass.TemplateArgs[i])) - return true; - - // Resolve it next. - CurRec->resolveReferencesTo(CurRec->getValue(SMCTArgs[i])); + 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); + } + } - // Now remove it. - CurRec->removeValue(SMCTArgs[i]); + TemplateArgs.emplace_back( + QualifiedNameOfImplicitName(SMC), + VarInit::get(QualifiedNameOfImplicitName(CurMC), StringRecTy::get())); - // If a value is specified for this template arg, set it in the - // new defs now. - for (const auto &Def : - makeArrayRef(CurMC->DefPrototypes).slice(newDefStart)) { - if (SetValue(Def.get(), SubMultiClass.RefRange.Start, SMCTArgs[i], - None, SubMultiClass.TemplateArgs[i])) - return true; + // Add all of the defs in the subclass into the current multiclass. + return resolve(SMC->Entries, TemplateArgs, false, &CurMC->Entries); +} - // Resolve it next. - Def->resolveReferencesTo(Def->getValue(SMCTArgs[i])); +/// Add a record or foreach loop to the current context (global record keeper, +/// current inner-most foreach loop, or multiclass). +bool TGParser::addEntry(RecordsEntry E) { + assert(!E.Rec || !E.Loop); - // Now remove it - Def->removeValue(SMCTArgs[i]); - } - } else if (!CurRec->getValue(SMCTArgs[i])->getValue()->isComplete()) { - return Error(SubMultiClass.RefRange.Start, - "Value not specified for template argument #" + - Twine(i) + " (" + SMCTArgs[i]->getAsUnquotedString() + - ") of subclass '" + SMC->Rec.getNameInitAsString() + "'!"); - } + if (!Loops.empty()) { + Loops.back()->Entries.push_back(std::move(E)); + return false; } - return false; -} + if (E.Loop) { + SubstStack Stack; + return resolve(*E.Loop, Stack, CurMultiClass == nullptr, + CurMultiClass ? &CurMultiClass->Entries : nullptr); + } -/// ProcessForeachDefs - Given a record, apply all of the variable -/// values in all surrounding foreach loops, creating new records for -/// each combination of values. -bool TGParser::ProcessForeachDefs(Record *CurRec, SMLoc Loc) { - if (Loops.empty()) + if (CurMultiClass) { + CurMultiClass->Entries.push_back(std::move(E)); return false; + } - // We want to instantiate a new copy of CurRec for each combination - // of nested loop iterator values. We don't want top instantiate - // any copies until we have values for each loop iterator. - IterSet IterVals; - return ProcessForeachDefs(CurRec, Loc, IterVals); + return addDefOne(std::move(E.Rec)); } -/// ProcessForeachDefs - Given a record, a loop and a loop iterator, -/// apply each of the variable values in this loop and then process -/// subloops. -bool TGParser::ProcessForeachDefs(Record *CurRec, SMLoc Loc, IterSet &IterVals){ - // Recursively build a tuple of iterator values. - if (IterVals.size() != Loops.size()) { - assert(IterVals.size() < Loops.size()); - ForeachLoop &CurLoop = Loops[IterVals.size()]; - ListInit *List = dyn_cast<ListInit>(CurLoop.ListValue); - if (!List) { - Error(Loc, "Loop list is not a list"); - return true; - } +/// Resolve the entries in \p Loop, going over inner loops recursively +/// and making the given subsitutions of (name, value) pairs. +/// +/// The resulting records are stored in \p Dest if non-null. Otherwise, they +/// are added to the global record keeper. +bool TGParser::resolve(const ForeachLoop &Loop, SubstStack &Substs, + bool Final, std::vector<RecordsEntry> *Dest, + SMLoc *Loc) { + MapResolver R; + for (const auto &S : Substs) + R.set(S.first, S.second); + Init *List = Loop.ListValue->resolveReferences(R); + auto LI = dyn_cast<ListInit>(List); + if (!LI) { + if (!Final) { + Dest->emplace_back(make_unique<ForeachLoop>(Loop.Loc, Loop.IterVar, + List)); + return resolve(Loop.Entries, Substs, Final, &Dest->back().Loop->Entries, + Loc); + } + + PrintError(Loop.Loc, Twine("attempting to loop over '") + + List->getAsString() + "', expected a list"); + return true; + } - // Process each value. - for (unsigned i = 0; i < List->size(); ++i) { - Init *ItemVal = List->resolveListElementReference(*CurRec, nullptr, i); - IterVals.push_back(IterRecord(CurLoop.IterVar, ItemVal)); - if (ProcessForeachDefs(CurRec, Loc, IterVals)) - return true; - IterVals.pop_back(); - } - return false; + bool Error = false; + for (auto Elt : *LI) { + Substs.emplace_back(Loop.IterVar->getNameInit(), Elt); + Error = resolve(Loop.Entries, Substs, Final, Dest); + Substs.pop_back(); + if (Error) + break; } + return Error; +} - // This is the bottom of the recursion. We have all of the iterator values - // for this point in the iteration space. Instantiate a new record to - // reflect this combination of values. - auto IterRec = make_unique<Record>(*CurRec); +/// Resolve the entries in \p Source, going over loops recursively and +/// making the given substitutions of (name, value) pairs. +/// +/// The resulting records are stored in \p Dest if non-null. Otherwise, they +/// are added to the global record keeper. +bool TGParser::resolve(const std::vector<RecordsEntry> &Source, + SubstStack &Substs, bool Final, + std::vector<RecordsEntry> *Dest, SMLoc *Loc) { + bool Error = false; + for (auto &E : Source) { + if (E.Loop) { + Error = resolve(*E.Loop, Substs, Final, Dest); + } else { + auto Rec = make_unique<Record>(*E.Rec); + if (Loc) + Rec->appendLoc(*Loc); - // Set the iterator values now. - for (IterRecord &IR : IterVals) { - VarInit *IterVar = IR.IterVar; - TypedInit *IVal = dyn_cast<TypedInit>(IR.IterValue); - if (!IVal) - return Error(Loc, "foreach iterator value is untyped"); + MapResolver R(Rec.get()); + for (const auto &S : Substs) + R.set(S.first, S.second); + Rec->resolveReferences(R); - IterRec->addValue(RecordVal(IterVar->getNameInit(), IVal->getType(), false)); + if (Dest) + Dest->push_back(std::move(Rec)); + else + Error = addDefOne(std::move(Rec)); + } + if (Error) + break; + } + return Error; +} - if (SetValue(IterRec.get(), Loc, IterVar->getNameInit(), None, IVal)) - return Error(Loc, "when instantiating this def"); +/// Resolve the record fully and add it to the record keeper. +bool TGParser::addDefOne(std::unique_ptr<Record> Rec) { + if (Record *Prev = Records.getDef(Rec->getNameInitAsString())) { + if (!Rec->isAnonymous()) { + PrintError(Rec->getLoc(), + "def already exists: " + Rec->getNameInitAsString()); + PrintNote(Prev->getLoc(), "location of previous definition"); + return true; + } + Rec->setName(Records.getNewAnonymousName()); + } - // Resolve it next. - IterRec->resolveReferencesTo(IterRec->getValue(IterVar->getNameInit())); + Rec->resolveReferences(); + checkConcrete(*Rec); - // Remove it. - IterRec->removeValue(IterVar->getNameInit()); + if (!isa<StringInit>(Rec->getNameInit())) { + PrintError(Rec->getLoc(), Twine("record name '") + + Rec->getNameInit()->getAsString() + + "' could not be fully resolved"); + return true; } - if (Records.getDef(IterRec->getNameInitAsString())) { - // If this record is anonymous, it's no problem, just generate a new name - if (!IterRec->isAnonymous()) - return Error(Loc, "def already exists: " +IterRec->getNameInitAsString()); - - IterRec->setName(GetNewAnonymousName()); + // 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); } - Record *IterRecSave = IterRec.get(); // Keep a copy before release. - Records.addDef(std::move(IterRec)); - IterRecSave->resolveReferences(); + Records.addDef(std::move(Rec)); return false; } @@ -371,19 +481,14 @@ bool TGParser::ProcessForeachDefs(Record *CurRec, SMLoc Loc, IterSet &IterVals){ /// isObjectStart - Return true if this is a valid first token for an Object. static bool isObjectStart(tgtok::TokKind K) { - return K == tgtok::Class || K == tgtok::Def || - K == tgtok::Defm || K == tgtok::Let || - K == tgtok::MultiClass || K == tgtok::Foreach; -} - -/// GetNewAnonymousName - Generate a unique anonymous name that can be used as -/// an identifier. -Init *TGParser::GetNewAnonymousName() { - return StringInit::get("anonymous_" + utostr(AnonCounter++)); + return K == tgtok::Class || K == tgtok::Def || K == tgtok::Defm || + K == tgtok::Let || K == tgtok::MultiClass || K == tgtok::Foreach || + K == tgtok::Defset; } -/// ParseObjectName - If an object name is specified, return it. Otherwise, -/// return 0. +/// 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*/ /// @@ -395,7 +500,7 @@ Init *TGParser::ParseObjectName(MultiClass *CurMultiClass) { // 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 nullptr; + return UnsetInit::get(); default: break; } @@ -404,17 +509,20 @@ Init *TGParser::ParseObjectName(MultiClass *CurMultiClass) { if (CurMultiClass) CurRec = &CurMultiClass->Rec; - RecTy *Type = nullptr; - if (CurRec) { - const TypedInit *CurRecName = dyn_cast<TypedInit>(CurRec->getNameInit()); - if (!CurRecName) { - TokError("Record name is not typed!"); - return nullptr; - } - Type = CurRecName->getType(); + 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 ParseValue(CurRec, Type, ParseNameMode); + return Name; } /// ParseClassID - Parse and resolve a reference to a class name. This returns @@ -679,6 +787,7 @@ RecTy *TGParser::ParseType() { 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' @@ -723,33 +832,29 @@ Init *TGParser::ParseIDValue(Record *CurRec, StringInit *Name, SMLoc NameLoc, if (CurRec) { if (const RecordVal *RV = CurRec->getValue(Name)) return VarInit::get(Name, RV->getType()); - - Init *TemplateArgName = QualifyName(*CurRec, CurMultiClass, Name, ":"); - - if (CurMultiClass) - TemplateArgName = QualifyName(CurMultiClass->Rec, CurMultiClass, Name, - "::"); - - if (CurRec->isTemplateArg(TemplateArgName)) { - const RecordVal *RV = CurRec->getValue(TemplateArgName); - assert(RV && "Template arg doesn't exist??"); - return VarInit::get(TemplateArgName, RV->getType()); - } } - if (CurMultiClass) { - Init *MCName = QualifyName(CurMultiClass->Rec, CurMultiClass, Name, "::"); + if ((CurRec && CurRec->isClass()) || CurMultiClass) { + Init *TemplateArgName; + if (CurMultiClass) { + TemplateArgName = + QualifyName(CurMultiClass->Rec, CurMultiClass, Name, "::"); + } else + TemplateArgName = QualifyName(*CurRec, CurMultiClass, Name, ":"); - if (CurMultiClass->Rec.isTemplateArg(MCName)) { - const RecordVal *RV = CurMultiClass->Rec.getValue(MCName); + Record *TemplateRec = CurMultiClass ? &CurMultiClass->Rec : CurRec; + if (TemplateRec->isTemplateArg(TemplateArgName)) { + const RecordVal *RV = TemplateRec->getValue(TemplateArgName); assert(RV && "Template arg doesn't exist??"); - return VarInit::get(MCName, RV->getType()); + return VarInit::get(TemplateArgName, RV->getType()); + } else if (Name->getValue() == "NAME") { + return VarInit::get(TemplateArgName, StringRecTy::get()); } } // If this is in a foreach loop, make sure it's not a loop iterator for (const auto &L : Loops) { - VarInit *IterVar = dyn_cast<VarInit>(L.IterVar); + VarInit *IterVar = dyn_cast<VarInit>(L->IterVar); if (IterVar && IterVar->getNameInit() == Name) return IterVar; } @@ -757,15 +862,17 @@ Init *TGParser::ParseIDValue(Record *CurRec, StringInit *Name, SMLoc NameLoc, if (Mode == ParseNameMode) return Name; - if (Record *D = Records.getDef(Name->getValue())) - return DefInit::get(D); + if (Init *I = Records.getGlobal(Name->getValue())) + return I; - if (Mode == ParseValueMode) { - Error(NameLoc, "Variable not defined: '" + Name->getValue() + "'"); - return nullptr; - } + // 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()); - return Name; + Error(NameLoc, "Variable not defined: '" + Name->getValue() + "'"); + return nullptr; } /// ParseOperation - Parse an operator. This returns null on error. @@ -779,6 +886,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { return nullptr; case tgtok::XHead: case tgtok::XTail: + case tgtok::XSize: case tgtok::XEmpty: case tgtok::XCast: { // Value ::= !unop '(' Value ')' UnOpInit::UnaryOp Code; @@ -806,6 +914,11 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { 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; @@ -840,12 +953,15 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { } } - if (Code == UnOpInit::HEAD || Code == UnOpInit::TAIL) { + if (Code == UnOpInit::HEAD || Code == UnOpInit::TAIL || + Code == UnOpInit::SIZE) { if (!LHSl && !LHSt) { TokError("expected list type argument in unary operator"); return nullptr; } + } + if (Code == UnOpInit::HEAD || Code == UnOpInit::TAIL) { if (LHSl && LHSl->empty()) { TokError("empty list argument in unary operator"); return nullptr; @@ -876,7 +992,34 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { return nullptr; } Lex.Lex(); // eat the ')' - return (UnOpInit::get(Code, LHS, Type))->Fold(CurRec, CurMultiClass); + 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 (Lex.getCode() != tgtok::l_paren) { + TokError("expected '(' after type of !isa"); + return nullptr; + } + Lex.Lex(); // eat the '(' + + Init *LHS = ParseValue(CurRec); + if (!LHS) + return nullptr; + + if (Lex.getCode() != tgtok::r_paren) { + TokError("expected ')' in !isa"); + return nullptr; + } + Lex.Lex(); // eat the ')' + + return (IsAOpInit::get(Type, LHS))->Fold(); } case tgtok::XConcat: @@ -887,6 +1030,11 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { 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::XStrConcat: { // Value ::= !binop '(' Value ',' Value ')' tgtok::TokKind OpTok = Lex.getCode(); @@ -894,28 +1042,72 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { Lex.Lex(); // eat the operation BinOpInit::BinaryOp Code; - RecTy *Type = nullptr; - switch (OpTok) { default: llvm_unreachable("Unhandled code!"); - case tgtok::XConcat: Code = BinOpInit::CONCAT;Type = DagRecTy::get(); break; - case tgtok::XADD: Code = BinOpInit::ADD; Type = IntRecTy::get(); break; - case tgtok::XAND: Code = BinOpInit::AND; Type = IntRecTy::get(); break; - case tgtok::XOR: Code = BinOpInit::OR; Type = IntRecTy::get(); break; - case tgtok::XSRA: Code = BinOpInit::SRA; Type = IntRecTy::get(); break; - case tgtok::XSRL: Code = BinOpInit::SRL; Type = IntRecTy::get(); break; - case tgtok::XSHL: Code = BinOpInit::SHL; Type = IntRecTy::get(); break; - case tgtok::XEq: Code = BinOpInit::EQ; Type = BitRecTy::get(); break; + case tgtok::XConcat: Code = BinOpInit::CONCAT; break; + case tgtok::XADD: Code = BinOpInit::ADD; break; + case tgtok::XAND: Code = BinOpInit::AND; break; + case tgtok::XOR: Code = BinOpInit::OR; 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::XStrConcat: Code = BinOpInit::STRCONCAT; break; + } + + RecTy *Type = nullptr; + RecTy *ArgType = nullptr; + switch (OpTok) { + default: + llvm_unreachable("Unhandled code!"); + case tgtok::XConcat: + Type = DagRecTy::get(); + ArgType = DagRecTy::get(); + break; + case tgtok::XAND: + case tgtok::XOR: + case tgtok::XSRA: + case tgtok::XSRL: + case tgtok::XSHL: + case tgtok::XADD: + Type = IntRecTy::get(); + ArgType = IntRecTy::get(); + break; + case tgtok::XEq: + case tgtok::XNe: + Type = BitRecTy::get(); + // ArgType for Eq / Ne is not known at this point + break; + case tgtok::XLe: + case tgtok::XLt: + case tgtok::XGe: + case tgtok::XGt: + Type = BitRecTy::get(); + ArgType = IntRecTy::get(); + break; case tgtok::XListConcat: - Code = BinOpInit::LISTCONCAT; // We don't know the list type until we parse the first argument + ArgType = ItemType; break; case tgtok::XStrConcat: - Code = BinOpInit::STRCONCAT; Type = StringRecTy::get(); + ArgType = StringRecTy::get(); break; } + if (Type && ItemType && !Type->typeIsConvertibleTo(ItemType)) { + Error(OpLoc, Twine("expected value of type '") + + ItemType->getAsString() + "', got '" + + Type->getAsString() + "'"); + return nullptr; + } + if (Lex.getCode() != tgtok::l_paren) { TokError("expected '(' after binary operator"); return nullptr; @@ -924,14 +1116,52 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { SmallVector<Init*, 2> InitList; - InitList.push_back(ParseValue(CurRec)); - if (!InitList.back()) return nullptr; + for (;;) { + SMLoc InitLoc = Lex.getLoc(); + InitList.push_back(ParseValue(CurRec, ArgType)); + if (!InitList.back()) return nullptr; - while (Lex.getCode() == tgtok::comma) { - Lex.Lex(); // eat the ',' + // All BinOps require their arguments to be of compatible types. + TypedInit *TI = dyn_cast<TypedInit>(InitList.back()); + if (!ArgType) { + ArgType = TI->getType(); - InitList.push_back(ParseValue(CurRec)); - if (!InitList.back()) return nullptr; + switch (Code) { + case BinOpInit::LISTCONCAT: + if (!isa<ListRecTy>(ArgType)) { + Error(InitLoc, Twine("expected a list, got value of type '") + + ArgType->getAsString() + "'"); + return nullptr; + } + break; + case BinOpInit::EQ: + case BinOpInit::NE: + if (!ArgType->typeIsConvertibleTo(IntRecTy::get()) && + !ArgType->typeIsConvertibleTo(StringRecTy::get())) { + Error(InitLoc, Twine("expected int, bits, or string; got value of " + "type '") + ArgType->getAsString() + "'"); + return nullptr; + } + break; + default: llvm_unreachable("other ops have fixed argument types"); + } + } else { + RecTy *Resolved = resolveTypes(ArgType, TI->getType()); + if (!Resolved) { + Error(InitLoc, Twine("expected value of type '") + + ArgType->getAsString() + "', got '" + + TI->getType()->getAsString() + "'"); + return nullptr; + } + if (Code != BinOpInit::ADD && Code != BinOpInit::AND && + Code != BinOpInit::OR && Code != BinOpInit::SRA && + Code != BinOpInit::SRL && Code != BinOpInit::SHL) + ArgType = Resolved; + } + + if (Lex.getCode() != tgtok::comma) + break; + Lex.Lex(); // eat the ',' } if (Lex.getCode() != tgtok::r_paren) { @@ -940,40 +1170,142 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { } Lex.Lex(); // eat the ')' - // If we are doing !listconcat, we should know the type by now - if (OpTok == tgtok::XListConcat) { - if (VarInit *Arg0 = dyn_cast<VarInit>(InitList[0])) - Type = Arg0->getType(); - else if (ListInit *Arg0 = dyn_cast<ListInit>(InitList[0])) - Type = Arg0->getType(); - else { - InitList[0]->print(errs()); - Error(OpLoc, "expected a list"); - return nullptr; - } - } + if (Code == BinOpInit::LISTCONCAT) + Type = ArgType; // We allow multiple operands to associative operators like !strconcat as // shorthand for nesting them. - if (Code == BinOpInit::STRCONCAT || Code == BinOpInit::LISTCONCAT) { + if (Code == BinOpInit::STRCONCAT || Code == BinOpInit::LISTCONCAT || + Code == BinOpInit::CONCAT || Code == BinOpInit::ADD || + Code == BinOpInit::AND || Code == BinOpInit::OR) { while (InitList.size() > 2) { Init *RHS = InitList.pop_back_val(); - RHS = (BinOpInit::get(Code, InitList.back(), RHS, Type)) - ->Fold(CurRec, CurMultiClass); + 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, CurMultiClass); + ->Fold(CurRec); Error(OpLoc, "expected two operands to operator"); return nullptr; } + case tgtok::XForEach: { // Value ::= !foreach '(' Id ',' Value ',' Value ')' + SMLoc OpLoc = Lex.getLoc(); + Lex.Lex(); // eat the operation + if (Lex.getCode() != tgtok::l_paren) { + TokError("expected '(' after !foreach"); + return nullptr; + } + + if (Lex.Lex() != tgtok::Id) { // eat the '(' + TokError("first argument of !foreach must be an identifier"); + return nullptr; + } + + Init *LHS = StringInit::get(Lex.getCurStrVal()); + + if (CurRec && CurRec->getValue(LHS)) { + TokError((Twine("iteration variable '") + LHS->getAsString() + + "' already defined") + .str()); + return nullptr; + } + + if (Lex.Lex() != tgtok::comma) { // eat the id + TokError("expected ',' in ternary operator"); + return nullptr; + } + Lex.Lex(); // eat the ',' + + Init *MHS = ParseValue(CurRec); + if (!MHS) + return nullptr; + + if (Lex.getCode() != tgtok::comma) { + TokError("expected ',' in ternary operator"); + return nullptr; + } + Lex.Lex(); // eat the ',' + + TypedInit *MHSt = dyn_cast<TypedInit>(MHS); + if (!MHSt) { + TokError("could not get type of !foreach input"); + return nullptr; + } + + RecTy *InEltType = nullptr; + RecTy *OutEltType = nullptr; + bool IsDAG = false; + + if (ListRecTy *InListTy = dyn_cast<ListRecTy>(MHSt->getType())) { + InEltType = InListTy->getElementType(); + if (ItemType) { + if (ListRecTy *OutListTy = dyn_cast<ListRecTy>(ItemType)) { + OutEltType = OutListTy->getElementType(); + } else { + Error(OpLoc, + "expected value of type '" + Twine(ItemType->getAsString()) + + "', but got !foreach of list type"); + return nullptr; + } + } + } else if (DagRecTy *InDagTy = dyn_cast<DagRecTy>(MHSt->getType())) { + InEltType = InDagTy; + if (ItemType && !isa<DagRecTy>(ItemType)) { + Error(OpLoc, + "expected value of type '" + Twine(ItemType->getAsString()) + + "', but got !foreach of dag type"); + return nullptr; + } + IsDAG = true; + } else { + TokError("!foreach must have list or dag input"); + return nullptr; + } + + // We need to create a temporary record to provide a scope for the iteration + // variable while parsing top-level foreach's. + std::unique_ptr<Record> ParseRecTmp; + Record *ParseRec = CurRec; + if (!ParseRec) { + ParseRecTmp = make_unique<Record>(".parse", ArrayRef<SMLoc>{}, Records); + ParseRec = ParseRecTmp.get(); + } + + ParseRec->addValue(RecordVal(LHS, InEltType, false)); + Init *RHS = ParseValue(ParseRec, OutEltType); + ParseRec->removeValue(LHS); + if (!RHS) + return nullptr; + + if (Lex.getCode() != tgtok::r_paren) { + TokError("expected ')' in binary operator"); + return nullptr; + } + Lex.Lex(); // eat the ')' + + RecTy *OutType; + if (IsDAG) { + OutType = InEltType; + } else { + TypedInit *RHSt = dyn_cast<TypedInit>(RHS); + if (!RHSt) { + TokError("could not get type of !foreach result"); + return nullptr; + } + OutType = RHSt->getType()->getListTy(); + } + + return (TernOpInit::get(TernOpInit::FOREACH, LHS, MHS, RHS, OutType)) + ->Fold(CurRec); + } + + case tgtok::XDag: case tgtok::XIf: - case tgtok::XForEach: case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')' TernOpInit::TernaryOp Code; RecTy *Type = nullptr; @@ -982,12 +1314,14 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { 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::XForEach: - Code = TernOpInit::FOREACH; - break; case tgtok::XSubst: Code = TernOpInit::SUBST; break; @@ -1007,6 +1341,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { } Lex.Lex(); // eat the ',' + SMLoc MHSLoc = Lex.getLoc(); Init *MHS = ParseValue(CurRec, ItemType); if (!MHS) return nullptr; @@ -1017,6 +1352,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { } Lex.Lex(); // eat the ',' + SMLoc RHSLoc = Lex.getLoc(); Init *RHS = ParseValue(CurRec, ItemType); if (!RHS) return nullptr; @@ -1029,6 +1365,36 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { switch (LexCode) { default: llvm_unreachable("Unhandled code!"); + case tgtok::XDag: { + TypedInit *MHSt = dyn_cast<TypedInit>(MHS); + if (!MHSt && !isa<UnsetInit>(MHS)) { + Error(MHSLoc, "could not determine type of the child list in !dag"); + return nullptr; + } + if (MHSt && !isa<ListRecTy>(MHSt->getType())) { + Error(MHSLoc, Twine("expected list of children, got type '") + + MHSt->getType()->getAsString() + "'"); + return nullptr; + } + + TypedInit *RHSt = dyn_cast<TypedInit>(RHS); + if (!RHSt && !isa<UnsetInit>(RHS)) { + Error(RHSLoc, "could not determine type of the name list in !dag"); + return nullptr; + } + if (RHSt && StringRecTy::get()->getListTy() != RHSt->getType()) { + Error(RHSLoc, Twine("expected list<string>, got type '") + + RHSt->getType()->getAsString() + "'"); + return nullptr; + } + + if (!MHSt && !RHSt) { + Error(MHSLoc, + "cannot have both unset children and unset names in !dag"); + return nullptr; + } + break; + } case tgtok::XIf: { RecTy *MHSTy = nullptr; RecTy *RHSTy = nullptr; @@ -1058,23 +1424,12 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { return nullptr; } - if (MHSTy->typeIsConvertibleTo(RHSTy)) { - Type = RHSTy; - } else if (RHSTy->typeIsConvertibleTo(MHSTy)) { - Type = MHSTy; - } else { - TokError("inconsistent types for !if"); - return nullptr; - } - break; - } - case tgtok::XForEach: { - TypedInit *MHSt = dyn_cast<TypedInit>(MHS); - if (!MHSt) { - TokError("could not get type for !foreach"); + Type = resolveTypes(MHSTy, RHSTy); + if (!Type) { + TokError(Twine("inconsistent types '") + MHSTy->getAsString() + + "' and '" + RHSTy->getAsString() + "' for !if"); return nullptr; } - Type = MHSt->getType(); break; } case tgtok::XSubst: { @@ -1087,8 +1442,133 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { break; } } - return (TernOpInit::get(Code, LHS, MHS, RHS, Type))->Fold(CurRec, - CurMultiClass); + return (TernOpInit::get(Code, LHS, MHS, RHS, Type))->Fold(CurRec); + } + + case tgtok::XFoldl: { + // Value ::= !foldl '(' Id ',' Id ',' Value ',' Value ',' Value ')' + Lex.Lex(); // eat the operation + if (Lex.getCode() != tgtok::l_paren) { + TokError("expected '(' after !foldl"); + return nullptr; + } + Lex.Lex(); // eat the '(' + + Init *StartUntyped = ParseValue(CurRec); + if (!StartUntyped) + return nullptr; + + TypedInit *Start = dyn_cast<TypedInit>(StartUntyped); + if (!Start) { + TokError(Twine("could not get type of !foldl start: '") + + StartUntyped->getAsString() + "'"); + return nullptr; + } + + if (Lex.getCode() != tgtok::comma) { + TokError("expected ',' in !foldl"); + return nullptr; + } + Lex.Lex(); // eat the ',' + + Init *ListUntyped = ParseValue(CurRec); + if (!ListUntyped) + return nullptr; + + TypedInit *List = dyn_cast<TypedInit>(ListUntyped); + if (!List) { + TokError(Twine("could not get type of !foldl list: '") + + ListUntyped->getAsString() + "'"); + return nullptr; + } + + ListRecTy *ListType = dyn_cast<ListRecTy>(List->getType()); + if (!ListType) { + TokError(Twine("!foldl list must be a list, but is of type '") + + List->getType()->getAsString()); + return nullptr; + } + + if (Lex.getCode() != tgtok::comma) { + TokError("expected ',' in !foldl"); + return nullptr; + } + + if (Lex.Lex() != tgtok::Id) { // eat the ',' + TokError("third argument of !foldl must be an identifier"); + return nullptr; + } + + Init *A = StringInit::get(Lex.getCurStrVal()); + if (CurRec && CurRec->getValue(A)) { + TokError((Twine("left !foldl variable '") + A->getAsString() + + "' already defined") + .str()); + return nullptr; + } + + if (Lex.Lex() != tgtok::comma) { // eat the id + TokError("expected ',' in !foldl"); + return nullptr; + } + + if (Lex.Lex() != tgtok::Id) { // eat the ',' + TokError("fourth argument of !foldl must be an identifier"); + return nullptr; + } + + Init *B = StringInit::get(Lex.getCurStrVal()); + if (CurRec && CurRec->getValue(B)) { + TokError((Twine("right !foldl variable '") + B->getAsString() + + "' already defined") + .str()); + return nullptr; + } + + if (Lex.Lex() != tgtok::comma) { // eat the id + TokError("expected ',' in !foldl"); + return nullptr; + } + Lex.Lex(); // eat the ',' + + // We need to create a temporary record to provide a scope for the iteration + // variable while parsing top-level foreach's. + std::unique_ptr<Record> ParseRecTmp; + Record *ParseRec = CurRec; + if (!ParseRec) { + ParseRecTmp = make_unique<Record>(".parse", ArrayRef<SMLoc>{}, Records); + ParseRec = ParseRecTmp.get(); + } + + ParseRec->addValue(RecordVal(A, Start->getType(), false)); + ParseRec->addValue(RecordVal(B, ListType->getElementType(), false)); + Init *ExprUntyped = ParseValue(ParseRec); + ParseRec->removeValue(A); + ParseRec->removeValue(B); + if (!ExprUntyped) + return nullptr; + + TypedInit *Expr = dyn_cast<TypedInit>(ExprUntyped); + if (!Expr) { + TokError("could not get type of !foldl expression"); + return nullptr; + } + + if (Expr->getType() != Start->getType()) { + TokError(Twine("!foldl expression must be of same type as start (") + + Start->getType()->getAsString() + "), but is of type " + + Expr->getType()->getAsString()); + return nullptr; + } + + if (Lex.getCode() != tgtok::r_paren) { + TokError("expected ')' in fold operator"); + return nullptr; + } + Lex.Lex(); // eat the ')' + + return FoldOpInit::get(Start, List, A, B, Expr, Start->getType()) + ->Fold(CurRec); } } } @@ -1204,60 +1684,49 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, return nullptr; } - SubClassReference SCRef; - ParseValueList(SCRef.TemplateArgs, CurRec, Class); - if (SCRef.TemplateArgs.empty()) return nullptr; + SmallVector<Init *, 8> Args; + ParseValueList(Args, CurRec, Class); + if (Args.empty()) return nullptr; if (Lex.getCode() != tgtok::greater) { TokError("expected '>' at end of value list"); return nullptr; } Lex.Lex(); // eat the '>' - SMLoc EndLoc = Lex.getLoc(); - - // Create the new record, set it as CurRec temporarily. - auto NewRecOwner = llvm::make_unique<Record>(GetNewAnonymousName(), NameLoc, - Records, /*IsAnonymous=*/true); - Record *NewRec = NewRecOwner.get(); // Keep a copy since we may release. - SCRef.RefRange = SMRange(NameLoc, EndLoc); - SCRef.Rec = Class; - // Add info about the subclass to NewRec. - if (AddSubClass(NewRec, SCRef)) - return nullptr; - if (!CurMultiClass) { - NewRec->resolveReferences(); - Records.addDef(std::move(NewRecOwner)); - } else { - // This needs to get resolved once the multiclass template arguments are - // known before any use. - NewRec->setResolveFirst(true); - // Otherwise, we're inside a multiclass, add it to the multiclass. - CurMultiClass->DefPrototypes.push_back(std::move(NewRecOwner)); - - // Copy the template arguments for the multiclass into the def. - for (Init *TArg : CurMultiClass->Rec.getTemplateArgs()) { - const RecordVal *RV = CurMultiClass->Rec.getValue(TArg); - assert(RV && "Template arg doesn't exist?"); - NewRec->addValue(*RV); - } + // Typecheck the template arguments list + ArrayRef<Init *> ExpectedArgs = Class->getTemplateArgs(); + if (ExpectedArgs.size() < Args.size()) { + Error(NameLoc, + "More template args specified than expected"); + return nullptr; + } - // We can't return the prototype def here, instead return: - // !cast<ItemType>(!strconcat(NAME, AnonName)). - const RecordVal *MCNameRV = CurMultiClass->Rec.getValue("NAME"); - assert(MCNameRV && "multiclass record must have a NAME"); + for (unsigned i = 0, e = ExpectedArgs.size(); i != e; ++i) { + RecordVal *ExpectedArg = Class->getValue(ExpectedArgs[i]); + if (i < Args.size()) { + if (TypedInit *TI = dyn_cast<TypedInit>(Args[i])) { + RecTy *ExpectedType = ExpectedArg->getType(); + if (!TI->getType()->typeIsConvertibleTo(ExpectedType)) { + Error(NameLoc, + "Value specified for template argument #" + Twine(i) + " (" + + ExpectedArg->getNameInitAsString() + ") is of type '" + + TI->getType()->getAsString() + "', expected '" + + ExpectedType->getAsString() + "': " + TI->getAsString()); + return nullptr; + } + continue; + } + } else if (ExpectedArg->getValue()->isComplete()) + continue; - return UnOpInit::get(UnOpInit::CAST, - BinOpInit::get(BinOpInit::STRCONCAT, - VarInit::get(MCNameRV->getName(), - MCNameRV->getType()), - NewRec->getNameInit(), - StringRecTy::get()), - Class->getDefInit()->getType()); + Error(NameLoc, + "Value not specified for template argument #" + Twine(i) + " (" + + ExpectedArgs[i]->getAsUnquotedString() + ")"); + return nullptr; } - // The result of the expression is a reference to the new record. - return DefInit::get(NewRec); + return VarDefInit::get(Class, Args)->Fold(); } case tgtok::l_brace: { // Value ::= '{' ValueList '}' SMLoc BraceLoc = Lex.getLoc(); @@ -1299,7 +1768,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, // Fallthrough to try convert this to a bit. } // All other values must be convertible to just a single bit. - Init *Bit = Vals[i]->convertInitializerTo(BitRecTy::get()); + Init *Bit = Vals[i]->getCastTo(BitRecTy::get()); if (!Bit) { Error(BraceLoc, "Element #" + Twine(i) + " (" + Vals[i]->getAsString() + ") is not convertable to a bit"); @@ -1360,18 +1829,16 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, RecTy *EltTy = nullptr; for (Init *V : Vals) { TypedInit *TArg = dyn_cast<TypedInit>(V); - if (!TArg) { - TokError("Untyped list element"); - return nullptr; - } - if (EltTy) { - EltTy = resolveTypes(EltTy, TArg->getType()); - if (!EltTy) { - TokError("Incompatible types in list elements"); - return nullptr; + if (TArg) { + if (EltTy) { + EltTy = resolveTypes(EltTy, TArg->getType()); + if (!EltTy) { + TokError("Incompatible types in list elements"); + return nullptr; + } + } else { + EltTy = TArg->getType(); } - } else { - EltTy = TArg->getType(); } } @@ -1396,7 +1863,9 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, // Make sure the deduced type is compatible with the given type if (GivenListTy) { if (!EltTy->typeIsConvertibleTo(GivenListTy->getElementType())) { - TokError("Element type mismatch for list"); + TokError(Twine("Element type mismatch for list: element type '") + + EltTy->getAsString() + "' not convertible to '" + + GivenListTy->getElementType()->getAsString()); return nullptr; } } @@ -1443,9 +1912,12 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, case tgtok::XHead: case tgtok::XTail: + case tgtok::XSize: case tgtok::XEmpty: case tgtok::XCast: // Value ::= !unop '(' Value ')' + case tgtok::XIsA: case tgtok::XConcat: + case tgtok::XDag: case tgtok::XADD: case tgtok::XAND: case tgtok::XOR: @@ -1453,9 +1925,15 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, 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::XStrConcat: // Value ::= !binop '(' Value ',' Value ')' case tgtok::XIf: + case tgtok::XFoldl: case tgtok::XForEach: case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')' return ParseOperation(CurRec, ItemType); @@ -1481,7 +1959,7 @@ Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) { switch (Lex.getCode()) { default: return Result; case tgtok::l_brace: { - if (Mode == ParseNameMode || Mode == ParseForeachMode) + if (Mode == ParseNameMode) // This is the beginning of the object body. return Result; @@ -1539,7 +2017,7 @@ Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) { Result->getAsString() + "'"); return nullptr; } - Result = FieldInit::get(Result, FieldName); + Result = FieldInit::get(Result, FieldName)->Fold(CurRec); Lex.Lex(); // eat field name break; } @@ -1557,13 +2035,20 @@ Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) { } if (LHS->getType() != StringRecTy::get()) { - LHS = UnOpInit::get(UnOpInit::CAST, LHS, StringRecTy::get()); + LHS = dyn_cast<TypedInit>( + UnOpInit::get(UnOpInit::CAST, LHS, StringRecTy::get()) + ->Fold(CurRec)); + if (!LHS) { + Error(PasteLoc, Twine("can't cast '") + LHS->getAsString() + + "' to string"); + return nullptr; + } } TypedInit *RHS = nullptr; Lex.Lex(); // Eat the '#'. - switch (Lex.getCode()) { + switch (Lex.getCode()) { case tgtok::colon: case tgtok::semi: case tgtok::l_brace: @@ -1576,7 +2061,7 @@ Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) { break; default: - Init *RHSResult = ParseValue(CurRec, ItemType, ParseNameMode); + Init *RHSResult = ParseValue(CurRec, nullptr, ParseNameMode); RHS = dyn_cast<TypedInit>(RHSResult); if (!RHS) { Error(PasteLoc, "RHS of paste is not typed!"); @@ -1584,14 +2069,20 @@ Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) { } if (RHS->getType() != StringRecTy::get()) { - RHS = UnOpInit::get(UnOpInit::CAST, RHS, StringRecTy::get()); + RHS = dyn_cast<TypedInit>( + UnOpInit::get(UnOpInit::CAST, RHS, StringRecTy::get()) + ->Fold(CurRec)); + if (!RHS) { + Error(PasteLoc, Twine("can't cast '") + RHS->getAsString() + + "' to string"); + return nullptr; + } } break; } - Result = BinOpInit::get(BinOpInit::STRCONCAT, LHS, RHS, - StringRecTy::get())->Fold(CurRec, CurMultiClass); + Result = BinOpInit::getStrConcat(LHS, RHS); break; } } @@ -1720,8 +2211,14 @@ Init *TGParser::ParseDeclaration(Record *CurRec, 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(Lex.getCurStrVal()); + Init *DeclName = StringInit::get(Str); Lex.Lex(); if (ParsingTemplateArgs) { @@ -1758,11 +2255,11 @@ Init *TGParser::ParseDeclaration(Record *CurRec, /// the name of the declared object or a NULL Init on error. Return /// the name of the parsed initializer list through ForeachListName. /// -/// ForeachDeclaration ::= ID '=' '[' ValueList ']' /// ForeachDeclaration ::= ID '=' '{' RangeList '}' /// ForeachDeclaration ::= ID '=' RangePiece +/// ForeachDeclaration ::= ID '=' Value /// -VarInit *TGParser::ParseForeachDeclaration(ListInit *&ForeachListValue) { +VarInit *TGParser::ParseForeachDeclaration(Init *&ForeachListValue) { if (Lex.getCode() != tgtok::Id) { TokError("Expected identifier in foreach declaration"); return nullptr; @@ -1782,24 +2279,6 @@ VarInit *TGParser::ParseForeachDeclaration(ListInit *&ForeachListValue) { SmallVector<unsigned, 16> Ranges; switch (Lex.getCode()) { - default: TokError("Unknown token when expecting a range list"); return nullptr; - case tgtok::l_square: { // '[' ValueList ']' - Init *List = ParseSimpleValue(nullptr, nullptr, ParseForeachMode); - ForeachListValue = dyn_cast<ListInit>(List); - if (!ForeachListValue) { - TokError("Expected a Value list"); - return nullptr; - } - RecTy *ValueType = ForeachListValue->getType(); - ListRecTy *ListType = dyn_cast<ListRecTy>(ValueType); - if (!ListType) { - TokError("Value list is not of list type"); - return nullptr; - } - IterType = ListType->getElementType(); - break; - } - case tgtok::IntVal: { // RangePiece. if (ParseRangePiece(Ranges)) return nullptr; @@ -1816,6 +2295,25 @@ VarInit *TGParser::ParseForeachDeclaration(ListInit *&ForeachListValue) { Lex.Lex(); break; } + + default: { + SMLoc ValueLoc = Lex.getLoc(); + Init *I = ParseValue(nullptr); + TypedInit *TI = dyn_cast<TypedInit>(I); + if (!TI || !isa<ListRecTy>(TI->getType())) { + std::string Type; + if (TI) + Type = (Twine("' of type '") + TI->getType()->getAsString()).str(); + Error(ValueLoc, "expected a list, got '" + I->getAsString() + Type + "'"); + if (CurMultiClass) + PrintNote({}, "references to multiclass template arguments cannot be " + "resolved at this time"); + return nullptr; + } + ForeachListValue = I; + IterType = cast<ListRecTy>(TI->getType())->getElementType(); + break; + } } if (!Ranges.empty()) { @@ -1857,9 +2355,15 @@ bool TGParser::ParseTemplateArgList(Record *CurRec) { Lex.Lex(); // eat the ',' // 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); } @@ -1945,7 +2449,7 @@ bool TGParser::ParseBody(Record *CurRec) { return false; } -/// \brief Apply the current let bindings to \a CurRec. +/// Apply the current let bindings to \a CurRec. /// \returns true on error, false otherwise. bool TGParser::ApplyLetStack(Record *CurRec) { for (SmallVectorImpl<LetRecord> &LetInfo : LetStack) @@ -1955,6 +2459,18 @@ bool TGParser::ApplyLetStack(Record *CurRec) { return false; } +bool TGParser::ApplyLetStack(RecordsEntry &Entry) { + if (Entry.Rec) + return ApplyLetStack(Entry.Rec.get()); + + for (auto &E : Entry.Loop->Entries) { + if (ApplyLetStack(E)) + return true; + } + + return false; +} + /// ParseObjectBody - Parse the body of a def or class. This consists of an /// optional ClassList followed by a Body. CurRec is the current def or class /// that is being parsed. @@ -2002,67 +2518,67 @@ bool TGParser::ParseDef(MultiClass *CurMultiClass) { Lex.Lex(); // Eat the 'def' token. // Parse ObjectName and make a record for it. - std::unique_ptr<Record> CurRecOwner; + std::unique_ptr<Record> CurRec; Init *Name = ParseObjectName(CurMultiClass); - if (Name) - CurRecOwner = make_unique<Record>(Name, DefLoc, Records); + if (!Name) + return true; + + if (isa<UnsetInit>(Name)) + CurRec = make_unique<Record>(Records.getNewAnonymousName(), DefLoc, Records, + /*Anonymous=*/true); else - CurRecOwner = llvm::make_unique<Record>(GetNewAnonymousName(), DefLoc, - Records, /*IsAnonymous=*/true); - Record *CurRec = CurRecOwner.get(); // Keep a copy since we may release. + CurRec = make_unique<Record>(Name, DefLoc, Records); - if (!CurMultiClass && Loops.empty()) { - // Top-level def definition. + if (ParseObjectBody(CurRec.get())) + return true; - // Ensure redefinition doesn't happen. - if (Records.getDef(CurRec->getNameInitAsString())) - return Error(DefLoc, "def '" + CurRec->getNameInitAsString()+ - "' already defined"); - Records.addDef(std::move(CurRecOwner)); + return addEntry(std::move(CurRec)); +} - if (ParseObjectBody(CurRec)) - return true; - } else if (CurMultiClass) { - // Parse the body before adding this prototype to the DefPrototypes vector. - // That way implicit definitions will be added to the DefPrototypes vector - // before this object, instantiated prior to defs derived from this object, - // and this available for indirect name resolution when defs derived from - // this object are instantiated. - if (ParseObjectBody(CurRec)) - return true; +/// ParseDefset - Parse a defset statement. +/// +/// Defset ::= DEFSET Type Id '=' '{' ObjectList '}' +/// +bool TGParser::ParseDefset() { + assert(Lex.getCode() == tgtok::Defset); + Lex.Lex(); // Eat the 'defset' token - // Otherwise, a def inside a multiclass, add it to the multiclass. - for (const auto &Proto : CurMultiClass->DefPrototypes) - if (Proto->getNameInit() == CurRec->getNameInit()) - return Error(DefLoc, "def '" + CurRec->getNameInitAsString() + - "' already defined in this multiclass!"); - CurMultiClass->DefPrototypes.push_back(std::move(CurRecOwner)); - } else if (ParseObjectBody(CurRec)) { + DefsetRecord Defset; + Defset.Loc = Lex.getLoc(); + RecTy *Type = ParseType(); + if (!Type) return true; - } - - if (!CurMultiClass) // Def's in multiclasses aren't really defs. - // See Record::setName(). This resolve step will see any new name - // for the def that might have been created when resolving - // inheritance, values and arguments above. - CurRec->resolveReferences(); + if (!isa<ListRecTy>(Type)) + return Error(Defset.Loc, "expected list type"); + Defset.EltTy = cast<ListRecTy>(Type)->getElementType(); - // If ObjectBody has template arguments, it's an error. - assert(CurRec->getTemplateArgs().empty() && "How'd this get template args?"); + 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 (CurMultiClass) { - // Copy the template arguments for the multiclass into the def. - for (Init *TArg : CurMultiClass->Rec.getTemplateArgs()) { - const RecordVal *RV = CurMultiClass->Rec.getValue(TArg); - assert(RV && "Template arg doesn't exist?"); - CurRec->addValue(*RV); - } + if (Lex.getCode() != tgtok::r_brace) { + TokError("expected '}' at end of defset"); + return Error(BraceLoc, "to match this '{'"); } + Lex.Lex(); // Eat the '}' - if (ProcessForeachDefs(CurRec, DefLoc)) - return Error(DefLoc, "Could not process loops for def" + - CurRec->getNameInitAsString()); - + Records.addExtraGlobal(DeclName->getValue(), + ListInit::get(Defset.Elements, Defset.EltTy)); return false; } @@ -2073,12 +2589,13 @@ bool TGParser::ParseDef(MultiClass *CurMultiClass) { /// 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. - ListInit *ListValue = nullptr; + Init *ListValue = nullptr; VarInit *IterName = ParseForeachDeclaration(ListValue); if (!IterName) return TokError("expected declaration in for"); @@ -2088,7 +2605,7 @@ bool TGParser::ParseForeach(MultiClass *CurMultiClass) { Lex.Lex(); // Eat the in // Create a loop object and remember it. - Loops.push_back(ForeachLoop(IterName, ListValue)); + Loops.push_back(llvm::make_unique<ForeachLoop>(Loc, IterName, ListValue)); if (Lex.getCode() != tgtok::l_brace) { // FOREACH Declaration IN Object @@ -2110,10 +2627,11 @@ bool TGParser::ParseForeach(MultiClass *CurMultiClass) { Lex.Lex(); // Eat the } } - // We've processed everything in this loop. + // Resolve the loop or store it for later resolution. + std::unique_ptr<ForeachLoop> Loop = std::move(Loops.back()); Loops.pop_back(); - return false; + return addEntry(std::move(Loop)); } /// ParseClass - Parse a tblgen class definition. @@ -2130,7 +2648,7 @@ bool TGParser::ParseClass() { Record *CurRec = Records.getClass(Lex.getCurStrVal()); if (CurRec) { // If the body was previously defined, this is an error. - if (CurRec->getValues().size() > 1 || // Account for NAME. + if (!CurRec->getValues().empty() || !CurRec->getSuperClasses().empty() || !CurRec->getTemplateArgs().empty()) return TokError("Class '" + CurRec->getNameInitAsString() + @@ -2138,7 +2656,8 @@ bool TGParser::ParseClass() { } else { // If this is the first reference to this class, create and add it. auto NewRec = - llvm::make_unique<Record>(Lex.getCurStrVal(), Lex.getLoc(), Records); + llvm::make_unique<Record>(Lex.getCurStrVal(), Lex.getLoc(), Records, + /*Class=*/true); CurRec = NewRec.get(); Records.addClass(std::move(NewRec)); } @@ -2149,7 +2668,6 @@ bool TGParser::ParseClass() { if (ParseTemplateArgList(CurRec)) return true; - // Finally, parse the object body. return ParseObjectBody(CurRec); } @@ -2318,7 +2836,8 @@ bool TGParser::ParseMultiClass() { while (Lex.getCode() != tgtok::r_brace) { switch (Lex.getCode()) { default: - return TokError("expected 'let', 'def' or 'defm' in multiclass body"); + return TokError("expected 'let', 'def', 'defm' or 'foreach' in " + "multiclass body"); case tgtok::Let: case tgtok::Def: case tgtok::Defm: @@ -2335,207 +2854,31 @@ bool TGParser::ParseMultiClass() { return false; } -Record *TGParser::InstantiateMulticlassDef(MultiClass &MC, Record *DefProto, - Init *&DefmPrefix, - SMRange DefmPrefixRange, - ArrayRef<Init *> TArgs, - ArrayRef<Init *> TemplateVals) { - // We need to preserve DefProto so it can be reused for later - // instantiations, so create a new Record to inherit from it. - - // Add in the defm name. If the defm prefix is empty, give each - // instantiated def a unique name. Otherwise, if "#NAME#" exists in the - // name, substitute the prefix for #NAME#. Otherwise, use the defm name - // as a prefix. - - bool IsAnonymous = false; - if (!DefmPrefix) { - DefmPrefix = GetNewAnonymousName(); - IsAnonymous = true; - } - - Init *DefName = DefProto->getNameInit(); - StringInit *DefNameString = dyn_cast<StringInit>(DefName); - - if (DefNameString) { - // We have a fully expanded string so there are no operators to - // resolve. We should concatenate the given prefix and name. - DefName = - BinOpInit::get(BinOpInit::STRCONCAT, - UnOpInit::get(UnOpInit::CAST, DefmPrefix, - StringRecTy::get())->Fold(DefProto, &MC), - DefName, StringRecTy::get())->Fold(DefProto, &MC); - } - - // Make a trail of SMLocs from the multiclass instantiations. - SmallVector<SMLoc, 4> Locs(1, DefmPrefixRange.Start); - Locs.append(DefProto->getLoc().begin(), DefProto->getLoc().end()); - auto CurRec = make_unique<Record>(DefName, Locs, Records, IsAnonymous); - - SubClassReference Ref; - Ref.RefRange = DefmPrefixRange; - Ref.Rec = DefProto; - AddSubClass(CurRec.get(), Ref); - - // Set the value for NAME. We don't resolve references to it 'til later, - // though, so that uses in nested multiclass names don't get - // confused. - if (SetValue(CurRec.get(), Ref.RefRange.Start, StringInit::get("NAME"), None, - DefmPrefix, /*AllowSelfAssignment*/true)) { - Error(DefmPrefixRange.Start, "Could not resolve " + - CurRec->getNameInitAsString() + ":NAME to '" + - DefmPrefix->getAsUnquotedString() + "'"); - return nullptr; - } - - // If the DefNameString didn't resolve, we probably have a reference to - // NAME and need to replace it. We need to do at least this much greedily, - // otherwise nested multiclasses will end up with incorrect NAME expansions. - if (!DefNameString) { - RecordVal *DefNameRV = CurRec->getValue("NAME"); - CurRec->resolveReferencesTo(DefNameRV); - } - - if (!CurMultiClass) { - // Now that we're at the top level, resolve all NAME references - // in the resultant defs that weren't in the def names themselves. - RecordVal *DefNameRV = CurRec->getValue("NAME"); - CurRec->resolveReferencesTo(DefNameRV); - - // Check if the name is a complex pattern. - // If so, resolve it. - DefName = CurRec->getNameInit(); - DefNameString = dyn_cast<StringInit>(DefName); - - // OK the pattern is more complex than simply using NAME. - // Let's use the heavy weaponery. - if (!DefNameString) { - ResolveMulticlassDefArgs(MC, CurRec.get(), DefmPrefixRange.Start, - Lex.getLoc(), TArgs, TemplateVals, - false/*Delete args*/); - DefName = CurRec->getNameInit(); - DefNameString = dyn_cast<StringInit>(DefName); - - if (!DefNameString) - DefName = DefName->convertInitializerTo(StringRecTy::get()); - - // We ran out of options here... - DefNameString = dyn_cast<StringInit>(DefName); - if (!DefNameString) { - PrintFatalError(CurRec->getLoc()[CurRec->getLoc().size() - 1], - DefName->getAsUnquotedString() + " is not a string."); - return nullptr; - } - - CurRec->setName(DefName); - } - - // Now that NAME references are resolved and we're at the top level of - // any multiclass expansions, add the record to the RecordKeeper. If we are - // currently in a multiclass, it means this defm appears inside a - // multiclass and its name won't be fully resolvable until we see - // the top-level defm. Therefore, we don't add this to the - // RecordKeeper at this point. If we did we could get duplicate - // defs as more than one probably refers to NAME or some other - // common internal placeholder. - - // Ensure redefinition doesn't happen. - if (Records.getDef(CurRec->getNameInitAsString())) { - Error(DefmPrefixRange.Start, "def '" + CurRec->getNameInitAsString() + - "' already defined, instantiating defm with subdef '" + - DefProto->getNameInitAsString() + "'"); - return nullptr; - } - - Record *CurRecSave = CurRec.get(); // Keep a copy before we release. - Records.addDef(std::move(CurRec)); - return CurRecSave; - } - - // FIXME This is bad but the ownership transfer to caller is pretty messy. - // The unique_ptr in this function at least protects the exits above. - return CurRec.release(); -} - -bool TGParser::ResolveMulticlassDefArgs(MultiClass &MC, Record *CurRec, - SMLoc DefmPrefixLoc, SMLoc SubClassLoc, - ArrayRef<Init *> TArgs, - ArrayRef<Init *> TemplateVals, - bool DeleteArgs) { - // Loop over all of the template arguments, setting them to the specified - // value or leaving them as the default if necessary. - for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { - // Check if a value is specified for this temp-arg. - if (i < TemplateVals.size()) { - // Set it now. - if (SetValue(CurRec, DefmPrefixLoc, TArgs[i], None, TemplateVals[i])) - return true; - - // Resolve it next. - CurRec->resolveReferencesTo(CurRec->getValue(TArgs[i])); - - if (DeleteArgs) - // Now remove it. - CurRec->removeValue(TArgs[i]); - - } else if (!CurRec->getValue(TArgs[i])->getValue()->isComplete()) { - return Error(SubClassLoc, "value not specified for template argument #" + - Twine(i) + " (" + TArgs[i]->getAsUnquotedString() + - ") of multiclassclass '" + MC.Rec.getNameInitAsString() + - "'"); - } - } - return false; -} - -bool TGParser::ResolveMulticlassDef(MultiClass &MC, - Record *CurRec, - Record *DefProto, - SMLoc DefmPrefixLoc) { - // If the mdef is inside a 'let' expression, add to each def. - if (ApplyLetStack(CurRec)) - return Error(DefmPrefixLoc, "when instantiating this defm"); - - // Don't create a top level definition for defm inside multiclasses, - // instead, only update the prototypes and bind the template args - // with the new created definition. - if (!CurMultiClass) - return false; - for (const auto &Proto : CurMultiClass->DefPrototypes) - if (Proto->getNameInit() == CurRec->getNameInit()) - return Error(DefmPrefixLoc, "defm '" + CurRec->getNameInitAsString() + - "' already defined in this multiclass!"); - CurMultiClass->DefPrototypes.push_back(std::unique_ptr<Record>(CurRec)); - - // Copy the template arguments for the multiclass into the new def. - for (Init * TA : CurMultiClass->Rec.getTemplateArgs()) { - const RecordVal *RV = CurMultiClass->Rec.getValue(TA); - assert(RV && "Template arg doesn't exist?"); - CurRec->addValue(*RV); - } - - 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!"); - SMLoc DefmLoc = Lex.getLoc(); - Init *DefmPrefix = nullptr; + Lex.Lex(); // eat the defm - if (Lex.Lex() == tgtok::Id) { // eat the defm. - DefmPrefix = ParseObjectName(CurMultiClass); + Init *DefmName = ParseObjectName(CurMultiClass); + if (!DefmName) + return true; + if (isa<UnsetInit>(DefmName)) { + DefmName = Records.getNewAnonymousName(); + if (CurMultiClass) + DefmName = BinOpInit::getStrConcat( + VarInit::get(QualifiedNameOfImplicitName(CurMultiClass), + StringRecTy::get()), + DefmName); } - SMLoc DefmPrefixEndLoc = Lex.getLoc(); if (Lex.getCode() != tgtok::colon) return TokError("expected ':' after defm identifier"); // Keep track of the new generated record definitions. - std::vector<Record*> NewRecDefs; + std::vector<RecordsEntry> NewEntries; // This record also inherits from a regular class (non-multiclass)? bool InheritFromClass = false; @@ -2562,37 +2905,28 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) { return Error(SubClassLoc, "more template args specified than multiclass expects"); - // Loop over all the def's in the multiclass, instantiating each one. - for (const std::unique_ptr<Record> &DefProto : MC->DefPrototypes) { - // The record name construction goes as follow: - // - If the def name is a string, prepend the prefix. - // - If the def name is a more complex pattern, use that pattern. - // As a result, the record is instantiated before resolving - // arguments, as it would make its name a string. - Record *CurRec = InstantiateMulticlassDef(*MC, DefProto.get(), DefmPrefix, - SMRange(DefmLoc, - DefmPrefixEndLoc), - TArgs, TemplateVals); - if (!CurRec) - return true; - - // Now that the record is instantiated, we can resolve arguments. - if (ResolveMulticlassDefArgs(*MC, CurRec, DefmLoc, SubClassLoc, - TArgs, TemplateVals, true/*Delete args*/)) - return Error(SubClassLoc, "could not instantiate def"); - - if (ResolveMulticlassDef(*MC, CurRec, DefProto.get(), DefmLoc)) - return Error(SubClassLoc, "could not instantiate def"); - - // Defs that can be used by other definitions should be fully resolved - // before any use. - if (DefProto->isResolveFirst() && !CurMultiClass) { - CurRec->resolveReferences(); - CurRec->setResolveFirst(false); + SubstStack Substs; + for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { + if (i < TemplateVals.size()) { + Substs.emplace_back(TArgs[i], TemplateVals[i]); + } else { + Init *Default = MC->Rec.getValue(TArgs[i])->getValue(); + if (!Default->isComplete()) { + return Error(SubClassLoc, + "value not specified for template argument #" + + Twine(i) + " (" + TArgs[i]->getAsUnquotedString() + + ") of multiclass '" + MC->Rec.getNameInitAsString() + + "'"); + } + Substs.emplace_back(TArgs[i], Default); } - NewRecDefs.push_back(CurRec); } + Substs.emplace_back(QualifiedNameOfImplicitName(MC), DefmName); + + if (resolve(MC->Entries, Substs, CurMultiClass == nullptr, &NewEntries, + &SubClassLoc)) + return true; if (Lex.getCode() != tgtok::comma) break; Lex.Lex(); // eat ','. @@ -2622,12 +2956,9 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) { // Get the expanded definition prototypes and teach them about // the record values the current class to inherit has - for (Record *CurRec : NewRecDefs) { + for (auto &E : NewEntries) { // Add it. - if (AddSubClass(CurRec, SubClass)) - return true; - - if (ApplyLetStack(CurRec)) + if (AddSubClass(E, SubClass)) return true; } @@ -2637,12 +2968,12 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) { } } - if (!CurMultiClass) - for (Record *CurRec : NewRecDefs) - // See Record::setName(). This resolve step will see any new - // name for the def that might have been created when resolving - // inheritance, values and arguments above. - CurRec->resolveReferences(); + for (auto &E : NewEntries) { + if (ApplyLetStack(E)) + return true; + + addEntry(std::move(E)); + } if (Lex.getCode() != tgtok::semi) return TokError("expected ';' at end of defm"); @@ -2661,13 +2992,26 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) { bool TGParser::ParseObject(MultiClass *MC) { switch (Lex.getCode()) { default: - return TokError("Expected class, def, defm, multiclass or let definition"); + return TokError("Expected class, def, defm, defset, multiclass, let or " + "foreach"); case tgtok::Let: return ParseTopLevelLet(MC); case tgtok::Def: return ParseDef(MC); case tgtok::Foreach: return ParseForeach(MC); case tgtok::Defm: return ParseDefm(MC); - case tgtok::Class: return ParseClass(); - case tgtok::MultiClass: return ParseMultiClass(); + 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(); } } @@ -2691,3 +3035,31 @@ bool TGParser::ParseFile() { return TokError("Unexpected input at top level"); } + +#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 diff --git a/contrib/llvm/lib/TableGen/TGParser.h b/contrib/llvm/lib/TableGen/TGParser.h index 1b2966c9f6c9..0a28b3a03aa1 100644 --- a/contrib/llvm/lib/TableGen/TGParser.h +++ b/contrib/llvm/lib/TableGen/TGParser.h @@ -27,6 +27,7 @@ namespace llvm { class RecordKeeper; class RecTy; class Init; + struct ForeachLoop; struct MultiClass; struct SubClassReference; struct SubMultiClassReference; @@ -41,16 +42,49 @@ namespace llvm { } }; + /// RecordsEntry - Can be either a record or a foreach loop. + struct RecordsEntry { + std::unique_ptr<Record> Rec; + std::unique_ptr<ForeachLoop> Loop; + + void dump() const; + + RecordsEntry() {} + RecordsEntry(std::unique_ptr<Record> Rec) : Rec(std::move(Rec)) {} + RecordsEntry(std::unique_ptr<ForeachLoop> Loop) + : Loop(std::move(Loop)) {} + }; + /// ForeachLoop - Record the iteration state associated with a for loop. /// This is used to instantiate items in the loop body. struct ForeachLoop { + SMLoc Loc; VarInit *IterVar; - ListInit *ListValue; + Init *ListValue; + std::vector<RecordsEntry> Entries; - ForeachLoop(VarInit *IVar, ListInit *LValue) - : IterVar(IVar), ListValue(LValue) {} + void dump() const; + + ForeachLoop(SMLoc Loc, VarInit *IVar, Init *LValue) + : Loc(Loc), IterVar(IVar), ListValue(LValue) {} }; + struct DefsetRecord { + SMLoc Loc; + RecTy *EltTy; + SmallVector<Init *, 16> Elements; + }; + +struct MultiClass { + Record Rec; // Placeholder for template args and Name. + std::vector<RecordsEntry> Entries; + + void dump() const; + + MultiClass(StringRef Name, SMLoc Loc, RecordKeeper &Records) : + Rec(Name, Loc, Records) {} +}; + class TGParser { TGLexer Lex; std::vector<SmallVector<LetRecord, 4>> LetStack; @@ -58,8 +92,9 @@ class TGParser { /// Loops - Keep track of any foreach loops we are within. /// - typedef std::vector<ForeachLoop> LoopVector; - LoopVector Loops; + std::vector<std::unique_ptr<ForeachLoop>> Loops; + + SmallVector<DefsetRecord *, 2> Defsets; /// CurMultiClass - If we are parsing a 'multiclass' definition, this is the /// current value. @@ -68,8 +103,6 @@ class TGParser { // Record tracker RecordKeeper &Records; - unsigned AnonCounter; - // A "named boolean" indicating how to parse identifiers. Usually // identifiers map to some existing object but in special cases // (e.g. parsing def names) no such object exists yet because we are @@ -79,12 +112,11 @@ class TGParser { ParseValueMode, // We are parsing a value we expect to look up. ParseNameMode, // We are parsing a name of an object that does not yet // exist. - ParseForeachMode // We are parsing a foreach init. }; public: TGParser(SourceMgr &SrcMgr, RecordKeeper &records) - : Lex(SrcMgr), CurMultiClass(nullptr), Records(records), AnonCounter(0) {} + : Lex(SrcMgr), CurMultiClass(nullptr), Records(records) {} /// ParseFile - Main entrypoint for parsing a tblgen file. These parser /// routines return true on error, or false on success. @@ -107,44 +139,28 @@ private: // Semantic analysis methods. ArrayRef<unsigned> BitList, Init *V, bool AllowSelfAssignment = false); bool AddSubClass(Record *Rec, SubClassReference &SubClass); + bool AddSubClass(RecordsEntry &Entry, SubClassReference &SubClass); bool AddSubMultiClass(MultiClass *CurMC, SubMultiClassReference &SubMultiClass); - Init *GetNewAnonymousName(); - - // IterRecord: Map an iterator name to a value. - struct IterRecord { - VarInit *IterVar; - Init *IterValue; - IterRecord(VarInit *Var, Init *Val) : IterVar(Var), IterValue(Val) {} - }; - - // IterSet: The set of all iterator values at some point in the - // iteration space. - typedef std::vector<IterRecord> IterSet; + using SubstStack = SmallVector<std::pair<Init *, Init *>, 8>; - bool ProcessForeachDefs(Record *CurRec, SMLoc Loc); - bool ProcessForeachDefs(Record *CurRec, SMLoc Loc, IterSet &IterVals); + bool addEntry(RecordsEntry E); + bool resolve(const ForeachLoop &Loop, SubstStack &Stack, bool Final, + std::vector<RecordsEntry> *Dest, SMLoc *Loc = nullptr); + bool resolve(const std::vector<RecordsEntry> &Source, SubstStack &Substs, + bool Final, std::vector<RecordsEntry> *Dest, + SMLoc *Loc = nullptr); + bool addDefOne(std::unique_ptr<Record> Rec); private: // Parser methods. bool ParseObjectList(MultiClass *MC = nullptr); bool ParseObject(MultiClass *MC); bool ParseClass(); bool ParseMultiClass(); - Record *InstantiateMulticlassDef(MultiClass &MC, Record *DefProto, - Init *&DefmPrefix, SMRange DefmPrefixRange, - ArrayRef<Init *> TArgs, - ArrayRef<Init *> TemplateVals); - bool ResolveMulticlassDefArgs(MultiClass &MC, Record *DefProto, - SMLoc DefmPrefixLoc, SMLoc SubClassLoc, - ArrayRef<Init *> TArgs, - ArrayRef<Init *> TemplateVals, bool DeleteArgs); - bool ResolveMulticlassDef(MultiClass &MC, - Record *CurRec, - Record *DefProto, - SMLoc DefmPrefixLoc); bool ParseDefm(MultiClass *CurMultiClass); bool ParseDef(MultiClass *CurMultiClass); + bool ParseDefset(); bool ParseForeach(MultiClass *CurMultiClass); bool ParseTopLevelLet(MultiClass *CurMultiClass); void ParseLetList(SmallVectorImpl<LetRecord> &Result); @@ -155,7 +171,7 @@ private: // Parser methods. bool ParseTemplateArgList(Record *CurRec); Init *ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs); - VarInit *ParseForeachDeclaration(ListInit *&ForeachListValue); + VarInit *ParseForeachDeclaration(Init *&ForeachListValue); SubClassReference ParseSubClassReference(Record *CurRec, bool isDefm); SubMultiClassReference ParseSubMultiClassReference(MultiClass *CurMC); @@ -182,6 +198,7 @@ private: // Parser methods. Record *ParseClassID(); MultiClass *ParseMultiClassID(); bool ApplyLetStack(Record *CurRec); + bool ApplyLetStack(RecordsEntry &Entry); }; } // end namespace llvm |