diff --git a/docs/TableGenFundamentals.html b/docs/TableGenFundamentals.html index 147b5be3c43..5d64a089529 100644 --- a/docs/TableGenFundamentals.html +++ b/docs/TableGenFundamentals.html @@ -417,6 +417,10 @@ aborts with an error.
!subst(a, b, c)
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.
+
!patsubst(a, b, c)
+
patch regular expression 'a' against string 'c' and substitute string 'b' on +a match. 'b' may contain placeholders of the form $<digit>, where +<digit> is a number 1-9.
!regmatch(a, b)
An integer {0,1} indicating whether string 'b' matched regular expression 'a.'
diff --git a/test/TableGen/patsubst.td b/test/TableGen/patsubst.td new file mode 100644 index 00000000000..0a7b3d8219d --- /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 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 05bbc0a7fdb..e668468772c 100644 --- a/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -2025,7 +2025,7 @@ void CodeGenDAGPatterns::ParsePatterns() { } } 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 fa10799622c..2f500ae5c4f 100644 --- a/utils/TableGen/Record.cpp +++ b/utils/TableGen/Record.cpp @@ -18,6 +18,7 @@ #include #include #include +#include using namespace llvm; @@ -1034,6 +1035,69 @@ Init *TernOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) { } break; } + + case PATSUBST: { + StringInit *LHSs = dynamic_cast(LHS); + StringInit *MHSs = dynamic_cast(MHS); + StringInit *RHSs = dynamic_cast(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 TernOpInit::getAsString() const { 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 8ef833d554d..d8e4fb34b68 100644 --- a/utils/TableGen/Record.h +++ b/utils/TableGen/Record.h @@ -885,7 +885,7 @@ public: /// 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 378bffb3d2e..930d9dba5bd 100644 --- a/utils/TableGen/TGLexer.cpp +++ b/utils/TableGen/TGLexer.cpp @@ -449,6 +449,7 @@ tgtok::TokKind TGLexer::LexExclaim() { 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 06f6535949e..fef10f0c455 100644 --- a/utils/TableGen/TGLexer.h +++ b/utils/TableGen/TGLexer.h @@ -46,7 +46,7 @@ namespace tgtok { // !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 7d3d1b37a94..d2bc6b853dc 100644 --- a/utils/TableGen/TGParser.cpp +++ b/utils/TableGen/TGParser.cpp @@ -878,6 +878,7 @@ Init *TGParser::ParseOperation(Record *CurRec) { 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 @@ Init *TGParser::ParseOperation(Record *CurRec) { 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 @@ Init *TGParser::ParseOperation(Record *CurRec) { 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 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType) { 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;