Index: include/llvm/TableGen/Record.h =================================================================== --- include/llvm/TableGen/Record.h +++ include/llvm/TableGen/Record.h @@ -1370,9 +1370,8 @@ init(); } - explicit Record(StringRef N, ArrayRef locs, RecordKeeper &records, - bool Anonymous = false) - : Record(StringInit::get(N), locs, records, Anonymous) {} + explicit Record(StringRef N, ArrayRef locs, RecordKeeper &records) + : Record(StringInit::get(N), locs, records) {} // When copy-constructing a Record, we must still guarantee a globally unique // ID number. Don't copy TheInit either since it's owned by the original @@ -1400,6 +1399,10 @@ void setName(Init *Name); // Also updates RecordKeeper. ArrayRef getLoc() const { return Locs; } + void appendLoc(SMLoc Loc) { Locs.push_back(Loc); } + + // Make the type that this record should have based on its superclasses. + RecordRecTy *getType(); /// get the corresponding DefInit. DefInit *getDefInit(); @@ -1491,6 +1494,7 @@ } void addSuperClass(Record *R, SMRange Range) { + assert(!TheInit && "changing type of record after it has been referenced"); assert(!isSubClassOf(R) && "Already subclassing record!"); SuperClasses.push_back(std::make_pair(R, Range)); } Index: lib/TableGen/Record.cpp =================================================================== --- lib/TableGen/Record.cpp +++ lib/TableGen/Record.cpp @@ -1508,14 +1508,8 @@ return VarBitInit::get(const_cast(this), Bit); } -static RecordRecTy *makeDefInitType(Record *Rec) { - SmallVector SuperClasses; - Rec->getDirectSuperClasses(SuperClasses); - return RecordRecTy::get(SuperClasses); -} - DefInit::DefInit(Record *D) - : TypedInit(IK_DefInit, makeDefInitType(D)), Def(D) {} + : TypedInit(IK_DefInit, D->getType()), Def(D) {} DefInit *DefInit::get(Record *R) { return R->getDefInit(); @@ -1865,7 +1859,14 @@ // Ensure the record name has string type. const TypedInit *TypedName = cast(Name); if (!isa(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 DirectSCs; + getDirectSuperClasses(DirectSCs); + return RecordRecTy::get(DirectSCs); } DefInit *Record::getDefInit() { Index: lib/TableGen/TGParser.h =================================================================== --- lib/TableGen/TGParser.h +++ lib/TableGen/TGParser.h @@ -126,28 +126,16 @@ // iteration space. typedef std::vector IterSet; - bool ProcessForeachDefs(Record *CurRec, SMLoc Loc); - bool ProcessForeachDefs(Record *CurRec, SMLoc Loc, IterSet &IterVals); - - bool addToDefsets(Record &R); + bool addDefOne(std::unique_ptr Rec, Init *DefmName, + IterSet &IterVals); + bool addDefForeach(Record *Rec, Init *DefmName, IterSet &IterVals); + bool addDef(std::unique_ptr Rec, Init *DefmName); 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 TArgs, - ArrayRef TemplateVals); - bool ResolveMulticlassDefArgs(MultiClass &MC, Record *DefProto, - SMLoc DefmPrefixLoc, SMLoc SubClassLoc, - ArrayRef TArgs, - ArrayRef TemplateVals, bool DeleteArgs); - bool ResolveMulticlassDef(MultiClass &MC, - Record *CurRec, - Record *DefProto, - SMLoc DefmPrefixLoc); bool ParseDefm(MultiClass *CurMultiClass); bool ParseDef(MultiClass *CurMultiClass); bool ParseDefset(); Index: lib/TableGen/TGParser.cpp =================================================================== --- lib/TableGen/TGParser.cpp +++ lib/TableGen/TGParser.cpp @@ -337,40 +337,32 @@ return false; } -/// 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) { +/// Add a record that results from 'def' or 'defm', after template arguments +/// and the external let stack have been resolved. +/// +/// Apply foreach loops, resolve internal variable references, and add to the +/// current multi class or the global record keeper as appropriate. +bool TGParser::addDef(std::unique_ptr Rec, Init *DefmName) { + IterSet IterVals; + if (Loops.empty()) - return false; + return addDefOne(std::move(Rec), DefmName, IterVals); - // 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 addDefForeach(Rec.get(), DefmName, IterVals); } -/// 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. +/// Recursive helper function for addDef/addDefOne to resolve references to +/// foreach variables. +bool TGParser::addDefForeach(Record *Rec, Init *DefmName, IterSet &IterVals) { if (IterVals.size() != Loops.size()) { assert(IterVals.size() < Loops.size()); ForeachLoop &CurLoop = Loops[IterVals.size()]; - ListInit *List = dyn_cast(CurLoop.ListValue); - if (!List) { - Error(Loc, "Loop list is not a list"); - return true; - } + ListInit *List = CurLoop.ListValue; // Process each value. for (unsigned i = 0; i < List->size(); ++i) { - RecordResolver R(*CurRec); - Init *ItemVal = List->getElement(i)->resolveReferences(R); - IterVals.push_back(IterRecord(CurLoop.IterVar, ItemVal)); - if (ProcessForeachDefs(CurRec, Loc, IterVals)) + IterVals.push_back(IterRecord(CurLoop.IterVar, List->getElement(i))); + if (addDefForeach(Rec, DefmName, IterVals)) return true; IterVals.pop_back(); } @@ -380,41 +372,77 @@ // 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(*CurRec); + auto IterRec = make_unique(*Rec); + return addDefOne(std::move(IterRec), DefmName, IterVals); +} - // Set the iterator values now. - for (IterRecord &IR : IterVals) { - VarInit *IterVar = IR.IterVar; - TypedInit *IVal = dyn_cast(IR.IterValue); - if (!IVal) - return Error(Loc, "foreach iterator value is untyped"); +/// After resolving foreach loops, add the record as a prototype to the +/// current multiclass, or resolve fully and add to the record keeper. +bool TGParser::addDefOne(std::unique_ptr Rec, Init *DefmName, + IterSet &IterVals) { + MapResolver R(Rec.get()); - IterRec->addValue(RecordVal(IterVar->getNameInit(), IVal->getType(), false)); + for (IterRecord &IR : IterVals) + R.set(IR.IterVar->getNameInit(), IR.IterValue); - if (SetValue(IterRec.get(), Loc, IterVar->getNameInit(), None, IVal)) - return Error(Loc, "when instantiating this def"); + Rec->resolveReferences(R); - // Resolve it next. - IterRec->resolveReferencesTo(IterRec->getValue(IterVar->getNameInit())); + if (CurMultiClass) { + for (const auto &Proto : CurMultiClass->DefPrototypes) { + if (Proto->getNameInit() == Rec->getNameInit()) { + if (!Rec->isAnonymous()) { + PrintError(Rec->getLoc(), + Twine("def '") + Rec->getNameInitAsString() + + "' already defined in this multiclass!"); + PrintNote(Proto->getLoc(), "location of previous definition"); + return true; + } + Rec->setName(Records.getNewAnonymousName()); + break; + } + } + CurMultiClass->DefPrototypes.emplace_back(std::move(Rec)); + return false; + } - // Remove it. - IterRec->removeValue(IterVar->getNameInit()); + // Name construction is an incoherent mess. Unfortunately, existing .td + // files rely on pretty much all the quirks and implementation details of + // this. + if (DefmName) { + MapResolver R(Rec.get()); + R.set(StringInit::get("NAME"), DefmName); + Rec->resolveReferences(R); } - 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()); + if (Record *Prev = Records.getDef(Rec->getNameInitAsString())) { + if (!Rec->isAnonymous()) { + PrintError(Rec->getLoc(), + "def already exists: " + Rec->getNameInitAsString()); + PrintNote(Prev->getLoc(), "location of previous definition"); + return true; + } + Rec->setName(Records.getNewAnonymousName()); + } + + Rec->resolveReferences(); + checkConcrete(*Rec); - IterRec->setName(Records.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(); - checkConcrete(*IterRecSave); - if (addToDefsets(*IterRecSave)) - return true; + Records.addDef(std::move(Rec)); return false; } @@ -429,8 +457,9 @@ 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*/ /// @@ -442,7 +471,7 @@ // 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; } @@ -451,17 +480,7 @@ if (CurMultiClass) CurRec = &CurMultiClass->Rec; - RecTy *Type = nullptr; - if (CurRec) { - const TypedInit *CurRecName = dyn_cast(CurRec->getNameInit()); - if (!CurRecName) { - TokError("Record name is not typed!"); - return nullptr; - } - Type = CurRecName->getType(); - } - - return ParseValue(CurRec, Type, ParseNameMode); + return ParseValue(CurRec, StringRecTy::get(), ParseNameMode); } /// ParseClassID - Parse and resolve a reference to a class name. This returns @@ -811,6 +830,11 @@ if (Init *I = Records.getGlobal(Name->getValue())) return I; + // Allow self-references of concrete defs, but delay the lookup so that we + // get the correct type. + if (CurRec && !CurMultiClass && CurRec->getNameInit() == Name) + return UnOpInit::get(UnOpInit::CAST, Name, CurRec->getType()); + if (Mode == ParseValueMode) { Error(NameLoc, "Variable not defined: '" + Name->getValue() + "'"); return nullptr; @@ -2224,6 +2248,9 @@ if (TypedInit *TI = dyn_cast(I)) 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 = dyn_cast(I); @@ -2416,89 +2443,21 @@ Lex.Lex(); // Eat the 'def' token. // Parse ObjectName and make a record for it. - std::unique_ptr CurRecOwner; + std::unique_ptr CurRec; Init *Name = ParseObjectName(CurMultiClass); - if (Name) - CurRecOwner = make_unique(Name, DefLoc, Records); - else - CurRecOwner = make_unique(Records.getNewAnonymousName(), DefLoc, - Records, /*IsAnonymous=*/true); - Record *CurRec = CurRecOwner.get(); // Keep a copy since we may release. - - if (!CurMultiClass && Loops.empty()) { - // Top-level def definition. - - // Ensure redefinition doesn't happen. - if (Records.getDef(CurRec->getNameInitAsString())) - return Error(DefLoc, "def '" + CurRec->getNameInitAsString()+ - "' already defined"); - Records.addDef(std::move(CurRecOwner)); - - 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; - - // 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)) { + if (!Name) 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 (Loops.empty()) { - checkConcrete(*CurRec); - if (addToDefsets(*CurRec)) - return true; - } - } - // If ObjectBody has template arguments, it's an error. - assert(CurRec->getTemplateArgs().empty() && "How'd this get template args?"); - - 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 (isa(Name)) + CurRec = make_unique(Records.getNewAnonymousName(), DefLoc, Records, + /*Anonymous=*/true); + else + CurRec = make_unique(Name, DefLoc, Records); - if (ProcessForeachDefs(CurRec, DefLoc)) - return Error(DefLoc, "Could not process loops for def" + - CurRec->getNameInitAsString()); + if (ParseObjectBody(CurRec.get())) + return true; - return false; -} - -bool TGParser::addToDefsets(Record &R) { - for (DefsetRecord *Defset : Defsets) { - DefInit *I = R.getDefInit(); - if (!I->getType()->typeIsA(Defset->EltTy)) { - PrintError(R.getLoc(), - Twine("adding record of incompatible type '") + - I->getType()->getAsString() + "' to defset"); - PrintNote(Defset->Loc, "to this defset"); - return true; - } - Defset->Elements.push_back(I); - } - return false; + return addDef(std::move(CurRec), nullptr); } /// ParseDefset - Parse a defset statement. @@ -2818,207 +2777,25 @@ return false; } -Record *TGParser::InstantiateMulticlassDef(MultiClass &MC, Record *DefProto, - Init *&DefmPrefix, - SMRange DefmPrefixRange, - ArrayRef TArgs, - ArrayRef 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 = Records.getNewAnonymousName(); - IsAnonymous = true; - } - - Init *DefName = DefProto->getNameInit(); - StringInit *DefNameString = dyn_cast(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::getStrConcat( - UnOpInit::get(UnOpInit::CAST, DefmPrefix, StringRecTy::get()) - ->Fold(DefProto), - DefName); - } - - // Make a trail of SMLocs from the multiclass instantiations. - SmallVector Locs(1, DefmPrefixRange.Start); - Locs.append(DefProto->getLoc().begin(), DefProto->getLoc().end()); - auto CurRec = make_unique(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(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(DefName); - - if (!DefNameString) { - DefName = DefName->convertInitializerTo(StringRecTy::get()); - DefNameString = dyn_cast(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 TArgs, - ArrayRef TemplateVals, - bool DeleteArgs) { - // Set all template arguments to the specified value or leave them as the - // default if necessary, then resolve them all simultaneously. - MapResolver R(CurRec); - - for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { - // Check if a value is specified for this temp-arg. - if (i < TemplateVals.size()) { - if (SetValue(CurRec, DefmPrefixLoc, TArgs[i], None, TemplateVals[i])) - return true; - } 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() + - "'"); - } - - R.set(TArgs[i], CurRec->getValue(TArgs[i])->getValue()); - - if (DeleteArgs) - CurRec->removeValue(TArgs[i]); - } - - CurRec->resolveReferences(R); - - 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(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(DefmName)) + DefmName = Records.getNewAnonymousName(); - 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 NewRecDefs; + SmallVector, 8> NewRecDefs; // This record also inherits from a regular class (non-multiclass)? bool InheritFromClass = false; @@ -3045,31 +2822,62 @@ return Error(SubClassLoc, "more template args specified than multiclass expects"); + DenseMap TemplateArgs; + for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { + if (i < TemplateVals.size()) { + TemplateArgs.insert({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() + + "'"); + } + TemplateArgs.insert({TArgs[i], Default}); + } + } + // Loop over all the def's in the multiclass, instantiating each one. for (const std::unique_ptr &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; + bool ResolveName = true; + auto CurRec = make_unique(*DefProto); + CurRec->appendLoc(SubClassLoc); + + if (StringInit *NameString = + dyn_cast(CurRec->getNameInit())) { + // We have a fully expanded string so there are no operators to + // resolve. We should concatenate the given prefix and name. + // + // TODO: This MUST happen before template argument resolution. This + // does not make sense and should be changed, but at the time of + // writing, there are existing .td files which rely on this + // implementation detail. It's a bad idea and should be fixed. + // See test/TableGen/name-resolution-consistency.td for some + // examples. + CurRec->setName(BinOpInit::getStrConcat(DefmName, NameString)); + ResolveName = false; + } - // 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"); + MapResolver R(CurRec.get()); - if (ResolveMulticlassDef(*MC, CurRec, DefProto.get(), DefmLoc)) - return Error(SubClassLoc, "could not instantiate def"); + if (ResolveName) { + // If the proto's name wasn't resolved, we probably have a reference to + // NAME and need to replace it. + // + // TODO: Whether the name is resolved is basically determined by magic. + // Unfortunately, existing .td files depend on it. + R.set(StringInit::get("NAME"), DefmName); + } - NewRecDefs.push_back(CurRec); - } + for (const auto &TArg : TemplateArgs) + R.set(TArg.first, TArg.second); + CurRec->resolveReferences(R); + + NewRecDefs.emplace_back(std::move(CurRec)); + } if (Lex.getCode() != tgtok::comma) break; Lex.Lex(); // eat ','. @@ -3099,12 +2907,9 @@ // Get the expanded definition prototypes and teach them about // the record values the current class to inherit has - for (Record *CurRec : NewRecDefs) { + for (const auto &CurRec : NewRecDefs) { // Add it. - if (AddSubClass(CurRec, SubClass)) - return true; - - if (ApplyLetStack(CurRec)) + if (AddSubClass(CurRec.get(), SubClass)) return true; } @@ -3114,16 +2919,11 @@ } } - 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(); - checkConcrete(*CurRec); - if (addToDefsets(*CurRec)) - return true; - } + for (auto &CurRec : NewRecDefs) { + if (ApplyLetStack(CurRec.get())) + return true; + + addDef(std::move(CurRec), DefmName); } if (Lex.getCode() != tgtok::semi) Index: test/TableGen/MultiClass-defm-fail.td =================================================================== --- test/TableGen/MultiClass-defm-fail.td +++ test/TableGen/MultiClass-defm-fail.td @@ -24,9 +24,9 @@ defm _m1: M0; } -// CHECK: defm d1: M1 +// CHECK: def _m01: B // CHECK: note: instantiated from multiclass // CHECK: defm _m1: M0 // CHECK: note: instantiated from multiclass -// CHECK: def _m01: B +// CHECK: defm d1: M1 defm d1: M1<"d1">; Index: test/TableGen/foreach-multiclass.td =================================================================== --- /dev/null +++ test/TableGen/foreach-multiclass.td @@ -0,0 +1,24 @@ +// RUN: llvm-tblgen %s | FileCheck %s +// XFAIL: vg_leak + +// CHECK: --- Defs --- + +// CHECK: def A00 { +// CHECK: int sum = 7; +// CHECK: } + +// CHECK: def A01 { +// CHECK: int sum = 8; +// CHECK: } + +multiclass A { + // Allow foreach in multiclass as long as the list does not depend on + // template args. + foreach i = [0, 1] in { + def NAME#i { + int sum = !add(x, i); + } + } +} + +defm A0 : A<7>; Index: test/TableGen/name-resolution-consistency.td =================================================================== --- /dev/null +++ test/TableGen/name-resolution-consistency.td @@ -0,0 +1,84 @@ +// RUN: llvm-tblgen %s | FileCheck %s +// XFAIL: vg_leak + +// This test demonstrates a number of inconsistencies in how NAME is resolved +// and record names are constructed. +// +// The TODO lines describe a suggested consistent behavior that would result +// from: +// (1) Treating NAME as an implicit multiclass template argument and +// (2) always storing the name of (non-anonymous) prototype records in +// multiclasses with at least one explicit reference to NAME. +// +// Unfortunately, several backends (including X86) rely quite heavily on the +// current inconsistent behavior and would have to be fixed. + +// CHECK: def B0a { +// CHECK: string e = "B0"; +// CHECK: } + +// CHECK: def B0ba { +// TODO: expect "B0b" here +// CHECK: string a = "B0"; +// CHECK: string b = "B0"; +// CHECK: } + +// CHECK: def B0cza { +// TODO: expect "B0cz" here +// CHECK: string a = "B0"; +// CHECK: string b = "B0"; +// CHECK: } + +// TODO: expect this to be named 'xB0b' +// CHECK: def B0xb { +// TODO: expect "B0b" here +// CHECK: string c = "b"; +// CHECK: string d = "b"; +// CHECK: } + +// TODO: expect this to be named B0bys +// CHECK: def B0ys { +// TODO: expect "B0b" here +// CHECK: string f = "b"; +// CHECK: string g = "b"; +// CHECK: } + +// CHECK: def xB0cz { +// CHECK: string c = "B0cz"; +// CHECK: string d = "B0cz"; +// CHECK: } + +// TODO: expect this to be named B0czyt +// CHECK: def yt { +// CHECK: string f = "B0cz"; +// CHECK: string g = "B0cz"; +// CHECK: } + +multiclass A { + def a { + string a = NAME; + string b = p; + } + + def x # NAME { + string c = NAME; + string d = p; + } + + def y # q { + string f = NAME; + string g = p; + } +} + +multiclass B { + def a { + string e = NAME; + } + + defm b : A; + + defm NAME # c # name : A; +} + +defm B0 : B<"z", "t">; Index: test/TableGen/self-reference.td =================================================================== --- test/TableGen/self-reference.td +++ test/TableGen/self-reference.td @@ -24,6 +24,14 @@ // CHECK: E e = E0; // CHECK: } +// CHECK: def F0 { +// CHECK: Fa as_a = F0; +// CHECK: Fb as_b = F0; +// CHECK: } +// CHECK: def F0x { +// CHECK: Fc as_c = F0; +// CHECK: } + def ops; class A { @@ -73,3 +81,18 @@ // work here because E0 does not yet have E as a superclass while the template // arguments are being parsed. def E0 : E("E0")>; + +// Ensure that records end up with the correct type even when direct self- +// references are involved. +class Fa; +class Fb { + Fa as_a = x; +} +class Fc { + Fb as_b = x; +} + +def F0 : Fa, Fb, Fc; +def F0x { + Fc as_c = F0; +}