diff --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst --- a/llvm/docs/TableGen/ProgRef.rst +++ b/llvm/docs/TableGen/ProgRef.rst @@ -1630,6 +1630,12 @@ This operator produces 1 if the string, list, or DAG *a* is empty; 0 otherwise. A dag is empty if it has no arguments; the operator does not count. +``!tolower(``\ *a*\ ``)`` + This operator converts a string input *a* to lower case. + +``!toupper(``\ *a*\ ``)`` + This operator converts a string input *a* to upper case. + ``!eq(`` *a*\ `,` *b*\ ``)`` This operator produces 1 if *a* is equal to *b*; 0 otherwise. The arguments must be ``bit``, ``bits``, ``int``, ``string``, or diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h --- a/llvm/include/llvm/TableGen/Record.h +++ b/llvm/include/llvm/TableGen/Record.h @@ -785,7 +785,18 @@ /// class UnOpInit : public OpInit, public FoldingSetNode { public: - enum UnaryOp : uint8_t { CAST, NOT, HEAD, TAIL, SIZE, EMPTY, GETDAGOP, LOG2 }; + enum UnaryOp : uint8_t { + TOLOWER, + TOUPPER, + CAST, + NOT, + HEAD, + TAIL, + SIZE, + EMPTY, + GETDAGOP, + LOG2 + }; private: Init *LHS; diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp --- a/llvm/lib/TableGen/Record.cpp +++ b/llvm/lib/TableGen/Record.cpp @@ -778,6 +778,14 @@ Init *UnOpInit::Fold(Record *CurRec, bool IsFinal) const { RecordKeeper &RK = getRecordKeeper(); switch (getOpcode()) { + case TOLOWER: + if (StringInit *LHSs = dyn_cast(LHS)) + return StringInit::get(RK, LHSs->getValue().lower()); + break; + case TOUPPER: + if (StringInit *LHSs = dyn_cast(LHS)) + return StringInit::get(RK, LHSs->getValue().upper()); + break; case CAST: if (isa(getType())) { if (StringInit *LHSs = dyn_cast(LHS)) @@ -927,6 +935,12 @@ case EMPTY: Result = "!empty"; break; case GETDAGOP: Result = "!getdagop"; break; case LOG2 : Result = "!logtwo"; break; + case TOLOWER: + Result = "!tolower"; + break; + case TOUPPER: + Result = "!toupper"; + break; } return Result + "(" + LHS->getAsString() + ")"; } diff --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h --- a/llvm/lib/TableGen/TGLexer.h +++ b/llvm/lib/TableGen/TGLexer.h @@ -29,11 +29,11 @@ class Twine; namespace tgtok { - enum TokKind { - // Markers +enum TokKind { + // Markers Eof, Error, - // Tokens with no info. + // Tokens with no info. minus, plus, // - + l_square, r_square, // [ ] l_brace, r_brace, // { } @@ -45,36 +45,36 @@ paste, // # dotdotdot, // ... - // Reserved keywords. ('ElseKW' is named to distinguish it from the - // existing 'Else' that means the preprocessor #else.) + // Reserved keywords. ('ElseKW' is named to distinguish it from the + // existing 'Else' that means the preprocessor #else.) Assert, Bit, Bits, Class, Code, Dag, Def, Defm, Defset, Defvar, ElseKW, FalseKW, Field, Foreach, If, In, Include, Int, Let, List, MultiClass, String, Then, TrueKW, - // Bang operators. + // Bang operators. XConcat, XADD, XSUB, XMUL, XDIV, XNOT, XLOG2, XAND, XOR, XXOR, XSRA, XSRL, XSHL, XListConcat, XListSplat, XStrConcat, XInterleave, XSubstr, XFind, XCast, XSubst, XForEach, XFilter, XFoldl, XHead, XTail, XSize, XEmpty, XIf, XCond, XEq, XIsA, XDag, XNe, XLe, XLt, XGe, XGt, XSetDagOp, XGetDagOp, - XExists, XListRemove, + XExists, XListRemove, XToLower, XToUpper, - // Boolean literals. + // Boolean literals. TrueVal, FalseVal, - // Integer value. - IntVal, + // Integer value. + IntVal, - // Binary constant. Note that these are sized according to the number of - // bits given. - BinaryIntVal, + // Binary constant. Note that these are sized according to the number of + // bits given. + BinaryIntVal, - // String valued tokens. + // String valued tokens. Id, StrVal, VarName, CodeFragment, - // Preprocessing tokens for internal usage by the lexer. - // They are never returned as a result of Lex(). + // Preprocessing tokens for internal usage by the lexer. + // They are never returned as a result of Lex(). Ifdef, Ifndef, Else, Endif, Define - }; +}; } /// TGLexer - TableGen Lexer class. diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp --- a/llvm/lib/TableGen/TGLexer.cpp +++ b/llvm/lib/TableGen/TGLexer.cpp @@ -549,50 +549,52 @@ // Check to see which operator this is. tgtok::TokKind Kind = - StringSwitch(StringRef(Start, CurPtr - Start)) - .Case("eq", tgtok::XEq) - .Case("ne", tgtok::XNe) - .Case("le", tgtok::XLe) - .Case("lt", tgtok::XLt) - .Case("ge", tgtok::XGe) - .Case("gt", tgtok::XGt) - .Case("if", tgtok::XIf) - .Case("cond", tgtok::XCond) - .Case("isa", tgtok::XIsA) - .Case("head", tgtok::XHead) - .Case("tail", tgtok::XTail) - .Case("size", tgtok::XSize) - .Case("con", tgtok::XConcat) - .Case("dag", tgtok::XDag) - .Case("add", tgtok::XADD) - .Case("sub", tgtok::XSUB) - .Case("mul", tgtok::XMUL) - .Case("div", tgtok::XDIV) - .Case("not", tgtok::XNOT) - .Case("logtwo", tgtok::XLOG2) - .Case("and", tgtok::XAND) - .Case("or", tgtok::XOR) - .Case("xor", tgtok::XXOR) - .Case("shl", tgtok::XSHL) - .Case("sra", tgtok::XSRA) - .Case("srl", tgtok::XSRL) - .Case("cast", tgtok::XCast) - .Case("empty", tgtok::XEmpty) - .Case("subst", tgtok::XSubst) - .Case("foldl", tgtok::XFoldl) - .Case("foreach", tgtok::XForEach) - .Case("filter", tgtok::XFilter) - .Case("listconcat", tgtok::XListConcat) - .Case("listsplat", tgtok::XListSplat) - .Case("listremove", tgtok::XListRemove) - .Case("strconcat", tgtok::XStrConcat) - .Case("interleave", tgtok::XInterleave) - .Case("substr", tgtok::XSubstr) - .Case("find", tgtok::XFind) - .Cases("setdagop", "setop", tgtok::XSetDagOp) // !setop is deprecated. - .Cases("getdagop", "getop", tgtok::XGetDagOp) // !getop is deprecated. - .Case("exists", tgtok::XExists) - .Default(tgtok::Error); + StringSwitch(StringRef(Start, CurPtr - Start)) + .Case("eq", tgtok::XEq) + .Case("ne", tgtok::XNe) + .Case("le", tgtok::XLe) + .Case("lt", tgtok::XLt) + .Case("ge", tgtok::XGe) + .Case("gt", tgtok::XGt) + .Case("if", tgtok::XIf) + .Case("cond", tgtok::XCond) + .Case("isa", tgtok::XIsA) + .Case("head", tgtok::XHead) + .Case("tail", tgtok::XTail) + .Case("size", tgtok::XSize) + .Case("con", tgtok::XConcat) + .Case("dag", tgtok::XDag) + .Case("add", tgtok::XADD) + .Case("sub", tgtok::XSUB) + .Case("mul", tgtok::XMUL) + .Case("div", tgtok::XDIV) + .Case("not", tgtok::XNOT) + .Case("logtwo", tgtok::XLOG2) + .Case("and", tgtok::XAND) + .Case("or", tgtok::XOR) + .Case("xor", tgtok::XXOR) + .Case("shl", tgtok::XSHL) + .Case("sra", tgtok::XSRA) + .Case("srl", tgtok::XSRL) + .Case("cast", tgtok::XCast) + .Case("empty", tgtok::XEmpty) + .Case("subst", tgtok::XSubst) + .Case("foldl", tgtok::XFoldl) + .Case("foreach", tgtok::XForEach) + .Case("filter", tgtok::XFilter) + .Case("listconcat", tgtok::XListConcat) + .Case("listsplat", tgtok::XListSplat) + .Case("listremove", tgtok::XListRemove) + .Case("strconcat", tgtok::XStrConcat) + .Case("interleave", tgtok::XInterleave) + .Case("substr", tgtok::XSubstr) + .Case("find", tgtok::XFind) + .Cases("setdagop", "setop", tgtok::XSetDagOp) // !setop is deprecated. + .Cases("getdagop", "getop", tgtok::XGetDagOp) // !getop is deprecated. + .Case("exists", tgtok::XExists) + .Case("tolower", tgtok::XToLower) + .Case("toupper", tgtok::XToUpper) + .Default(tgtok::Error); return Kind != tgtok::Error ? Kind : ReturnError(Start-1, "Unknown operator"); } diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp --- a/llvm/lib/TableGen/TGParser.cpp +++ b/llvm/lib/TableGen/TGParser.cpp @@ -944,6 +944,8 @@ TokError("unknown bang operator"); return nullptr; case tgtok::XNOT: + case tgtok::XToLower: + case tgtok::XToUpper: case tgtok::XLOG2: case tgtok::XHead: case tgtok::XTail: @@ -967,6 +969,16 @@ return nullptr; } + break; + case tgtok::XToLower: + Lex.Lex(); // eat the operation + Code = UnOpInit::TOLOWER; + Type = StringRecTy::get(Records); + break; + case tgtok::XToUpper: + Lex.Lex(); // eat the operation + Code = UnOpInit::TOUPPER; + Type = StringRecTy::get(Records); break; case tgtok::XNOT: Lex.Lex(); // eat the operation @@ -2445,6 +2457,8 @@ case tgtok::XSize: case tgtok::XEmpty: case tgtok::XCast: + case tgtok::XToLower: + case tgtok::XToUpper: case tgtok::XGetDagOp: // Value ::= !unop '(' Value ')' case tgtok::XExists: case tgtok::XIsA: diff --git a/llvm/test/TableGen/string_ops.td b/llvm/test/TableGen/string_ops.td new file mode 100644 --- /dev/null +++ b/llvm/test/TableGen/string_ops.td @@ -0,0 +1,39 @@ +// RUN: llvm-tblgen %s | FileCheck %s + +class ToLower { + string s = !tolower(str); +} + +class ToUpper { + string s = !toupper(str); +} + +// CHECK-LABEL: def LOWER1 { +// CHECK: string s = "str"; +// CHECK: } +def LOWER1: ToLower<"STR">; + +// CHECK-LABEL: def LOWER2 { +// CHECK: string s = "str"; +// CHECK: } +def LOWER2 : ToLower<"Str">; + +// CHECK-LABEL: def LOWER3 { +// CHECK: string s = "str"; +// CHECK: } +def LOWER3 : ToLower<"STr">; + +// CHECK-LABEL: def UPPER1 { +// CHECK: string s = "STR"; +// CHECK: } +def UPPER1 : ToUpper<"str">; + +// CHECK-LABEL: def UPPER2 { +// CHECK: string s = "STR"; +// CHECK: } +def UPPER2 : ToUpper<"sTr">; + +// CHECK-LABEL: def UPPER3 { +// CHECK: string s = "STR"; +// CHECK: } +def UPPER3 : ToUpper<"sTR">; \ No newline at end of file diff --git a/llvm/utils/kate/llvm-tablegen.xml b/llvm/utils/kate/llvm-tablegen.xml --- a/llvm/utils/kate/llvm-tablegen.xml +++ b/llvm/utils/kate/llvm-tablegen.xml @@ -42,6 +42,8 @@ !ge !gt !ne + !tolower + !toupper class