diff --git a/docs/TableGenFundamentals.html b/docs/TableGenFundamentals.html index 6db1827b3be..45baf198454 100644 --- a/docs/TableGenFundamentals.html +++ b/docs/TableGenFundamentals.html @@ -37,6 +37,7 @@
  1. File inclusion
  2. 'let' expressions
  3. +
  4. 'foreach' blocks
  • TableGen backends @@ -401,6 +402,14 @@ which case the user must specify it explicitly.
    list[4-7,17,2-3]
    A slice of the 'list' list, including elements 4,5,6,7,17,2, and 3 from it. Elements may be included multiple times.
    +
    foreach <var> = <list> in { <body> }
    +
    foreach <var> = <list> in <def>
    +
    Replicate <body> or <def>, replacing instances of + <var> with each value in <list>. <var> is scoped at the + level of the foreach loop and must not conflict with any other object + introduced in <body> or <def>. Currently only defs are + expanded within <body>. +
    (DEF a, b)
    a dag value. The first element is required to be a record definition, the remaining elements in the list may be arbitrary other values, including nested @@ -880,6 +889,39 @@ several levels of multiclass instanciations. This also avoids the need of using + +

    + Looping +

    + +
    +

    TableGen supports the 'foreach' block, which textually replicates +the loop body, substituting iterator values for iterator references in the +body. Example:

    + +
    +
    +foreach i = [0, 1, 2, 3] in {
    +  def R#i : Register<...>;
    +  def F#i : Register<...>;
    +}
    +
    +
    + +

    This will create objects R0, R1, R2 and +R3. foreach blocks may be nested. If there is only +one item in the body the braces may be elided:

    + +
    +
    +foreach i = [0, 1, 2, 3] in
    +  def R#i : Register<...>;
    +
    +
    +
    + +
    + diff --git a/include/llvm/TableGen/Record.h b/include/llvm/TableGen/Record.h index f51af286fad..5e68c10a47a 100644 --- a/include/llvm/TableGen/Record.h +++ b/include/llvm/TableGen/Record.h @@ -1535,6 +1535,7 @@ struct MultiClass { class RecordKeeper { std::map Classes, Defs; + public: ~RecordKeeper() { for (std::map::iterator I = Classes.begin(), diff --git a/lib/TableGen/TGLexer.cpp b/lib/TableGen/TGLexer.cpp index 79d9ed29f90..ff322e74fba 100644 --- a/lib/TableGen/TGLexer.cpp +++ b/lib/TableGen/TGLexer.cpp @@ -274,6 +274,7 @@ tgtok::TokKind TGLexer::LexIdentifier() { .Case("dag", tgtok::Dag) .Case("class", tgtok::Class) .Case("def", tgtok::Def) + .Case("foreach", tgtok::Foreach) .Case("defm", tgtok::Defm) .Case("multiclass", tgtok::MultiClass) .Case("field", tgtok::Field) diff --git a/lib/TableGen/TGLexer.h b/lib/TableGen/TGLexer.h index 0246ab6b900..8a850b5cec8 100644 --- a/lib/TableGen/TGLexer.h +++ b/lib/TableGen/TGLexer.h @@ -42,7 +42,7 @@ namespace tgtok { paste, // # // Keywords. - Bit, Bits, Class, Code, Dag, Def, Defm, Field, In, Int, Let, List, + Bit, Bits, Class, Code, Dag, Def, Foreach, Defm, Field, In, Int, Let, List, MultiClass, String, // !keywords. diff --git a/lib/TableGen/TGParser.cpp b/lib/TableGen/TGParser.cpp index c7cf097aee1..04c4fc158ff 100644 --- a/lib/TableGen/TGParser.cpp +++ b/lib/TableGen/TGParser.cpp @@ -289,6 +289,113 @@ bool TGParser::AddSubMultiClass(MultiClass *CurMC, 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, MultiClass *CurMultiClass, + SMLoc Loc) { + // 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; + for (LoopVector::iterator Loop = Loops.begin(), LoopEnd = Loops.end(); + Loop != LoopEnd; + ++Loop) { + // Process this loop. + if (ProcessForeachDefs(CurRec, CurMultiClass, Loc, + IterVals, *Loop, Loop+1)) { + Error(Loc, + "Could not process loops for def " + CurRec->getNameInitAsString()); + return true; + } + } + + return false; +} + +/// 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, MultiClass *CurMultiClass, + SMLoc Loc, IterSet &IterVals, + ForeachLoop &CurLoop, + LoopVector::iterator NextLoop) { + Init *IterVar = CurLoop.IterVar; + ListInit *List = dynamic_cast(CurLoop.ListValue); + + if (List == 0) { + Error(Loc, "Loop list is not a list"); + return true; + } + + // Process each value. + for (int64_t i = 0; i < List->getSize(); ++i) { + Init *ItemVal = List->resolveListElementReference(*CurRec, 0, i); + IterVals.push_back(IterRecord(IterVar, ItemVal)); + + if (IterVals.size() == Loops.size()) { + // Ok, we have all of the iterator values for this point in the + // iteration space. Instantiate a new record to reflect this + // combination of values. + Record *IterRec = new Record(*CurRec); + + // Set the iterator values now. + for (IterSet::iterator i = IterVals.begin(), iend = IterVals.end(); + i != iend; + ++i) { + VarInit *IterVar = dynamic_cast(i->IterVar); + if (IterVar == 0) { + Error(Loc, "foreach iterator is unresolved"); + return true; + } + + TypedInit *IVal = dynamic_cast(i->IterValue); + if (IVal == 0) { + Error(Loc, "foreach iterator value is untyped"); + return true; + } + + IterRec->addValue(RecordVal(IterVar->getName(), IVal->getType(), false)); + + if (SetValue(IterRec, Loc, IterVar->getName(), + std::vector(), IVal)) { + Error(Loc, "when instantiating this def"); + return true; + } + + // Resolve it next. + IterRec->resolveReferencesTo(IterRec->getValue(IterVar->getName())); + + // Remove it. + IterRec->removeValue(IterVar->getName()); + } + + if (Records.getDef(IterRec->getNameInitAsString())) { + Error(Loc, "def already exists: " + IterRec->getNameInitAsString()); + return true; + } + + Records.addDef(IterRec); + IterRec->resolveReferences(); + } + + if (NextLoop != Loops.end()) { + // Process nested loops. + if (ProcessForeachDefs(CurRec, CurMultiClass, Loc, IterVals, *NextLoop, + NextLoop+1)) { + Error(Loc, + "Could not process loops for def " + + CurRec->getNameInitAsString()); + return true; + } + } + + // We're done with this iterator. + IterVals.pop_back(); + } + return false; +} + //===----------------------------------------------------------------------===// // Parser Code //===----------------------------------------------------------------------===// @@ -296,7 +403,8 @@ bool TGParser::AddSubMultiClass(MultiClass *CurMC, /// 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::Defm || K == tgtok::Let || + K == tgtok::MultiClass || K == tgtok::Foreach; } static std::string GetNewAnonymousName() { @@ -698,6 +806,15 @@ Init *TGParser::ParseIDValue(Record *CurRec, } } + // If this is in a foreach loop, make sure it's not a loop iterator + for (LoopVector::iterator i = Loops.begin(), iend = Loops.end(); + i != iend; + ++i) { + VarInit *IterVar = dynamic_cast(i->IterVar); + if (IterVar && IterVar->getName() == Name) + return IterVar; + } + if (Mode == ParseNameMode) return StringInit::get(Name); @@ -1353,7 +1470,7 @@ Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) { switch (Lex.getCode()) { default: return Result; case tgtok::l_brace: { - if (Mode == ParseNameMode) + if (Mode == ParseNameMode || Mode == ParseForeachMode) // This is the beginning of the object body. return Result; @@ -1605,6 +1722,50 @@ Init *TGParser::ParseDeclaration(Record *CurRec, return DeclName; } +/// ParseForeachDeclaration - Read a foreach declaration, returning +/// the name of the declared object or a NULL Init on error. Return +/// the name of the parsed initializer list through ForeachListName. +/// +/// ForeachDeclaration ::= ID '=' Value +/// +Init *TGParser::ParseForeachDeclaration(Init *&ForeachListValue) { + if (Lex.getCode() != tgtok::Id) { + TokError("Expected identifier in foreach declaration"); + return 0; + } + + Init *DeclName = StringInit::get(Lex.getCurStrVal()); + Lex.Lex(); + + // If a value is present, parse it. + if (Lex.getCode() != tgtok::equal) { + TokError("Expected '=' in foreach declaration"); + return 0; + } + Lex.Lex(); // Eat the '=' + + // Expect a list initializer. + ForeachListValue = ParseValue(0, 0, ParseForeachMode); + + TypedInit *TypedList = dynamic_cast(ForeachListValue); + if (TypedList == 0) { + TokError("Value list is untyped"); + return 0; + } + + RecTy *ValueType = TypedList->getType(); + ListRecTy *ListType = dynamic_cast(ValueType); + if (ListType == 0) { + TokError("Value list is not of list type"); + return 0; + } + + RecTy *IterType = ListType->getElementType(); + VarInit *IterVar = VarInit::get(DeclName, IterType); + + return IterVar; +} + /// ParseTemplateArgList - Read a template argument list, which is a non-empty /// sequence of template-declarations in <>'s. If CurRec is non-null, these are /// template args for a def, which may or may not be in a multiclass. If null, @@ -1817,6 +1978,63 @@ bool TGParser::ParseDef(MultiClass *CurMultiClass) { } } + if (ProcessForeachDefs(CurRec, CurMultiClass, DefLoc)) { + Error(DefLoc, + "Could not process loops for def" + CurRec->getNameInitAsString()); + return true; + } + + return false; +} + +/// ParseForeach - Parse a for statement. Return the record corresponding +/// to it. This returns true on error. +/// +/// Foreach ::= FOREACH Declaration IN '{ ObjectList '}' +/// Foreach ::= FOREACH Declaration IN Object +/// +bool TGParser::ParseForeach(MultiClass *CurMultiClass) { + 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. + Init *ListValue = 0; + Init *IterName = ParseForeachDeclaration(ListValue); + if (IterName == 0) + return TokError("expected declaration in for"); + + if (Lex.getCode() != tgtok::In) + return TokError("Unknown tok"); + Lex.Lex(); // Eat the in + + // Create a loop object and remember it. + Loops.push_back(ForeachLoop(IterName, ListValue)); + + if (Lex.getCode() != tgtok::l_brace) { + // FOREACH Declaration IN Object + if (ParseObject(CurMultiClass)) + return true; + } + else { + SMLoc BraceLoc = Lex.getLoc(); + // Otherwise, this is a group foreach. + Lex.Lex(); // eat the '{'. + + // Parse the object list. + if (ParseObjectList(CurMultiClass)) + return true; + + if (Lex.getCode() != tgtok::r_brace) { + TokError("expected '}' at end of foreach command"); + return Error(BraceLoc, "to match this '{'"); + } + Lex.Lex(); // Eat the } + } + + // We've processed everything in this loop. + Loops.pop_back(); + return false; } @@ -2010,6 +2228,7 @@ bool TGParser::ParseMultiClass() { case tgtok::Let: case tgtok::Def: case tgtok::Defm: + case tgtok::Foreach: if (ParseObject(CurMultiClass)) return true; break; @@ -2305,6 +2524,7 @@ bool TGParser::ParseObject(MultiClass *MC) { return TokError("Expected class, def, defm, multiclass or let definition"); 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(); diff --git a/lib/TableGen/TGParser.h b/lib/TableGen/TGParser.h index 54cd99a8a4a..509b02c0782 100644 --- a/lib/TableGen/TGParser.h +++ b/lib/TableGen/TGParser.h @@ -42,11 +42,25 @@ namespace llvm { } }; + /// ForeachLoop - Record the iteration state associated with a for loop. + /// This is used to instantiate items in the loop body. + struct ForeachLoop { + Init *IterVar; + Init *ListValue; + + ForeachLoop(Init *IVar, Init *LValue) : IterVar(IVar), ListValue(LValue) {}; + }; + class TGParser { TGLexer Lex; std::vector > LetStack; std::map MultiClasses; + /// Loops - Keep track of any foreach loops we are within. + /// + typedef std::vector LoopVector; + LoopVector Loops; + /// CurMultiClass - If we are parsing a 'multiclass' definition, this is the /// current value. MultiClass *CurMultiClass; @@ -60,8 +74,10 @@ class TGParser { // in the middle of creating in. For those situations, allow the // parser to ignore missing object errors. enum IDParseMode { - 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. + 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: @@ -82,6 +98,7 @@ public: const std::vector &getDependencies() const { return Lex.getDependencies(); } + private: // Semantic analysis methods. bool AddValue(Record *TheRec, SMLoc Loc, const RecordVal &RV); bool SetValue(Record *TheRec, SMLoc Loc, Init *ValName, @@ -94,6 +111,23 @@ private: // Semantic analysis methods. bool AddSubMultiClass(MultiClass *CurMC, SubMultiClassReference &SubMultiClass); + // IterRecord: Map an iterator name to a value. + struct IterRecord { + Init *IterVar; + Init *IterValue; + IterRecord(Init *Var, Init *Val) : IterVar(Var), IterValue(Val) {} + }; + + // IterSet: The set of all iterator values at some point in the + // iteration space. + typedef std::vector IterSet; + + bool ProcessForeachDefs(Record *CurRec, MultiClass *CurMultiClass, + SMLoc Loc); + bool ProcessForeachDefs(Record *CurRec, MultiClass *CurMultiClass, + SMLoc Loc, IterSet &IterVals, ForeachLoop &CurLoop, + LoopVector::iterator NextLoop); + private: // Parser methods. bool ParseObjectList(MultiClass *MC = 0); bool ParseObject(MultiClass *MC); @@ -116,6 +150,7 @@ private: // Parser methods. SMLoc DefmPrefixLoc); bool ParseDefm(MultiClass *CurMultiClass); bool ParseDef(MultiClass *CurMultiClass); + bool ParseForeach(MultiClass *CurMultiClass); bool ParseTopLevelLet(MultiClass *CurMultiClass); std::vector ParseLetList(); @@ -125,6 +160,7 @@ private: // Parser methods. bool ParseTemplateArgList(Record *CurRec); Init *ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs); + Init *ParseForeachDeclaration(Init *&ForeachListValue); SubClassReference ParseSubClassReference(Record *CurRec, bool isDefm); SubMultiClassReference ParseSubMultiClassReference(MultiClass *CurMC); diff --git a/test/TableGen/ForeachList.td b/test/TableGen/ForeachList.td new file mode 100644 index 00000000000..99b7e14c2d5 --- /dev/null +++ b/test/TableGen/ForeachList.td @@ -0,0 +1,76 @@ +// RUN: llvm-tblgen %s | FileCheck %s +// XFAIL: vg_leak + +class Register { + string Name = name; + int Index = idx; +} + +foreach i = [0, 1, 2, 3, 4, 5, 6, 7] in { + def R#i : Register<"R"#i, i>; + def F#i : Register<"F"#i, i>; +} + +// CHECK: def F0 +// CHECK: string Name = "F0"; +// CHECK: int Index = 0; + +// CHECK: def F1 +// CHECK: string Name = "F1"; +// CHECK: int Index = 1; + +// CHECK: def F2 +// CHECK: string Name = "F2"; +// CHECK: int Index = 2; + +// CHECK: def F3 +// CHECK: string Name = "F3"; +// CHECK: int Index = 3; + +// CHECK: def F4 +// CHECK: string Name = "F4"; +// CHECK: int Index = 4; + +// CHECK: def F5 +// CHECK: string Name = "F5"; +// CHECK: int Index = 5; + +// CHECK: def F6 +// CHECK: string Name = "F6"; +// CHECK: int Index = 6; + +// CHECK: def F7 +// CHECK: string Name = "F7"; +// CHECK: int Index = 7; + +// CHECK: def R0 +// CHECK: string Name = "R0"; +// CHECK: int Index = 0; + +// CHECK: def R1 +// CHECK: string Name = "R1"; +// CHECK: int Index = 1; + +// CHECK: def R2 +// CHECK: string Name = "R2"; +// CHECK: int Index = 2; + +// CHECK: def R3 +// CHECK: string Name = "R3"; +// CHECK: int Index = 3; + +// CHECK: def R4 +// CHECK: string Name = "R4"; +// CHECK: int Index = 4; + +// CHECK: def R5 +// CHECK: string Name = "R5"; +// CHECK: int Index = 5; + +// CHECK: def R6 +// CHECK: string Name = "R6"; +// CHECK: int Index = 6; + +// CHECK: def R7 +// CHECK: string Name = "R7"; +// CHECK: int Index = 7; diff --git a/test/TableGen/ForeachLoop.td b/test/TableGen/ForeachLoop.td new file mode 100644 index 00000000000..e2defe9cfea --- /dev/null +++ b/test/TableGen/ForeachLoop.td @@ -0,0 +1,43 @@ +// RUN: llvm-tblgen %s | FileCheck %s +// XFAIL: vg_leak + +class Register { + string Name = name; + int Index = idx; +} + +foreach i = [0, 1, 2, 3, 4, 5, 6, 7] in + def R#i : Register<"R"#i, i>; + + +// CHECK: def R0 +// CHECK: string Name = "R0"; +// CHECK: int Index = 0; + +// CHECK: def R1 +// CHECK: string Name = "R1"; +// CHECK: int Index = 1; + +// CHECK: def R2 +// CHECK: string Name = "R2"; +// CHECK: int Index = 2; + +// CHECK: def R3 +// CHECK: string Name = "R3"; +// CHECK: int Index = 3; + +// CHECK: def R4 +// CHECK: string Name = "R4"; +// CHECK: int Index = 4; + +// CHECK: def R5 +// CHECK: string Name = "R5"; +// CHECK: int Index = 5; + +// CHECK: def R6 +// CHECK: string Name = "R6"; +// CHECK: int Index = 6; + +// CHECK: def R7 +// CHECK: string Name = "R7"; +// CHECK: int Index = 7; diff --git a/test/TableGen/NestedForeach.td b/test/TableGen/NestedForeach.td new file mode 100644 index 00000000000..e8c16f720d0 --- /dev/null +++ b/test/TableGen/NestedForeach.td @@ -0,0 +1,74 @@ +// RUN: llvm-tblgen %s | FileCheck %s +// XFAIL: vg_leak + +class Droid { + string Series = series; + int Release = release; + string Model = model; + int Patchlevel = patchlevel; +} + +foreach S = ["R", "C"] in { + foreach R = [2, 3, 4] in { + foreach M = ["D", "P", "Q"] in { + foreach P = [0, 2, 4] in { + def S#R#M#P : Droid; + } + } + } +} + +// CHECK: def C2D0 +// CHECK: def C2D2 +// CHECK: def C2D4 +// CHECK: def C2P0 +// CHECK: def C2P2 +// CHECK: def C2P4 +// CHECK: def C2Q0 +// CHECK: def C2Q2 +// CHECK: def C2Q4 +// CHECK: def C3D0 +// CHECK: def C3D2 +// CHECK: def C3D4 +// CHECK: def C3P0 +// CHECK: def C3P2 +// CHECK: def C3P4 +// CHECK: def C3Q0 +// CHECK: def C3Q2 +// CHECK: def C3Q4 +// CHECK: def C4D0 +// CHECK: def C4D2 +// CHECK: def C4D4 +// CHECK: def C4P0 +// CHECK: def C4P2 +// CHECK: def C4P4 +// CHECK: def C4Q0 +// CHECK: def C4Q2 +// CHECK: def C4Q4 +// CHECK: def R2D0 +// CHECK: def R2D2 +// CHECK: def R2D4 +// CHECK: def R2P0 +// CHECK: def R2P2 +// CHECK: def R2P4 +// CHECK: def R2Q0 +// CHECK: def R2Q2 +// CHECK: def R2Q4 +// CHECK: def R3D0 +// CHECK: def R3D2 +// CHECK: def R3D4 +// CHECK: def R3P0 +// CHECK: def R3P2 +// CHECK: def R3P4 +// CHECK: def R3Q0 +// CHECK: def R3Q2 +// CHECK: def R3Q4 +// CHECK: def R4D0 +// CHECK: def R4D2 +// CHECK: def R4D4 +// CHECK: def R4P0 +// CHECK: def R4P2 +// CHECK: def R4P4 +// CHECK: def R4Q0 +// CHECK: def R4Q2 +// CHECK: def R4Q4 diff --git a/test/TableGen/SiblingForeach.td b/test/TableGen/SiblingForeach.td new file mode 100644 index 00000000000..a11f6f87b42 --- /dev/null +++ b/test/TableGen/SiblingForeach.td @@ -0,0 +1,277 @@ +// RUN: llvm-tblgen %s | FileCheck %s +// XFAIL: vg_leak + +class Set { + int I = i; + int J = j; + int K = k; +} + +foreach i = [1, 2, 3] in { + def I1_#i : Set; + foreach j = [1, 2, 3] in { + def I1_#i#_J1_#j : Set; + } + def I2_#i : Set; + foreach j = [4, 5, 6] in { + foreach k = [1, 2, 3] in { + def I3_#i#_J2_#j#_K1_#k : Set; + } + def I4_#i#_J3_#j : Set; + } +} + +// CHECK: def I1_1 +// CHECK: int I = 1; +// CHECK: int J = 0; +// CHECK: int K = 0; + +// CHECK: def I1_1_J1_1 +// CHECK: int I = 1; +// CHECK: int J = 1; +// CHECK: int K = 0; + +// CHECK: def I1_1_J1_2 +// CHECK: int I = 1; +// CHECK: int J = 2; +// CHECK: int K = 0; + +// CHECK: def I1_1_J1_3 +// CHECK: int I = 1; +// CHECK: int J = 3; +// CHECK: int K = 0; + +// CHECK: def I1_2 +// CHECK: int I = 2; +// CHECK: int J = 0; +// CHECK: int K = 0; + +// CHECK: def I1_2_J1_1 +// CHECK: int I = 2; +// CHECK: int J = 1; +// CHECK: int K = 0; + +// CHECK: def I1_2_J1_2 +// CHECK: int I = 2; +// CHECK: int J = 2; +// CHECK: int K = 0; + +// CHECK: def I1_2_J1_3 +// CHECK: int I = 2; +// CHECK: int J = 3; +// CHECK: int K = 0; + +// CHECK: def I1_3 +// CHECK: int I = 3; +// CHECK: int J = 0; +// CHECK: int K = 0; + +// CHECK: def I1_3_J1_1 +// CHECK: int I = 3; +// CHECK: int J = 1; +// CHECK: int K = 0; + +// CHECK: def I1_3_J1_2 +// CHECK: int I = 3; +// CHECK: int J = 2; +// CHECK: int K = 0; + +// CHECK: def I1_3_J1_3 +// CHECK: int I = 3; +// CHECK: int J = 3; +// CHECK: int K = 0; + +// CHECK: def I2_1 +// CHECK: int I = 1; +// CHECK: int J = 0; +// CHECK: int K = 0; + +// CHECK: def I2_2 +// CHECK: int I = 2; +// CHECK: int J = 0; +// CHECK: int K = 0; + +// CHECK: def I2_3 +// CHECK: int I = 3; +// CHECK: int J = 0; +// CHECK: int K = 0; + +// CHECK: def I3_1_J2_4_K1_1 +// CHECK: int I = 1; +// CHECK: int J = 4; +// CHECK: int K = 1; + +// CHECK: def I3_1_J2_4_K1_2 +// CHECK: int I = 1; +// CHECK: int J = 4; +// CHECK: int K = 2; + +// CHECK: def I3_1_J2_4_K1_3 +// CHECK: int I = 1; +// CHECK: int J = 4; +// CHECK: int K = 3; + +// CHECK: def I3_1_J2_5_K1_1 +// CHECK: int I = 1; +// CHECK: int J = 5; +// CHECK: int K = 1; + +// CHECK: def I3_1_J2_5_K1_2 +// CHECK: int I = 1; +// CHECK: int J = 5; +// CHECK: int K = 2; + +// CHECK: def I3_1_J2_5_K1_3 +// CHECK: int I = 1; +// CHECK: int J = 5; +// CHECK: int K = 3; + +// CHECK: def I3_1_J2_6_K1_1 +// CHECK: int I = 1; +// CHECK: int J = 6; +// CHECK: int K = 1; + +// CHECK: def I3_1_J2_6_K1_2 +// CHECK: int I = 1; +// CHECK: int J = 6; +// CHECK: int K = 2; + +// CHECK: def I3_1_J2_6_K1_3 +// CHECK: int I = 1; +// CHECK: int J = 6; +// CHECK: int K = 3; + +// CHECK: def I3_2_J2_4_K1_1 +// CHECK: int I = 2; +// CHECK: int J = 4; +// CHECK: int K = 1; + +// CHECK: def I3_2_J2_4_K1_2 +// CHECK: int I = 2; +// CHECK: int J = 4; +// CHECK: int K = 2; + +// CHECK: def I3_2_J2_4_K1_3 +// CHECK: int I = 2; +// CHECK: int J = 4; +// CHECK: int K = 3; + +// CHECK: def I3_2_J2_5_K1_1 +// CHECK: int I = 2; +// CHECK: int J = 5; +// CHECK: int K = 1; + +// CHECK: def I3_2_J2_5_K1_2 +// CHECK: int I = 2; +// CHECK: int J = 5; +// CHECK: int K = 2; + +// CHECK: def I3_2_J2_5_K1_3 +// CHECK: int I = 2; +// CHECK: int J = 5; +// CHECK: int K = 3; + +// CHECK: def I3_2_J2_6_K1_1 +// CHECK: int I = 2; +// CHECK: int J = 6; +// CHECK: int K = 1; + +// CHECK: def I3_2_J2_6_K1_2 +// CHECK: int I = 2; +// CHECK: int J = 6; +// CHECK: int K = 2; + +// CHECK: def I3_2_J2_6_K1_3 +// CHECK: int I = 2; +// CHECK: int J = 6; +// CHECK: int K = 3; + +// CHECK: def I3_3_J2_4_K1_1 +// CHECK: int I = 3; +// CHECK: int J = 4; +// CHECK: int K = 1; + +// CHECK: def I3_3_J2_4_K1_2 +// CHECK: int I = 3; +// CHECK: int J = 4; +// CHECK: int K = 2; + +// CHECK: def I3_3_J2_4_K1_3 +// CHECK: int I = 3; +// CHECK: int J = 4; +// CHECK: int K = 3; + +// CHECK: def I3_3_J2_5_K1_1 +// CHECK: int I = 3; +// CHECK: int J = 5; +// CHECK: int K = 1; + +// CHECK: def I3_3_J2_5_K1_2 +// CHECK: int I = 3; +// CHECK: int J = 5; +// CHECK: int K = 2; + +// CHECK: def I3_3_J2_5_K1_3 +// CHECK: int I = 3; +// CHECK: int J = 5; +// CHECK: int K = 3; + +// CHECK: def I3_3_J2_6_K1_1 +// CHECK: int I = 3; +// CHECK: int J = 6; +// CHECK: int K = 1; + +// CHECK: def I3_3_J2_6_K1_2 +// CHECK: int I = 3; +// CHECK: int J = 6; +// CHECK: int K = 2; + +// CHECK: def I3_3_J2_6_K1_3 +// CHECK: int I = 3; +// CHECK: int J = 6; +// CHECK: int K = 3; + +// CHECK: def I4_1_J3_4 +// CHECK: int I = 1; +// CHECK: int J = 4; +// CHECK: int K = 0; + +// CHECK: def I4_1_J3_5 +// CHECK: int I = 1; +// CHECK: int J = 5; +// CHECK: int K = 0; + +// CHECK: def I4_1_J3_6 +// CHECK: int I = 1; +// CHECK: int J = 6; +// CHECK: int K = 0; + +// CHECK: def I4_2_J3_4 +// CHECK: int I = 2; +// CHECK: int J = 4; +// CHECK: int K = 0; + +// CHECK: def I4_2_J3_5 +// CHECK: int I = 2; +// CHECK: int J = 5; +// CHECK: int K = 0; + +// CHECK: def I4_2_J3_6 +// CHECK: int I = 2; +// CHECK: int J = 6; +// CHECK: int K = 0; + +// CHECK: def I4_3_J3_4 +// CHECK: int I = 3; +// CHECK: int J = 4; +// CHECK: int K = 0; + +// CHECK: def I4_3_J3_5 +// CHECK: int I = 3; +// CHECK: int J = 5; +// CHECK: int K = 0; + +// CHECK: def I4_3_J3_6 +// CHECK: int I = 3; +// CHECK: int J = 6; +// CHECK: int K = 0; diff --git a/utils/emacs/tablegen-mode.el b/utils/emacs/tablegen-mode.el index 3853ce66a28..26b6639c185 100644 --- a/utils/emacs/tablegen-mode.el +++ b/utils/emacs/tablegen-mode.el @@ -13,7 +13,7 @@ (defvar tablegen-font-lock-keywords (let ((kw (regexp-opt '("class" "defm" "def" "field" "include" "in" - "let" "multiclass") + "let" "multiclass", "foreach") 'words)) (type-kw (regexp-opt '("bit" "bits" "code" "dag" "int" "list" "string") 'words)) diff --git a/utils/vim/tablegen.vim b/utils/vim/tablegen.vim index 30434899bc0..a9b0e4e3a4e 100644 --- a/utils/vim/tablegen.vim +++ b/utils/vim/tablegen.vim @@ -14,7 +14,7 @@ syntax sync minlines=100 syn case match -syn keyword tgKeyword def let in code dag field include defm +syn keyword tgKeyword def let in code dag field include defm foreach syn keyword tgType class int string list bit bits multiclass syn match tgNumber /\<\d\+\>/