summaryrefslogtreecommitdiff
path: root/llvm/lib/TableGen
diff options
context:
space:
mode:
authorNicolai Haehnle <nhaehnle@gmail.com>2018-03-06 13:49:01 +0000
committerNicolai Haehnle <nhaehnle@gmail.com>2018-03-06 13:49:01 +0000
commitce2a4673a5fb4538a008424d9bb3317aeb061c19 (patch)
tree7edf9735f39987b3997db23a0349633a2d564357 /llvm/lib/TableGen
parentce8c46b7e9899b80f75ae274e91bdd77801d483d (diff)
TableGen: Delay instantiating inline anonymous records
Summary: Only instantiate anonymous records once all variable references in template arguments have been resolved. This allows patterns like the new test case, which in practice can appear in expressions like: class IntrinsicTypeProfile<list<LLVMType> ty, int shift> { list<LLVMType> types = !listconcat(ty, [llvm_any_ty, LLVMMatchType<shift>]); } class FooIntrinsic<IntrinsicTypeProfile P, ...> : Intrinsic<..., P.types, ...>; Without this change, the anonymous LLVMMatchType instantiation would never get resolved. Another consequence of this change is that anonymous inline instantiations are uniqued via the folding set of the newly introduced VarDefInit. Change-Id: I7a7041a20e297cf98c9109b28d85e64e176c932a Reviewers: arsenm, craig.topper, tra, MartinO Subscribers: wdng, llvm-commits Differential Revision: https://reviews.llvm.org/D43756
Diffstat (limited to 'llvm/lib/TableGen')
-rw-r--r--llvm/lib/TableGen/Record.cpp146
-rw-r--r--llvm/lib/TableGen/TGParser.cpp76
2 files changed, 178 insertions, 44 deletions
diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index dac12d7d506..2fe58dd61d0 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -1355,6 +1355,132 @@ 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()) {
+ if (Val.getName() != "NAME")
+ 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;
@@ -1917,3 +2043,23 @@ Init *RecordResolver::resolve(Init *VarName) {
Cache[VarName] = Val;
return Val;
}
+
+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 (!I)
+ FoundUnresolved = true;
+ return I;
+}
diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 642812d5ceb..654b4fd1ce5 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -1346,61 +1346,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 =
- make_unique<Record>(Records.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()),
- NewRec->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();