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 @@ : !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 + : !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: @@ -1741,6 +1741,10 @@ 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. + ``!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,7 +52,7 @@ String, Then, TrueKW, // Bang operators. - XConcat, XADD, XSUB, XMUL, XNOT, XAND, XOR, XXOR, XSRA, XSRL, XSHL, + XConcat, XADD, XSUB, XMUL, 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, 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 @@ -564,6 +564,7 @@ .Case("sub", tgtok::XSUB) .Case("mul", tgtok::XMUL) .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 @@ -932,6 +932,7 @@ TokError("unknown bang operator"); return nullptr; case tgtok::XNOT: + case tgtok::XLOG2: case tgtok::XHead: case tgtok::XTail: case tgtok::XSize: @@ -960,6 +961,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; @@ -2412,6 +2418,7 @@ case tgtok::XSUB: case tgtok::XMUL: 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,4 +1,6 @@ // RUN: llvm-tblgen %s | FileCheck %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 @@ -84,6 +86,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;