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 @@ -223,10 +223,10 @@ : !div !empty !eq !filter !find : !foldl !foreach !ge !getdagop !gt : !head !if !interleave !isa !le - : !listconcat !listsplat !lt !mul !ne - : !not !or !setdagop !shl !size - : !sra !srl !strconcat !sub !subst - : !substr !tail !xor + : !listconcat !listsplat !logtwo !lt !mul + : !ne !not !or !setdagop !shl + : !size !sra !srl !strconcat !sub + : !subst !substr !tail !xor The ``!cond`` operator has a slightly different syntax compared to other bang operators, so it is defined separately: @@ -1745,6 +1745,11 @@ equal to the *value*. For example, ``!listsplat(42, 3)`` results in ``[42, 42, 42]``. +``!logtwo(``\ *a*\ ``)`` + This operator produces the base 2 log of *a* and produces the integer + result. The log of 0 or a negative number produces an error. This + is a flooring operation. + ``!lt(``\ *a*\ `,` *b*\ ``)`` This operator produces 1 if *a* is less than *b*; 0 otherwise. The arguments must be ``bit``, ``bits``, ``int``, or ``string`` values. 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 @@ -784,7 +784,7 @@ /// class UnOpInit : public OpInit, public FoldingSetNode { public: - enum UnaryOp : uint8_t { CAST, NOT, HEAD, TAIL, SIZE, EMPTY, GETDAGOP }; + enum UnaryOp : uint8_t { 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 @@ -24,6 +24,7 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" @@ -885,6 +886,23 @@ } } break; + + case LOG2: + if (IntInit *LHSi = dyn_cast_or_null( + LHS->convertInitializerTo(IntRecTy::get(RK)))) { + int64_t LHSv = LHSi->getValue(); + if (LHSv <= 0) { + PrintFatalError(CurRec->getLoc(), + "Illegal operation: logtwo is undefined " + "on arguments less than or equal to 0"); + } else { + uint64_t Log = Log2_64(LHSv); + assert(Log <= INT64_MAX && + "Log of an int64_t must be smaller than INT64_MAX"); + return IntInit::get(RK, static_cast(Log)); + } + } + break; } return const_cast(this); } @@ -908,6 +926,7 @@ case SIZE: Result = "!size"; break; case EMPTY: Result = "!empty"; break; case GETDAGOP: Result = "!getdagop"; break; + case LOG2 : Result = "!logtwo"; 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 @@ -52,9 +52,9 @@ String, Then, TrueKW, // Bang operators. - XConcat, XADD, XSUB, XMUL, XDIV, XNOT, XAND, XOR, XXOR, XSRA, XSRL, XSHL, - XListConcat, XListSplat, XStrConcat, XInterleave, XSubstr, XFind, XCast, - XSubst, XForEach, XFilter, XFoldl, XHead, XTail, XSize, XEmpty, XIf, + 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, 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 @@ -569,6 +569,7 @@ .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) 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 @@ -945,6 +945,7 @@ TokError("unknown bang operator"); return nullptr; case tgtok::XNOT: + case tgtok::XLOG2: case tgtok::XHead: case tgtok::XTail: case tgtok::XSize: @@ -973,6 +974,11 @@ Code = UnOpInit::NOT; Type = IntRecTy::get(Records); break; + case tgtok::XLOG2: + Lex.Lex(); // eat the operation + Code = UnOpInit::LOG2; + Type = IntRecTy::get(Records); + break; case tgtok::XHead: Lex.Lex(); // eat the operation Code = UnOpInit::HEAD; @@ -2433,6 +2439,7 @@ case tgtok::XMUL: case tgtok::XDIV: case tgtok::XNOT: + case tgtok::XLOG2: case tgtok::XAND: case tgtok::XOR: case tgtok::XXOR: diff --git a/llvm/test/TableGen/math.td b/llvm/test/TableGen/math.td --- a/llvm/test/TableGen/math.td +++ b/llvm/test/TableGen/math.td @@ -1,6 +1,8 @@ // RUN: llvm-tblgen %s | FileCheck %s // RUN: not llvm-tblgen -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s // RUN: not llvm-tblgen -DERROR2 %s 2>&1 | FileCheck --check-prefix=ERROR2 %s +// RUN: not llvm-tblgen -DERROR3 %s 2>&1 | FileCheck --check-prefix=ERROR3 %s +// RUN: not llvm-tblgen -DERROR4 %s 2>&1 | FileCheck --check-prefix=ERROR4 %s // XFAIL: vg_leak // CHECK: def shifts @@ -116,6 +118,28 @@ // CHECK: Value = 925 def v925 : Int; +// CHECK: def v950 +// CHECK: Value = 4 +def v950: Int; + +// CHECK: def v951 +// CHECK: Value = 10 +def v951 : Int; + +// CHECK: def v952 +// CHECK: Value = 10 +def v952 : Int; + +#ifdef ERROR3 +// ERROR3: error: Illegal operation: logtwo is undefined on arguments less than or equal to 0 +def v953 : Int; +#endif + +#ifdef ERROR4 +// ERROR4: error: Illegal operation: logtwo is undefined on arguments less than or equal to 0 +def v954 : Int; +#endif + // CHECK: def vneg // CHECK: Value = -2 -def vneg : Int; \ No newline at end of file +def vneg : Int;