aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/lib/TableGen
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/TableGen')
-rw-r--r--contrib/llvm/lib/TableGen/Error.cpp9
-rw-r--r--contrib/llvm/lib/TableGen/JSONBackend.cpp189
-rw-r--r--contrib/llvm/lib/TableGen/Main.cpp2
-rw-r--r--contrib/llvm/lib/TableGen/Record.cpp1400
-rw-r--r--contrib/llvm/lib/TableGen/TGLexer.cpp60
-rw-r--r--contrib/llvm/lib/TableGen/TGLexer.h23
-rw-r--r--contrib/llvm/lib/TableGen/TGParser.cpp1586
-rw-r--r--contrib/llvm/lib/TableGen/TGParser.h89
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