Implement !if, analogous to $(if) in GNU make.
authorDavid Greene <greened@obbligato.org>
Thu, 14 May 2009 23:26:46 +0000 (23:26 +0000)
committerDavid Greene <greened@obbligato.org>
Thu, 14 May 2009 23:26:46 +0000 (23:26 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@71815 91177308-0d34-0410-b5e6-96231b3b80d8

docs/TableGenFundamentals.html
test/TableGen/if.td [new file with mode: 0644]
utils/TableGen/Record.cpp
utils/TableGen/Record.h
utils/TableGen/TGLexer.cpp
utils/TableGen/TGLexer.h
utils/TableGen/TGParser.cpp

index 36798c8b8b82d949cfb7d7c8e70e909763008460..08838caf464c10015cb7755f847dbe3053cb10d5 100644 (file)
@@ -417,6 +417,8 @@ class.  This operation is analogous to $(foreach) in GNU make.</dd>
   <dd>The 2nd-N elements of list 'a.'</dd>
 <dt><tt>!null(a)</tt></dt>
   <dd>An integer {0,1} indicating whether list 'a' is empty.</dd>
+<dt><tt>!if(a,b,c)</tt></dt>
+  <dd>'b' if the result of integer operator 'a' is nonzero, 'c' otherwise.</dd>
 </dl>
 
 <p>Note that all of the values have rules specifying how they convert to values
diff --git a/test/TableGen/if.td b/test/TableGen/if.td
new file mode 100644 (file)
index 0000000..3c45d95
--- /dev/null
@@ -0,0 +1,20 @@
+// RUN: tblgen %s | grep {1, 2, 3} | count 4
+// RUN: tblgen %s | grep {4, 5, 6} | count 2
+
+class A<list<list<int>> vals> {
+  list<int> first = vals[0];
+  list<int> rest  = !if(!null(!cdr(vals)), vals[0], vals[1]);
+}
+
+def One : A<[[1,2,3]]>;
+def Two : A<[[1,2,3],[4,5,6]]>;
+
+class B<list<int> v> {
+  list<int> vals = v;
+}
+
+class BB<list<list<int>> vals> : B<!if(!null(!cdr(vals)), vals[0], vals[1])>;
+class BBB<list<list<int>> vals> : BB<vals>;
+
+def OneB : BBB<[[1,2,3]]>;
+def TwoB : BBB<[[1,2,3],[4,5,6]]>;
index ae2c2f3ea407157c413e9693b180b28dbf4fc51a..fc2de1c135ad379331adf4617030b8321f18db03 100644 (file)
@@ -912,6 +912,19 @@ Init *TernOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
     }
     break;
   }
+
+  case IF: {
+    IntInit *LHSi = dynamic_cast<IntInit*>(LHS);
+    if (LHSi) {
+      if (LHSi->getValue()) {
+        return MHS;
+      }
+      else {
+        return RHS;
+      }
+    }
+    break;
+  }
   }
 
   return this;
@@ -932,6 +945,7 @@ std::string TernOpInit::getAsString() const {
   switch (Opc) {
   case SUBST: Result = "!subst"; break;
   case FOREACH: Result = "!foreach"; break; 
+  case IF: Result = "!if"; break; 
  }
   return Result + "(" + LHS->getAsString() + ", " + MHS->getAsString() + ", " 
     + RHS->getAsString() + ")";
index c2549dab73a9b123a41bff4a72c363c8afb8fb61..2153a54c95a28b9beafcef2bb246062c82e9cf58 100644 (file)
@@ -843,7 +843,7 @@ public:
 ///
 class TernOpInit : public OpInit {
 public:
-  enum TernaryOp { SUBST, FOREACH };
+  enum TernaryOp { SUBST, FOREACH, IF };
 private:
   TernaryOp Opc;
   Init *LHS, *MHS, *RHS;
index faf1e75a6849db3834528686362d7ee0dec7ef30..758d499a8b5f317a40417555a72f871f8d5bebd4 100644 (file)
@@ -453,6 +453,7 @@ tgtok::TokKind TGLexer::LexExclaim() {
   if (Len == 3 && !memcmp(Start, "car", 3)) return tgtok::XCar;
   if (Len == 3 && !memcmp(Start, "cdr", 3)) return tgtok::XCdr;
   if (Len == 4 && !memcmp(Start, "null", 4)) return tgtok::XNull;
+  if (Len == 2 && !memcmp(Start, "if", 2)) return tgtok::XIf;
 
   return ReturnError(Start-1, "Unknown operator");
 }
index 3d27e5e8edb61b409fff9051286e1998fe38e7dc..ac3b9840039b2fa2dd9738e88c40b5b84cbb713f 100644 (file)
@@ -46,7 +46,7 @@ namespace tgtok {
     
     // !keywords.
     XConcat, XSRA, XSRL, XSHL, XStrConcat, XNameConcat, XCast, XSubst,
-    XForEach, XCar, XCdr, XNull,
+    XForEach, XCar, XCdr, XNull, XIf,
 
     // Integer value.
     IntVal,
index 8ff25a6186bd502794fc3e68400e2cdc559df87c..fc6f29fd9f1b5a17fc458445119522e992391b22 100644 (file)
@@ -862,6 +862,7 @@ Init *TGParser::ParseOperation(Record *CurRec) {
     return (new BinOpInit(Code, LHS, RHS, Type))->Fold(CurRec, CurMultiClass);
   }
 
+  case tgtok::XIf:
   case tgtok::XForEach:
   case tgtok::XSubst: {  // Value ::= !ternop '(' Value ',' Value ',' Value ')'
     TernOpInit::TernaryOp Code;
@@ -872,6 +873,9 @@ Init *TGParser::ParseOperation(Record *CurRec) {
     Lex.Lex();  // eat the operation
     switch (LexCode) {
     default: assert(0 && "Unhandled code!");
+    case tgtok::XIf:
+      Code = TernOpInit::IF;
+      break;
     case tgtok::XForEach:
       Code = TernOpInit::FOREACH;
       break;
@@ -914,6 +918,25 @@ Init *TGParser::ParseOperation(Record *CurRec) {
 
     switch (LexCode) {
     default: assert(0 && "Unhandled code!");
+    case tgtok::XIf: {
+      TypedInit *MHSt = dynamic_cast<TypedInit *>(MHS);
+      TypedInit *RHSt = dynamic_cast<TypedInit *>(RHS);
+      if (MHSt == 0 || RHSt == 0) {
+        TokError("could not get type for !if");
+        return 0;
+      }
+      if (MHSt->getType()->typeIsConvertibleTo(RHSt->getType())) {
+        Type = RHSt->getType();
+      }
+      else if (RHSt->getType()->typeIsConvertibleTo(MHSt->getType())) {
+        Type = MHSt->getType();
+      }
+      else {
+        TokError("inconsistent types for !if");
+        return 0;
+      }
+      break;
+    }
     case tgtok::XForEach: {
       TypedInit *MHSt = dynamic_cast<TypedInit *>(MHS);
       if (MHSt == 0) {
@@ -1152,6 +1175,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec) {
   case tgtok::XSHL:
   case tgtok::XStrConcat:
   case tgtok::XNameConcat:  // Value ::= !binop '(' Value ',' Value ')'
+  case tgtok::XIf:
   case tgtok::XForEach:
   case tgtok::XSubst: {  // Value ::= !ternop '(' Value ',' Value ',' Value ')'
     return ParseOperation(CurRec);