diff --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst index c9bee3fa31bb0..c316c33a37f46 100644 --- a/llvm/docs/TableGen/ProgRef.rst +++ b/llvm/docs/TableGen/ProgRef.rst @@ -1282,9 +1282,7 @@ placement. the subclasses and records that inherit from the class. The assertions are then checked when the records are completely built. -* In a multiclass definition, the assertions are saved with the other - components of the multiclass and then checked each time the multiclass - is instantiated with ``defm``. +* In a multiclass definition, ... [this placement is not yet available] Using assertions in TableGen files can simplify record checking in TableGen backends. Here is an example of an ``assert`` in two class definitions. diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h index 36c6c688cf6e7..9432de6738613 100644 --- a/llvm/include/llvm/TableGen/Record.h +++ b/llvm/include/llvm/TableGen/Record.h @@ -1469,10 +1469,6 @@ inline raw_ostream &operator<<(raw_ostream &OS, const RecordVal &RV) { } class Record { -public: - using AssertionTuple = std::tuple; - -private: static unsigned LastID; Init *Name; @@ -1482,7 +1478,7 @@ class Record { SmallVector TemplateArgs; SmallVector Values; // Vector of [source location, condition Init, message Init]. - SmallVector Assertions; + SmallVector, 0> Assertions; // All superclasses in the inheritance forest in post-order (yes, it // must be a forest; diamond-shaped inheritance is not allowed). @@ -1557,7 +1553,7 @@ class Record { ArrayRef getValues() const { return Values; } - ArrayRef getAssertions() const { + ArrayRef> getAssertions() const { return Assertions; } @@ -1624,7 +1620,7 @@ class Record { Assertions.append(Rec->Assertions); } - void checkRecordAssertions(); + void checkAssertions(); bool isSubClassOf(const Record *R) const { for (const auto &SCPair : SuperClasses) diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp index 2c8234da84311..21f7bacb10b0f 100644 --- a/llvm/lib/TableGen/Record.cpp +++ b/llvm/lib/TableGen/Record.cpp @@ -1835,7 +1835,7 @@ DefInit *VarDefInit::instantiate() { Records.addDef(std::move(NewRecOwner)); // Check the assertions. - NewRec->checkRecordAssertions(); + NewRec->checkAssertions(); Def = DefInit::get(NewRec); } @@ -2618,7 +2618,7 @@ DagInit *Record::getValueAsDag(StringRef FieldName) const { // and message, then call CheckAssert(). // Note: The condition and message are probably already resolved, // but resolving again allows calls before records are resolved. -void Record::checkRecordAssertions() { +void Record::checkAssertions() { RecordResolver R(*this); R.setFinal(true); diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp index 8c2ec289ea854..3d95ac30ebd0b 100644 --- a/llvm/lib/TableGen/TGParser.cpp +++ b/llvm/lib/TableGen/TGParser.cpp @@ -339,38 +339,27 @@ bool TGParser::AddSubMultiClass(MultiClass *CurMC, return resolve(SMC->Entries, TemplateArgs, false, &CurMC->Entries); } -/// Add a record, foreach loop, or assertion to the current context. +/// 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 + !!E.Assertion) == 1 && - "RecordsEntry has invalid number of items"); + assert(!E.Rec || !E.Loop); - // If we are parsing a loop, add it to the loop's entries. if (!Loops.empty()) { Loops.back()->Entries.push_back(std::move(E)); return false; } - // If it is a loop, then resolve and perform the loop. if (E.Loop) { SubstStack Stack; return resolve(*E.Loop, Stack, CurMultiClass == nullptr, CurMultiClass ? &CurMultiClass->Entries : nullptr); } - // If we are parsing a multiclass, add it to the multiclass's entries. if (CurMultiClass) { CurMultiClass->Entries.push_back(std::move(E)); return false; } - // If it is an assertion, then it's a top-level one, so check it. - if (E.Assertion) { - CheckAssert(std::get<0>(*E.Assertion), std::get<1>(*E.Assertion), - std::get<2>(*E.Assertion)); - return false; - } - - // It must be a record, so finish it off. return addDefOne(std::move(E.Rec)); } @@ -425,24 +414,6 @@ bool TGParser::resolve(const std::vector &Source, for (auto &E : Source) { if (E.Loop) { Error = resolve(*E.Loop, Substs, Final, Dest); - - } else if (E.Assertion) { - MapResolver R; - for (const auto &S : Substs) - R.set(S.first, S.second); - Init *Condition = std::get<1>(*E.Assertion)->resolveReferences(R); - Init *Message = std::get<2>(*E.Assertion)->resolveReferences(R); - - if (Dest) { - std::unique_ptr tuple = - std::make_unique(std::get<0>(*E.Assertion), - std::move(Condition), - std::move(Message)); - Dest->push_back(std::move(tuple)); - } else { - CheckAssert(std::get<0>(*E.Assertion), Condition, Message); - } - } else { auto Rec = std::make_unique(*E.Rec); if (Loc) @@ -488,7 +459,7 @@ bool TGParser::addDefOne(std::unique_ptr Rec) { } // Check the assertions. - Rec->checkRecordAssertions(); + Rec->checkAssertions(); // If ObjectBody has template arguments, it's an error. assert(Rec->getTemplateArgs().empty() && "How'd this get template args?"); @@ -2871,15 +2842,10 @@ bool TGParser::ApplyLetStack(Record *CurRec) { return false; } -/// Apply the current let bindings to the RecordsEntry. bool TGParser::ApplyLetStack(RecordsEntry &Entry) { if (Entry.Rec) return ApplyLetStack(Entry.Rec.get()); - // Let bindings are not applied to assertions. - if (Entry.Assertion) - return false; - for (auto &E : Entry.Loop->Entries) { if (ApplyLetStack(E)) return true; @@ -2923,8 +2889,8 @@ bool TGParser::ParseObjectBody(Record *CurRec) { return ParseBody(CurRec); } -/// ParseDef - Parse and return a top level or multiclass record definition. -/// Return false if okay, true if error. +/// ParseDef - Parse and return a top level or multiclass def, return the record +/// corresponding to it. This returns null on error. /// /// DefInst ::= DEF ObjectName ObjectBody /// @@ -3218,12 +3184,12 @@ bool TGParser::ParseAssert(MultiClass *CurMultiClass, Record *CurRec) { if (!consume(tgtok::semi)) return TokError("expected ';'"); - if (CurRec) { + if (CurMultiClass) { + assert(false && "assert in multiclass not yet supported"); + } else if (CurRec) { CurRec->addAssertion(ConditionLoc, Condition, Message); - } else { - std::unique_ptr tuple = - std::make_unique(ConditionLoc, Condition, Message); - addEntry(std::move(tuple)); + } else { // at top level + CheckAssert(ConditionLoc, Condition, Message); } return false; @@ -3362,13 +3328,10 @@ bool TGParser::ParseTopLevelLet(MultiClass *CurMultiClass) { /// MultiClassInst ::= MULTICLASS ID TemplateArgList? /// ':' BaseMultiClassList '{' MultiClassObject+ '}' /// MultiClassObject ::= DefInst +/// MultiClassObject ::= MultiClassInst /// MultiClassObject ::= DefMInst -/// MultiClassObject ::= Defvar -/// MultiClassObject ::= Foreach -/// MultiClassObject ::= If /// MultiClassObject ::= LETCommand '{' ObjectList '}' /// MultiClassObject ::= LETCommand Object -/// MultiClassObject ::= Assert /// bool TGParser::ParseMultiClass() { assert(Lex.getCode() == tgtok::MultiClass && "Unexpected token"); @@ -3433,6 +3396,8 @@ bool TGParser::ParseMultiClass() { default: return TokError("expected 'assert', 'def', 'defm', 'defvar', " "'foreach', 'if', or 'let' in multiclass body"); + case tgtok::Assert: + return TokError("an assert statement in a multiclass is not yet supported"); case tgtok::Def: case tgtok::Defm: @@ -3440,7 +3405,6 @@ bool TGParser::ParseMultiClass() { case tgtok::Foreach: case tgtok::If: case tgtok::Let: - case tgtok::Assert: if (ParseObject(CurMultiClass)) return true; break; @@ -3600,7 +3564,7 @@ bool TGParser::ParseObject(MultiClass *MC) { default: return TokError( "Expected assert, class, def, defm, defset, foreach, if, or let"); - case tgtok::Assert: return ParseAssert(MC); + case tgtok::Assert: return ParseAssert(MC, nullptr); case tgtok::Def: return ParseDef(MC); case tgtok::Defm: return ParseDefm(MC); case tgtok::Defvar: return ParseDefvar(); diff --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h index 254ce3c90980e..6514d4276a7f6 100644 --- a/llvm/lib/TableGen/TGParser.h +++ b/llvm/lib/TableGen/TGParser.h @@ -36,12 +36,10 @@ namespace llvm { } }; - /// RecordsEntry - Holds exactly one of a Record, ForeachLoop, or - /// assertion tuple. + /// RecordsEntry - Can be either a record or a foreach loop. struct RecordsEntry { std::unique_ptr Rec; std::unique_ptr Loop; - std::unique_ptr Assertion; void dump() const; @@ -49,8 +47,6 @@ namespace llvm { RecordsEntry(std::unique_ptr Rec) : Rec(std::move(Rec)) {} RecordsEntry(std::unique_ptr Loop) : Loop(std::move(Loop)) {} - RecordsEntry(std::unique_ptr Assertion) - : Assertion(std::move(Assertion)) {} }; /// ForeachLoop - Record the iteration state associated with a for loop. @@ -226,7 +222,7 @@ class TGParser { bool ParseForeach(MultiClass *CurMultiClass); bool ParseIf(MultiClass *CurMultiClass); bool ParseIfBody(MultiClass *CurMultiClass, StringRef Kind); - bool ParseAssert(MultiClass *CurMultiClass, Record *CurRec = nullptr); + bool ParseAssert(MultiClass *CurMultiClass, Record *CurRec); bool ParseTopLevelLet(MultiClass *CurMultiClass); void ParseLetList(SmallVectorImpl &Result); diff --git a/llvm/test/TableGen/assert.td b/llvm/test/TableGen/assert.td index fb8f7beccc89c..1c436301d85d0 100644 --- a/llvm/test/TableGen/assert.td +++ b/llvm/test/TableGen/assert.td @@ -39,15 +39,6 @@ class Cube { assert !eq(Cube<9>.result, 81), "cube of 9 should be 729"; -// CHECK: assertion failed -// CHECK: note: foreach i cannot be 2 -// CHECK-NOT: note: foreach i cannot be 2 - -foreach i = 1...3 in { - assert !ne(i, 2), "foreach i cannot be 2"; - def bar_ # i; -} - // Test the assert statement in a record definition. // CHECK: assertion failed @@ -145,47 +136,3 @@ def Rec32 { // Test the assert statement in a multiclass. -// CHECK: assertion failed -// CHECK: note: MC1 id string is too long -// CHECK: assertion failed -// CHECK: note: MC1 seq is too high - -multiclass MC1 { - assert !le(!size(id), 5), "MC1 id string is too long"; - assert !le(seq, 999999), "MC1 seq is too high"; - - def _mc1 { - string ID = id; - int Seq = seq; - } -} - -defm Rec40 : MC1<"ILISP", 999>; -defm Rec41 : MC1<"ILISPX", 999>; -defm Rec42 : MC1<"ILISP", 999999999>; - -// CHECK: assertion failed -// CHECK: note: MC2 phrase must be secret: secrex code - -multiclass MC2 { - assert !eq(!substr(phr, 0, 6), "secret"), "MC2 phrase must be secret: " # phr; - - def _mc2 { - string phrase = phr; - } -} - -multiclass MC3 { - defm _mc3 : MC2; -} - -defm Rec43 : MC3<"secrex code">; - -// CHECK: assertion failed -// CHECK: note: MC2 phrase must be secret: xecret code - -multiclass MC4 : MC2 { - def _def; -} - -defm Rec44 : MC4<"xecret code">;