Add a !patsubst operator.  Use on string types.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@73099 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/docs/TableGenFundamentals.html b/docs/TableGenFundamentals.html
index 147b5be..5d64a08 100644
--- a/docs/TableGenFundamentals.html
+++ b/docs/TableGenFundamentals.html
@@ -417,6 +417,10 @@
 <dt><tt>!subst(a, b, c)</tt></dt>
   <dd>If 'a' and 'b' are of string type or are symbol references, substitute 
 'b' for 'a' in 'c.'  This operation is analogous to $(subst) in GNU make.</dd>
+<dt><tt>!patsubst(a, b, c)</tt></dt>
+  <dd>patch regular expression 'a' against string 'c' and substitute string 'b' on 
+a match.  'b' may contain placeholders of the form $&lt;digit&gt;, where 
+&lt;digit&gt; is a number 1-9.</dd>
 <dt><tt>!regmatch(a, b)</tt></dt>
   <dd>An integer {0,1} indicating whether string 'b' matched regular expression
 'a.'</dd>
diff --git a/test/TableGen/patsubst.td b/test/TableGen/patsubst.td
new file mode 100644
index 0000000..0a7b3d8
--- /dev/null
+++ b/test/TableGen/patsubst.td
@@ -0,0 +1,15 @@
+// RUN: tblgen %s | grep {Match1 = "v4f32"} | count 1
+// RUN: tblgen %s | grep {Match2 = "v2f64"} | count 1
+// RUN: tblgen %s | grep {Match3 = "v4f32 add"} | count 1
+// RUN: tblgen %s | grep {Match4 = "v2f64 add"} | count 1
+
+class Foo<string v> {
+      string Value = v;
+      string Match1 = !patsubst(".*ps$", "v4f32", v);
+      string Match2 = !patsubst(".*pd$", "v2f64", v);
+      string Match3 = !patsubst("(.*)ps$", "v4f32 $1", v);
+      string Match4 = !patsubst("(.*)pd$", "v2f64 $1", v);
+}
+
+def Bar : Foo<"addps">;
+def Baz : Foo<"addpd">;
diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp
index 05bbc0a..e668468 100644
--- a/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -2025,7 +2025,7 @@
           }
         }
         else {
-          ListTy - TArg->getType();
+          ListTy = TArg->getType();
         }
       }
       ListInit *LI = new ListInit(Values, new ListRecTy(ListTy));
diff --git a/utils/TableGen/Record.cpp b/utils/TableGen/Record.cpp
index fa10799..2f500ae 100644
--- a/utils/TableGen/Record.cpp
+++ b/utils/TableGen/Record.cpp
@@ -18,6 +18,7 @@
 #include <ios>
 #include <sys/types.h>
 #include <regex.h>
+#include <sstream>
 
 using namespace llvm;
 
@@ -1034,6 +1035,69 @@
     }
     break;
   }
+
+  case PATSUBST: {
+    StringInit *LHSs = dynamic_cast<StringInit*>(LHS);
+    StringInit *MHSs = dynamic_cast<StringInit*>(MHS);
+    StringInit *RHSs = dynamic_cast<StringInit*>(RHS);
+
+    if (LHSs && MHSs && RHSs) {
+      regex_t compiled;
+      int err = regcomp (&compiled, LHSs->getValue().c_str(), REG_EXTENDED);
+      if (err != 0) {
+        size_t length = regerror (err, &compiled, NULL, 0);
+        char *buffer = new char[length];
+        (void) regerror (err, &compiled, buffer, length);
+        std::string errmsg = buffer;
+        delete[] buffer;
+        regfree(&compiled);
+        throw errmsg;
+      }
+      regmatch_t matches[10];
+      int result = regexec(&compiled, RHSs->getValue().c_str(), 10, matches, 0);
+      if (result == REG_ESPACE) {
+        size_t length = regerror (err, &compiled, NULL, 0);
+        char *buffer = new char[length];
+        (void) regerror (err, &compiled, buffer, length);
+        std::string errmsg = buffer;
+        delete[] buffer;
+        regfree(&compiled);
+        throw errmsg;
+      }
+      regfree(&compiled);
+      if (result == 0) {
+        // Parse the substitution string looking for $1, $2, etc. and
+        // substitute strings.  If there are no $1, etc. just replace
+        // the whole string.
+        std::string replacement = MHSs->getValue();
+        size_t pos = replacement.find("$");
+        while (pos != std::string::npos && pos+1 < replacement.size()) {
+          if (std::isdigit(replacement[pos+1])) {
+            std::string sidx(&replacement[pos+1], 1);
+            std::istringstream str(sidx);
+            int idx;
+            if (str >> idx) {              
+              replacement.replace(pos, 2, RHSs->getValue(), matches[idx].rm_so,
+                                  matches[idx].rm_eo - matches[idx].rm_so);
+            }
+            else {
+              throw "unexpected failure in patsubst index calculation";
+            }
+          }
+          else if (replacement[pos+1] == '$') {
+            replacement.replace(pos, 2, "$");
+          }
+          pos = replacement.find("$", pos+1);
+        }
+        return new StringInit(replacement);
+      }
+      else {
+        // No match, just pass the string through
+        return RHSs;
+      }
+    }
+    break;
+  }  
   }
 
   return this;
@@ -1069,6 +1133,7 @@
   std::string Result;
   switch (Opc) {
   case SUBST: Result = "!subst"; break;
+  case PATSUBST: Result = "!patsubst"; break;
   case FOREACH: Result = "!foreach"; break; 
   case IF: Result = "!if"; break; 
  }
diff --git a/utils/TableGen/Record.h b/utils/TableGen/Record.h
index 8ef833d..d8e4fb3 100644
--- a/utils/TableGen/Record.h
+++ b/utils/TableGen/Record.h
@@ -885,7 +885,7 @@
 ///
 class TernOpInit : public OpInit {
 public:
-  enum TernaryOp { SUBST, FOREACH, IF };
+  enum TernaryOp { SUBST, FOREACH, IF, PATSUBST };
 private:
   TernaryOp Opc;
   Init *LHS, *MHS, *RHS;
diff --git a/utils/TableGen/TGLexer.cpp b/utils/TableGen/TGLexer.cpp
index 378bffb..930d9db 100644
--- a/utils/TableGen/TGLexer.cpp
+++ b/utils/TableGen/TGLexer.cpp
@@ -449,6 +449,7 @@
   if (Len == 10 && !memcmp(Start, "nameconcat", 10)) return tgtok::XNameConcat;
   if (Len == 8 && !memcmp(Start, "regmatch", 8)) return tgtok::XRegMatch;
   if (Len == 5 && !memcmp(Start, "subst", 5)) return tgtok::XSubst;
+  if (Len == 8 && !memcmp(Start, "patsubst", 8)) return tgtok::XPatSubst;
   if (Len == 7 && !memcmp(Start, "foreach", 7)) return tgtok::XForEach;
   if (Len == 4 && !memcmp(Start, "cast", 4)) return tgtok::XCast;
   if (Len == 3 && !memcmp(Start, "car", 3)) return tgtok::XCar;
diff --git a/utils/TableGen/TGLexer.h b/utils/TableGen/TGLexer.h
index 06f6535..fef10f0 100644
--- a/utils/TableGen/TGLexer.h
+++ b/utils/TableGen/TGLexer.h
@@ -46,7 +46,7 @@
     
     // !keywords.
     XConcat, XSRA, XSRL, XSHL, XStrConcat, XNameConcat, XCast, XSubst,
-    XForEach, XCar, XCdr, XNull, XIf, XRegMatch,
+    XForEach, XCar, XCdr, XNull, XIf, XRegMatch, XPatSubst,
 
     // Integer value.
     IntVal,
diff --git a/utils/TableGen/TGParser.cpp b/utils/TableGen/TGParser.cpp
index 7d3d1b3..d2bc6b8 100644
--- a/utils/TableGen/TGParser.cpp
+++ b/utils/TableGen/TGParser.cpp
@@ -878,6 +878,7 @@
 
   case tgtok::XIf:
   case tgtok::XForEach:
+  case tgtok::XPatSubst:
   case tgtok::XSubst: {  // Value ::= !ternop '(' Value ',' Value ',' Value ')'
     TernOpInit::TernaryOp Code;
     RecTy *Type = 0;
@@ -896,6 +897,9 @@
     case tgtok::XSubst:
       Code = TernOpInit::SUBST;
       break;
+    case tgtok::XPatSubst:
+      Code = TernOpInit::PATSUBST;
+      break;
     }
     if (Lex.getCode() != tgtok::l_paren) {
       TokError("expected '(' after ternary operator");
@@ -969,6 +973,10 @@
       Type = RHSt->getType();
       break;
     }
+    case tgtok::XPatSubst: {
+      Type = new StringRecTy;
+      break;
+    }      
     }
     return (new TernOpInit(Code, LHS, MHS, RHS, Type))->Fold(CurRec, CurMultiClass);
   }
@@ -1277,6 +1285,7 @@
   case tgtok::XNameConcat:  // Value ::= !binop '(' Value ',' Value ')'
   case tgtok::XIf:
   case tgtok::XForEach:
+  case tgtok::XPatSubst:
   case tgtok::XSubst: {  // Value ::= !ternop '(' Value ',' Value ',' Value ')'
     return ParseOperation(CurRec);
     break;