llvm.org GIT mirror llvm / cebb4ee
Add Foreach Loop Add some data structures to represent for loops. These will be referenced during object processing to do any needed iteration and instantiation. Add foreach keyword support to the lexer. Add a mode to indicate that we're parsing a foreach loop. This allows the value parser to early-out when processing the foreach value list. Add a routine to parse foreach iteration declarations. This is separate from ParseDeclaration because the type of the named value (the iterator) doesn't match the type of the initializer value (the value list). It also needs to add two values to the foreach record: the iterator and the value list. Add parsing support for foreach. Add the code to process foreach loops and create defs based on iterator values. Allow foreach loops to be matched at the top level. When parsing an IDValue check if it is a foreach loop iterator for one of the active loops. If so, return a VarInit for it. Add Emacs keyword support for foreach. Add VIM keyword support for foreach. Add tests to check foreach operation. Add TableGen documentation for foreach. Support foreach with multiple objects. Support non-braced foreach body with one object. Do not require types for the foreach declaration. Assume the iterator type from the iteration list element type. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@151164 91177308-0d34-0410-b5e6-96231b3b80d8 David Greene 7 years ago
12 changed file(s) with 777 addition(s) and 7 deletion(s). Raw diff Collapse all Expand all
3636
3737
  • File inclusion
  • 3838
  • 'let' expressions
  • 39
  • 'foreach' blocks
  • 3940
    4041
    4142
  • TableGen backends
  • 400401
    list[4-7,17,2-3]
    401402
    A slice of the 'list' list, including elements 4,5,6,7,17,2, and 3 from
    402403 it. Elements may be included multiple times.
    404
    foreach <var> = <list> in { <body> }
    405
    foreach <var> = <list> in <def>
    406
    Replicate <body> or <def>, replacing instances of
    407 <var> with each value in <list>. <var> is scoped at the
    408 level of the foreach loop and must not conflict with any other object
    409 introduced in <body> or <def>. Currently only defs are
    410 expanded within <body>.
    411
    403412
    (DEF a, b)
    404413
    a dag value. The first element is required to be a record definition, the
    405414 remaining elements in the list may be arbitrary other values, including nested
    879888
    880889
    881890
    891
    892

    893 Looping
    894
    895
    896
    897

    TableGen supports the 'foreach' block, which textually replicates

    898 the loop body, substituting iterator values for iterator references in the
    899 body. Example:

    900
    901
    902
    
                      
                    
    903 foreach i = [0, 1, 2, 3] in {
    904 def R#i : Register<...>;
    905 def F#i : Register<...>;
    906 }
    907
    908
    909
    910

    This will create objects R0, R1, R2 and

    911 R3. foreach blocks may be nested. If there is only
    912 one item in the body the braces may be elided:

    913
    914
    915
    
                      
                    
    916 foreach i = [0, 1, 2, 3] in
    917 def R#i : Register<...>;
    918
    919
    920
    921
    922
    923
    882924
    883925
    884926
    15341534
    15351535 class RecordKeeper {
    15361536 std::map Classes, Defs;
    1537
    15371538 public:
    15381539 ~RecordKeeper() {
    15391540 for (std::map::iterator I = Classes.begin(),
    273273 .Case("dag", tgtok::Dag)
    274274 .Case("class", tgtok::Class)
    275275 .Case("def", tgtok::Def)
    276 .Case("foreach", tgtok::Foreach)
    276277 .Case("defm", tgtok::Defm)
    277278 .Case("multiclass", tgtok::MultiClass)
    278279 .Case("field", tgtok::Field)
    4141 paste, // #
    4242
    4343 // Keywords.
    44 Bit, Bits, Class, Code, Dag, Def, Defm, Field, In, Int, Let, List,
    44 Bit, Bits, Class, Code, Dag, Def, Foreach, Defm, Field, In, Int, Let, List,
    4545 MultiClass, String,
    4646
    4747 // !keywords.
    288288 return false;
    289289 }
    290290
    291 /// ProcessForeachDefs - Given a record, apply all of the variable
    292 /// values in all surrounding foreach loops, creating new records for
    293 /// each combination of values.
    294 bool TGParser::ProcessForeachDefs(Record *CurRec, MultiClass *CurMultiClass,
    295 SMLoc Loc) {
    296 // We want to instantiate a new copy of CurRec for each combination
    297 // of nested loop iterator values. We don't want top instantiate
    298 // any copies until we have values for each loop iterator.
    299 IterSet IterVals;
    300 for (LoopVector::iterator Loop = Loops.begin(), LoopEnd = Loops.end();
    301 Loop != LoopEnd;
    302 ++Loop) {
    303 // Process this loop.
    304 if (ProcessForeachDefs(CurRec, CurMultiClass, Loc,
    305 IterVals, *Loop, Loop+1)) {
    306 Error(Loc,
    307 "Could not process loops for def " + CurRec->getNameInitAsString());
    308 return true;
    309 }
    310 }
    311
    312 return false;
    313 }
    314
    315 /// ProcessForeachDefs - Given a record, a loop and a loop iterator,
    316 /// apply each of the variable values in this loop and then process
    317 /// subloops.
    318 bool TGParser::ProcessForeachDefs(Record *CurRec, MultiClass *CurMultiClass,
    319 SMLoc Loc, IterSet &IterVals,
    320 ForeachLoop &CurLoop,
    321 LoopVector::iterator NextLoop) {
    322 Init *IterVar = CurLoop.IterVar;
    323 ListInit *List = dynamic_cast(CurLoop.ListValue);
    324
    325 if (List == 0) {
    326 Error(Loc, "Loop list is not a list");
    327 return true;
    328 }
    329
    330 // Process each value.
    331 for (int64_t i = 0; i < List->getSize(); ++i) {
    332 Init *ItemVal = List->resolveListElementReference(*CurRec, 0, i);
    333 IterVals.push_back(IterRecord(IterVar, ItemVal));
    334
    335 if (IterVals.size() == Loops.size()) {
    336 // Ok, we have all of the iterator values for this point in the
    337 // iteration space. Instantiate a new record to reflect this
    338 // combination of values.
    339 Record *IterRec = new Record(*CurRec);
    340
    341 // Set the iterator values now.
    342 for (IterSet::iterator i = IterVals.begin(), iend = IterVals.end();
    343 i != iend;
    344 ++i) {
    345 VarInit *IterVar = dynamic_cast(i->IterVar);
    346 if (IterVar == 0) {
    347 Error(Loc, "foreach iterator is unresolved");
    348 return true;
    349 }
    350
    351 TypedInit *IVal = dynamic_cast(i->IterValue);
    352 if (IVal == 0) {
    353 Error(Loc, "foreach iterator value is untyped");
    354 return true;
    355 }
    356
    357 IterRec->addValue(RecordVal(IterVar->getName(), IVal->getType(), false));
    358
    359 if (SetValue(IterRec, Loc, IterVar->getName(),
    360 std::vector(), IVal)) {
    361 Error(Loc, "when instantiating this def");
    362 return true;
    363 }
    364
    365 // Resolve it next.
    366 IterRec->resolveReferencesTo(IterRec->getValue(IterVar->getName()));
    367
    368 // Remove it.
    369 IterRec->removeValue(IterVar->getName());
    370 }
    371
    372 if (Records.getDef(IterRec->getNameInitAsString())) {
    373 Error(Loc, "def already exists: " + IterRec->getNameInitAsString());
    374 return true;
    375 }
    376
    377 Records.addDef(IterRec);
    378 IterRec->resolveReferences();
    379 }
    380
    381 if (NextLoop != Loops.end()) {
    382 // Process nested loops.
    383 if (ProcessForeachDefs(CurRec, CurMultiClass, Loc, IterVals, *NextLoop,
    384 NextLoop+1)) {
    385 Error(Loc,
    386 "Could not process loops for def " +
    387 CurRec->getNameInitAsString());
    388 return true;
    389 }
    390 }
    391
    392 // We're done with this iterator.
    393 IterVals.pop_back();
    394 }
    395 return false;
    396 }
    397
    291398 //===----------------------------------------------------------------------===//
    292399 // Parser Code
    293400 //===----------------------------------------------------------------------===//
    295402 /// isObjectStart - Return true if this is a valid first token for an Object.
    296403 static bool isObjectStart(tgtok::TokKind K) {
    297404 return K == tgtok::Class || K == tgtok::Def ||
    298 K == tgtok::Defm || K == tgtok::Let || K == tgtok::MultiClass;
    405 K == tgtok::Defm || K == tgtok::Let ||
    406 K == tgtok::MultiClass || K == tgtok::Foreach;
    299407 }
    300408
    301409 static std::string GetNewAnonymousName() {
    695803 assert(RV && "Template arg doesn't exist??");
    696804 return VarInit::get(MCName, RV->getType());
    697805 }
    806 }
    807
    808 // If this is in a foreach loop, make sure it's not a loop iterator
    809 for (LoopVector::iterator i = Loops.begin(), iend = Loops.end();
    810 i != iend;
    811 ++i) {
    812 VarInit *IterVar = dynamic_cast(i->IterVar);
    813 if (IterVar && IterVar->getName() == Name)
    814 return IterVar;
    698815 }
    699816
    700817 if (Mode == ParseNameMode)
    13521469 switch (Lex.getCode()) {
    13531470 default: return Result;
    13541471 case tgtok::l_brace: {
    1355 if (Mode == ParseNameMode)
    1472 if (Mode == ParseNameMode || Mode == ParseForeachMode)
    13561473 // This is the beginning of the object body.
    13571474 return Result;
    13581475
    16041721 return DeclName;
    16051722 }
    16061723
    1724 /// ParseForeachDeclaration - Read a foreach declaration, returning
    1725 /// the name of the declared object or a NULL Init on error. Return
    1726 /// the name of the parsed initializer list through ForeachListName.
    1727 ///
    1728 /// ForeachDeclaration ::= ID '=' Value
    1729 ///
    1730 Init *TGParser::ParseForeachDeclaration(Init *&ForeachListValue) {
    1731 if (Lex.getCode() != tgtok::Id) {
    1732 TokError("Expected identifier in foreach declaration");
    1733 return 0;
    1734 }
    1735
    1736 Init *DeclName = StringInit::get(Lex.getCurStrVal());
    1737 Lex.Lex();
    1738
    1739 // If a value is present, parse it.
    1740 if (Lex.getCode() != tgtok::equal) {
    1741 TokError("Expected '=' in foreach declaration");
    1742 return 0;
    1743 }
    1744 Lex.Lex(); // Eat the '='
    1745
    1746 // Expect a list initializer.
    1747 ForeachListValue = ParseValue(0, 0, ParseForeachMode);
    1748
    1749 TypedInit *TypedList = dynamic_cast(ForeachListValue);
    1750 if (TypedList == 0) {
    1751 TokError("Value list is untyped");
    1752 return 0;
    1753 }
    1754
    1755 RecTy *ValueType = TypedList->getType();
    1756 ListRecTy *ListType = dynamic_cast(ValueType);
    1757 if (ListType == 0) {
    1758 TokError("Value list is not of list type");
    1759 return 0;
    1760 }
    1761
    1762 RecTy *IterType = ListType->getElementType();
    1763 VarInit *IterVar = VarInit::get(DeclName, IterType);
    1764
    1765 return IterVar;
    1766 }
    1767
    16071768 /// ParseTemplateArgList - Read a template argument list, which is a non-empty
    16081769 /// sequence of template-declarations in <>'s. If CurRec is non-null, these are
    16091770 /// template args for a def, which may or may not be in a multiclass. If null,
    18151976 CurRec->addValue(*RV);
    18161977 }
    18171978 }
    1979
    1980 if (ProcessForeachDefs(CurRec, CurMultiClass, DefLoc)) {
    1981 Error(DefLoc,
    1982 "Could not process loops for def" + CurRec->getNameInitAsString());
    1983 return true;
    1984 }
    1985
    1986 return false;
    1987 }
    1988
    1989 /// ParseForeach - Parse a for statement. Return the record corresponding
    1990 /// to it. This returns true on error.
    1991 ///
    1992 /// Foreach ::= FOREACH Declaration IN '{ ObjectList '}'
    1993 /// Foreach ::= FOREACH Declaration IN Object
    1994 ///
    1995 bool TGParser::ParseForeach(MultiClass *CurMultiClass) {
    1996 assert(Lex.getCode() == tgtok::Foreach && "Unknown tok");
    1997 Lex.Lex(); // Eat the 'for' token.
    1998
    1999 // Make a temporary object to record items associated with the for
    2000 // loop.
    2001 Init *ListValue = 0;
    2002 Init *IterName = ParseForeachDeclaration(ListValue);
    2003 if (IterName == 0)
    2004 return TokError("expected declaration in for");
    2005
    2006 if (Lex.getCode() != tgtok::In)
    2007 return TokError("Unknown tok");
    2008 Lex.Lex(); // Eat the in
    2009
    2010 // Create a loop object and remember it.
    2011 Loops.push_back(ForeachLoop(IterName, ListValue));
    2012
    2013 if (Lex.getCode() != tgtok::l_brace) {
    2014 // FOREACH Declaration IN Object
    2015 if (ParseObject(CurMultiClass))
    2016 return true;
    2017 }
    2018 else {
    2019 SMLoc BraceLoc = Lex.getLoc();
    2020 // Otherwise, this is a group foreach.
    2021 Lex.Lex(); // eat the '{'.
    2022
    2023 // Parse the object list.
    2024 if (ParseObjectList(CurMultiClass))
    2025 return true;
    2026
    2027 if (Lex.getCode() != tgtok::r_brace) {
    2028 TokError("expected '}' at end of foreach command");
    2029 return Error(BraceLoc, "to match this '{'");
    2030 }
    2031 Lex.Lex(); // Eat the }
    2032 }
    2033
    2034 // We've processed everything in this loop.
    2035 Loops.pop_back();
    18182036
    18192037 return false;
    18202038 }
    20092227 case tgtok::Let:
    20102228 case tgtok::Def:
    20112229 case tgtok::Defm:
    2230 case tgtok::Foreach:
    20122231 if (ParseObject(CurMultiClass))
    20132232 return true;
    20142233 break;
    23042523 return TokError("Expected class, def, defm, multiclass or let definition");
    23052524 case tgtok::Let: return ParseTopLevelLet(MC);
    23062525 case tgtok::Def: return ParseDef(MC);
    2526 case tgtok::Foreach: return ParseForeach(MC);
    23072527 case tgtok::Defm: return ParseDefm(MC);
    23082528 case tgtok::Class: return ParseClass();
    23092529 case tgtok::MultiClass: return ParseMultiClass();
    4141 }
    4242 };
    4343
    44 /// ForeachLoop - Record the iteration state associated with a for loop.
    45 /// This is used to instantiate items in the loop body.
    46 struct ForeachLoop {
    47 Init *IterVar;
    48 Init *ListValue;
    49
    50 ForeachLoop(Init *IVar, Init *LValue) : IterVar(IVar), ListValue(LValue) {};
    51 };
    52
    4453 class TGParser {
    4554 TGLexer Lex;
    4655 std::vector > LetStack;
    4756 std::map MultiClasses;
    4857
    58 /// Loops - Keep track of any foreach loops we are within.
    59 ///
    60 typedef std::vector LoopVector;
    61 LoopVector Loops;
    62
    4963 /// CurMultiClass - If we are parsing a 'multiclass' definition, this is the
    5064 /// current value.
    5165 MultiClass *CurMultiClass;
    5973 // in the middle of creating in. For those situations, allow the
    6074 // parser to ignore missing object errors.
    6175 enum IDParseMode {
    62 ParseValueMode, // We are parsing a value we expect to look up.
    63 ParseNameMode // We are parsing a name of an object that does not yet exist.
    76 ParseValueMode, // We are parsing a value we expect to look up.
    77 ParseNameMode, // We are parsing a name of an object that does not yet
    78 // exist.
    79 ParseForeachMode // We are parsing a foreach init.
    6480 };
    6581
    6682 public:
    8197 const std::vector &getDependencies() const {
    8298 return Lex.getDependencies();
    8399 }
    100
    84101 private: // Semantic analysis methods.
    85102 bool AddValue(Record *TheRec, SMLoc Loc, const RecordVal &RV);
    86103 bool SetValue(Record *TheRec, SMLoc Loc, Init *ValName,
    92109 bool AddSubClass(Record *Rec, SubClassReference &SubClass);
    93110 bool AddSubMultiClass(MultiClass *CurMC,
    94111 SubMultiClassReference &SubMultiClass);
    112
    113 // IterRecord: Map an iterator name to a value.
    114 struct IterRecord {
    115 Init *IterVar;
    116 Init *IterValue;
    117 IterRecord(Init *Var, Init *Val) : IterVar(Var), IterValue(Val) {}
    118 };
    119
    120 // IterSet: The set of all iterator values at some point in the
    121 // iteration space.
    122 typedef std::vector IterSet;
    123
    124 bool ProcessForeachDefs(Record *CurRec, MultiClass *CurMultiClass,
    125 SMLoc Loc);
    126 bool ProcessForeachDefs(Record *CurRec, MultiClass *CurMultiClass,
    127 SMLoc Loc, IterSet &IterVals, ForeachLoop &CurLoop,
    128 LoopVector::iterator NextLoop);
    95129
    96130 private: // Parser methods.
    97131 bool ParseObjectList(MultiClass *MC = 0);
    115149 SMLoc DefmPrefixLoc);
    116150 bool ParseDefm(MultiClass *CurMultiClass);
    117151 bool ParseDef(MultiClass *CurMultiClass);
    152 bool ParseForeach(MultiClass *CurMultiClass);
    118153 bool ParseTopLevelLet(MultiClass *CurMultiClass);
    119154 std::vector ParseLetList();
    120155
    124159
    125160 bool ParseTemplateArgList(Record *CurRec);
    126161 Init *ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs);
    162 Init *ParseForeachDeclaration(Init *&ForeachListValue);
    127163
    128164 SubClassReference ParseSubClassReference(Record *CurRec, bool isDefm);
    129165 SubMultiClassReference ParseSubMultiClassReference(MultiClass *CurMC);
    0 // RUN: llvm-tblgen %s | FileCheck %s
    1 // XFAIL: vg_leak
    2
    3 class Register {
    4 string Name = name;
    5 int Index = idx;
    6 }
    7
    8 foreach i = [0, 1, 2, 3, 4, 5, 6, 7] in {
    9 def R#i : Register<"R"#i, i>;
    10 def F#i : Register<"F"#i, i>;
    11 }
    12
    13 // CHECK: def F0
    14 // CHECK: string Name = "F0";
    15 // CHECK: int Index = 0;
    16
    17 // CHECK: def F1
    18 // CHECK: string Name = "F1";
    19 // CHECK: int Index = 1;
    20
    21 // CHECK: def F2
    22 // CHECK: string Name = "F2";
    23 // CHECK: int Index = 2;
    24
    25 // CHECK: def F3
    26 // CHECK: string Name = "F3";
    27 // CHECK: int Index = 3;
    28
    29 // CHECK: def F4
    30 // CHECK: string Name = "F4";
    31 // CHECK: int Index = 4;
    32
    33 // CHECK: def F5
    34 // CHECK: string Name = "F5";
    35 // CHECK: int Index = 5;
    36
    37 // CHECK: def F6
    38 // CHECK: string Name = "F6";
    39 // CHECK: int Index = 6;
    40
    41 // CHECK: def F7
    42 // CHECK: string Name = "F7";
    43 // CHECK: int Index = 7;
    44
    45 // CHECK: def R0
    46 // CHECK: string Name = "R0";
    47 // CHECK: int Index = 0;
    48
    49 // CHECK: def R1
    50 // CHECK: string Name = "R1";
    51 // CHECK: int Index = 1;
    52
    53 // CHECK: def R2
    54 // CHECK: string Name = "R2";
    55 // CHECK: int Index = 2;
    56
    57 // CHECK: def R3
    58 // CHECK: string Name = "R3";
    59 // CHECK: int Index = 3;
    60
    61 // CHECK: def R4
    62 // CHECK: string Name = "R4";
    63 // CHECK: int Index = 4;
    64
    65 // CHECK: def R5
    66 // CHECK: string Name = "R5";
    67 // CHECK: int Index = 5;
    68
    69 // CHECK: def R6
    70 // CHECK: string Name = "R6";
    71 // CHECK: int Index = 6;
    72
    73 // CHECK: def R7
    74 // CHECK: string Name = "R7";
    75 // CHECK: int Index = 7;
    0 // RUN: llvm-tblgen %s | FileCheck %s
    1 // XFAIL: vg_leak
    2
    3 class Register {
    4 string Name = name;
    5 int Index = idx;
    6 }
    7
    8 foreach i = [0, 1, 2, 3, 4, 5, 6, 7] in
    9 def R#i : Register<"R"#i, i>;
    10
    11
    12 // CHECK: def R0
    13 // CHECK: string Name = "R0";
    14 // CHECK: int Index = 0;
    15
    16 // CHECK: def R1
    17 // CHECK: string Name = "R1";
    18 // CHECK: int Index = 1;
    19
    20 // CHECK: def R2
    21 // CHECK: string Name = "R2";
    22 // CHECK: int Index = 2;
    23
    24 // CHECK: def R3
    25 // CHECK: string Name = "R3";
    26 // CHECK: int Index = 3;
    27
    28 // CHECK: def R4
    29 // CHECK: string Name = "R4";
    30 // CHECK: int Index = 4;
    31
    32 // CHECK: def R5
    33 // CHECK: string Name = "R5";
    34 // CHECK: int Index = 5;
    35
    36 // CHECK: def R6
    37 // CHECK: string Name = "R6";
    38 // CHECK: int Index = 6;
    39
    40 // CHECK: def R7
    41 // CHECK: string Name = "R7";
    42 // CHECK: int Index = 7;
    0 // RUN: llvm-tblgen %s | FileCheck %s
    1 // XFAIL: vg_leak
    2
    3 class Droid {
    4 string Series = series;
    5 int Release = release;
    6 string Model = model;
    7 int Patchlevel = patchlevel;
    8 }
    9
    10 foreach S = ["R", "C"] in {
    11 foreach R = [2, 3, 4] in {
    12 foreach M = ["D", "P", "Q"] in {
    13 foreach P = [0, 2, 4] in {
    14 def S#R#M#P : Droid;
    15 }
    16 }
    17 }
    18 }
    19
    20 // CHECK: def C2D0
    21 // CHECK: def C2D2
    22 // CHECK: def C2D4
    23 // CHECK: def C2P0
    24 // CHECK: def C2P2
    25 // CHECK: def C2P4
    26 // CHECK: def C2Q0
    27 // CHECK: def C2Q2
    28 // CHECK: def C2Q4
    29 // CHECK: def C3D0
    30 // CHECK: def C3D2
    31 // CHECK: def C3D4
    32 // CHECK: def C3P0
    33 // CHECK: def C3P2
    34 // CHECK: def C3P4
    35 // CHECK: def C3Q0
    36 // CHECK: def C3Q2
    37 // CHECK: def C3Q4
    38 // CHECK: def C4D0
    39 // CHECK: def C4D2
    40 // CHECK: def C4D4
    41 // CHECK: def C4P0
    42 // CHECK: def C4P2
    43 // CHECK: def C4P4
    44 // CHECK: def C4Q0
    45 // CHECK: def C4Q2
    46 // CHECK: def C4Q4
    47 // CHECK: def R2D0
    48 // CHECK: def R2D2
    49 // CHECK: def R2D4
    50 // CHECK: def R2P0
    51 // CHECK: def R2P2
    52 // CHECK: def R2P4
    53 // CHECK: def R2Q0
    54 // CHECK: def R2Q2
    55 // CHECK: def R2Q4
    56 // CHECK: def R3D0
    57 // CHECK: def R3D2
    58 // CHECK: def R3D4
    59 // CHECK: def R3P0
    60 // CHECK: def R3P2
    61 // CHECK: def R3P4
    62 // CHECK: def R3Q0
    63 // CHECK: def R3Q2
    64 // CHECK: def R3Q4
    65 // CHECK: def R4D0
    66 // CHECK: def R4D2
    67 // CHECK: def R4D4
    68 // CHECK: def R4P0
    69 // CHECK: def R4P2
    70 // CHECK: def R4P4
    71 // CHECK: def R4Q0
    72 // CHECK: def R4Q2
    73 // CHECK: def R4Q4
    0 // RUN: llvm-tblgen %s | FileCheck %s
    1 // XFAIL: vg_leak
    2
    3 class Set {
    4 int I = i;
    5 int J = j;
    6 int K = k;
    7 }
    8
    9 foreach i = [1, 2, 3] in {
    10 def I1_#i : Set;
    11 foreach j = [1, 2, 3] in {
    12 def I1_#i#_J1_#j : Set;
    13 }
    14 def I2_#i : Set;
    15 foreach j = [4, 5, 6] in {
    16 foreach k = [1, 2, 3] in {
    17 def I3_#i#_J2_#j#_K1_#k : Set;
    18 }
    19 def I4_#i#_J3_#j : Set;
    20 }
    21 }
    22
    23 // CHECK: def I1_1
    24 // CHECK: int I = 1;
    25 // CHECK: int J = 0;
    26 // CHECK: int K = 0;
    27
    28 // CHECK: def I1_1_J1_1
    29 // CHECK: int I = 1;
    30 // CHECK: int J = 1;
    31 // CHECK: int K = 0;
    32
    33 // CHECK: def I1_1_J1_2
    34 // CHECK: int I = 1;
    35 // CHECK: int J = 2;
    36 // CHECK: int K = 0;
    37
    38 // CHECK: def I1_1_J1_3
    39 // CHECK: int I = 1;
    40 // CHECK: int J = 3;
    41 // CHECK: int K = 0;
    42
    43 // CHECK: def I1_2
    44 // CHECK: int I = 2;
    45 // CHECK: int J = 0;
    46 // CHECK: int K = 0;
    47
    48 // CHECK: def I1_2_J1_1
    49 // CHECK: int I = 2;
    50 // CHECK: int J = 1;
    51 // CHECK: int K = 0;
    52
    53 // CHECK: def I1_2_J1_2
    54 // CHECK: int I = 2;
    55 // CHECK: int J = 2;
    56 // CHECK: int K = 0;
    57
    58 // CHECK: def I1_2_J1_3
    59 // CHECK: int I = 2;
    60 // CHECK: int J = 3;
    61 // CHECK: int K = 0;
    62
    63 // CHECK: def I1_3
    64 // CHECK: int I = 3;
    65 // CHECK: int J = 0;
    66 // CHECK: int K = 0;
    67
    68 // CHECK: def I1_3_J1_1
    69 // CHECK: int I = 3;
    70 // CHECK: int J = 1;
    71 // CHECK: int K = 0;
    72
    73 // CHECK: def I1_3_J1_2
    74 // CHECK: int I = 3;
    75 // CHECK: int J = 2;
    76 // CHECK: int K = 0;
    77
    78 // CHECK: def I1_3_J1_3
    79 // CHECK: int I = 3;
    80 // CHECK: int J = 3;
    81 // CHECK: int K = 0;
    82
    83 // CHECK: def I2_1
    84 // CHECK: int I = 1;
    85 // CHECK: int J = 0;
    86 // CHECK: int K = 0;
    87
    88 // CHECK: def I2_2
    89 // CHECK: int I = 2;
    90 // CHECK: int J = 0;
    91 // CHECK: int K = 0;
    92
    93 // CHECK: def I2_3
    94 // CHECK: int I = 3;
    95 // CHECK: int J = 0;
    96 // CHECK: int K = 0;
    97
    98 // CHECK: def I3_1_J2_4_K1_1
    99 // CHECK: int I = 1;
    100 // CHECK: int J = 4;
    101 // CHECK: int K = 1;
    102
    103 // CHECK: def I3_1_J2_4_K1_2
    104 // CHECK: int I = 1;
    105 // CHECK: int J = 4;
    106 // CHECK: int K = 2;
    107
    108 // CHECK: def I3_1_J2_4_K1_3
    109 // CHECK: int I = 1;
    110 // CHECK: int J = 4;
    111 // CHECK: int K = 3;
    112
    113 // CHECK: def I3_1_J2_5_K1_1
    114 // CHECK: int I = 1;
    115 // CHECK: int J = 5;
    116 // CHECK: int K = 1;
    117
    118 // CHECK: def I3_1_J2_5_K1_2
    119 // CHECK: int I = 1;
    120 // CHECK: int J = 5;
    121 // CHECK: int K = 2;
    122
    123 // CHECK: def I3_1_J2_5_K1_3
    124 // CHECK: int I = 1;
    125 // CHECK: int J = 5;
    126 // CHECK: int K = 3;
    127
    128 // CHECK: def I3_1_J2_6_K1_1
    129 // CHECK: int I = 1;
    130 // CHECK: int J = 6;
    131 // CHECK: int K = 1;
    132
    133 // CHECK: def I3_1_J2_6_K1_2
    134 // CHECK: int I = 1;
    135 // CHECK: int J = 6;
    136 // CHECK: int K = 2;
    137
    138 // CHECK: def I3_1_J2_6_K1_3
    139 // CHECK: int I = 1;
    140 // CHECK: int J = 6;
    141 // CHECK: int K = 3;
    142
    143 // CHECK: def I3_2_J2_4_K1_1
    144 // CHECK: int I = 2;
    145 // CHECK: int J = 4;
    146 // CHECK: int K = 1;
    147
    148 // CHECK: def I3_2_J2_4_K1_2
    149 // CHECK: int I = 2;
    150 // CHECK: int J = 4;
    151 // CHECK: int K = 2;
    152
    153 // CHECK: def I3_2_J2_4_K1_3
    154 // CHECK: int I = 2;
    155 // CHECK: int J = 4;
    156 // CHECK: int K = 3;
    157
    158 // CHECK: def I3_2_J2_5_K1_1
    159 // CHECK: int I = 2;
    160 // CHECK: int J = 5;
    161 // CHECK: int K = 1;
    162
    163 // CHECK: def I3_2_J2_5_K1_2
    164 // CHECK: int I = 2;
    165 // CHECK: int J = 5;
    166 // CHECK: int K = 2;
    167
    168 // CHECK: def I3_2_J2_5_K1_3
    169 // CHECK: int I = 2;
    170 // CHECK: int J = 5;
    171 // CHECK: int K = 3;
    172
    173 // CHECK: def I3_2_J2_6_K1_1
    174 // CHECK: int I = 2;
    175 // CHECK: int J = 6;
    176 // CHECK: int K = 1;
    177
    178 // CHECK: def I3_2_J2_6_K1_2
    179 // CHECK: int I = 2;
    180 // CHECK: int J = 6;
    181 // CHECK: int K = 2;
    182
    183 // CHECK: def I3_2_J2_6_K1_3
    184 // CHECK: int I = 2;
    185 // CHECK: int J = 6;
    186 // CHECK: int K = 3;
    187
    188 // CHECK: def I3_3_J2_4_K1_1
    189 // CHECK: int I = 3;
    190 // CHECK: int J = 4;
    191 // CHECK: int K = 1;
    192
    193 // CHECK: def I3_3_J2_4_K1_2
    194 // CHECK: int I = 3;
    195 // CHECK: int J = 4;
    196 // CHECK: int K = 2;
    197
    198 // CHECK: def I3_3_J2_4_K1_3
    199 // CHECK: int I = 3;
    200 // CHECK: int J = 4;
    201 // CHECK: int K = 3;
    202
    203 // CHECK: def I3_3_J2_5_K1_1
    204 // CHECK: int I = 3;
    205 // CHECK: int J = 5;
    206 // CHECK: int K = 1;
    207
    208 // CHECK: def I3_3_J2_5_K1_2
    209 // CHECK: int I = 3;
    210 // CHECK: int J = 5;
    211 // CHECK: int K = 2;
    212
    213 // CHECK: def I3_3_J2_5_K1_3
    214 // CHECK: int I = 3;
    215 // CHECK: int J = 5;
    216 // CHECK: int K = 3;
    217
    218 // CHECK: def I3_3_J2_6_K1_1
    219 // CHECK: int I = 3;
    220 // CHECK: int J = 6;
    221 // CHECK: int K = 1;
    222
    223 // CHECK: def I3_3_J2_6_K1_2
    224 // CHECK: int I = 3;
    225 // CHECK: int J = 6;
    226 // CHECK: int K = 2;
    227
    228 // CHECK: def I3_3_J2_6_K1_3
    229 // CHECK: int I = 3;
    230 // CHECK: int J = 6;
    231 // CHECK: int K = 3;
    232
    233 // CHECK: def I4_1_J3_4
    234 // CHECK: int I = 1;
    235 // CHECK: int J = 4;
    236 // CHECK: int K = 0;
    237
    238 // CHECK: def I4_1_J3_5
    239 // CHECK: int I = 1;
    240 // CHECK: int J = 5;
    241 // CHECK: int K = 0;
    242
    243 // CHECK: def I4_1_J3_6
    244 // CHECK: int I = 1;
    245 // CHECK: int J = 6;
    246 // CHECK: int K = 0;
    247
    248 // CHECK: def I4_2_J3_4
    249 // CHECK: int I = 2;
    250 // CHECK: int J = 4;
    251 // CHECK: int K = 0;
    252
    253 // CHECK: def I4_2_J3_5
    254 // CHECK: int I = 2;
    255 // CHECK: int J = 5;
    256 // CHECK: int K = 0;
    257
    258 // CHECK: def I4_2_J3_6
    259 // CHECK: int I = 2;
    260 // CHECK: int J = 6;
    261 // CHECK: int K = 0;
    262
    263 // CHECK: def I4_3_J3_4
    264 // CHECK: int I = 3;
    265 // CHECK: int J = 4;
    266 // CHECK: int K = 0;
    267
    268 // CHECK: def I4_3_J3_5
    269 // CHECK: int I = 3;
    270 // CHECK: int J = 5;
    271 // CHECK: int K = 0;
    272
    273 // CHECK: def I4_3_J3_6
    274 // CHECK: int I = 3;
    275 // CHECK: int J = 6;
    276 // CHECK: int K = 0;
    1212
    1313 (defvar tablegen-font-lock-keywords
    1414 (let ((kw (regexp-opt '("class" "defm" "def" "field" "include" "in"
    15 "let" "multiclass")
    15 "let" "multiclass", "foreach")
    1616 'words))
    1717 (type-kw (regexp-opt '("bit" "bits" "code" "dag" "int" "list" "string")
    1818 'words))
    1313
    1414 syn case match
    1515
    16 syn keyword tgKeyword def let in code dag field include defm
    16 syn keyword tgKeyword def let in code dag field include defm foreach
    1717 syn keyword tgType class int string list bit bits multiclass
    1818
    1919 syn match tgNumber /\<\d\+\>/