Index: llvm/trunk/docs/TableGen/LangIntro.rst =================================================================== --- llvm/trunk/docs/TableGen/LangIntro.rst +++ llvm/trunk/docs/TableGen/LangIntro.rst @@ -267,6 +267,13 @@ on string, int and bit objects. Use !cast to compare other types of objects. +``!ne(a,b)`` + The negation of ``!eq(a,b)``. + +``!le(a,b), !lt(a,b), !ge(a,b), !gt(a,b)`` + (Signed) comparison of integer values that returns bit 1 or 0 depending on + the result of the comparison. + ``!shl(a,b)`` ``!srl(a,b)`` ``!sra(a,b)`` The usual shift operators. Operations are on 64-bit integers, the result is undefined for shift counts outside [0, 63]. Index: llvm/trunk/docs/TableGen/LangRef.rst =================================================================== --- llvm/trunk/docs/TableGen/LangRef.rst +++ llvm/trunk/docs/TableGen/LangRef.rst @@ -99,7 +99,8 @@ :!add !shl !sra !srl !and :!or !empty !subst !foreach !strconcat :!cast !listconcat !size !foldl - :!isa !dag + :!isa !dag !le !lt !ge + :!gt !ne Syntax Index: llvm/trunk/include/llvm/TableGen/Record.h =================================================================== --- llvm/trunk/include/llvm/TableGen/Record.h +++ llvm/trunk/include/llvm/TableGen/Record.h @@ -803,7 +803,7 @@ class BinOpInit : public OpInit, public FoldingSetNode { public: enum BinaryOp : uint8_t { ADD, AND, OR, SHL, SRA, SRL, LISTCONCAT, - STRCONCAT, CONCAT, EQ }; + STRCONCAT, CONCAT, EQ, NE, LE, LT, GE, GT }; private: Init *LHS, *RHS; Index: llvm/trunk/lib/TableGen/Record.cpp =================================================================== --- llvm/trunk/lib/TableGen/Record.cpp +++ llvm/trunk/lib/TableGen/Record.cpp @@ -898,23 +898,43 @@ return ConcatStringInits(LHSs, RHSs); break; } - case EQ: { + case EQ: + case NE: + case LE: + case LT: + case GE: + case GT: { // try to fold eq comparison for 'bit' and 'int', otherwise fallback // to string objects. IntInit *L = - dyn_cast_or_null(LHS->convertInitializerTo(IntRecTy::get())); + dyn_cast_or_null(LHS->convertInitializerTo(IntRecTy::get())); IntInit *R = - dyn_cast_or_null(RHS->convertInitializerTo(IntRecTy::get())); + dyn_cast_or_null(RHS->convertInitializerTo(IntRecTy::get())); - if (L && R) - return IntInit::get(L->getValue() == R->getValue()); + if (L && R) { + bool Result; + switch (getOpcode()) { + case EQ: Result = L->getValue() == R->getValue(); break; + case NE: Result = L->getValue() != R->getValue(); break; + case LE: Result = L->getValue() <= R->getValue(); break; + case LT: Result = L->getValue() < R->getValue(); break; + case GE: Result = L->getValue() >= R->getValue(); break; + case GT: Result = L->getValue() > R->getValue(); break; + default: llvm_unreachable("unhandled comparison"); + } + return BitInit::get(Result); + } - StringInit *LHSs = dyn_cast(LHS); - StringInit *RHSs = dyn_cast(RHS); + if (getOpcode() == EQ || getOpcode() == NE) { + StringInit *LHSs = dyn_cast(LHS); + StringInit *RHSs = dyn_cast(RHS); - // Make sure we've resolved - if (LHSs && RHSs) - return IntInit::get(LHSs->getValue() == RHSs->getValue()); + // Make sure we've resolved + if (LHSs && RHSs) { + bool Equal = LHSs->getValue() == RHSs->getValue(); + return BitInit::get(getOpcode() == EQ ? Equal : !Equal); + } + } break; } @@ -969,6 +989,11 @@ case SRA: Result = "!sra"; break; case SRL: Result = "!srl"; break; case EQ: Result = "!eq"; break; + case NE: Result = "!ne"; break; + case LE: Result = "!le"; break; + case LT: Result = "!lt"; break; + case GE: Result = "!ge"; break; + case GT: Result = "!gt"; break; case LISTCONCAT: Result = "!listconcat"; break; case STRCONCAT: Result = "!strconcat"; break; } Index: llvm/trunk/lib/TableGen/TGLexer.h =================================================================== --- llvm/trunk/lib/TableGen/TGLexer.h +++ llvm/trunk/lib/TableGen/TGLexer.h @@ -49,6 +49,7 @@ // !keywords. XConcat, XADD, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XStrConcat, XCast, XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty, XIf, XEq, XIsA, XDag, + XNe, XLe, XLt, XGe, XGt, // Integer value. IntVal, Index: llvm/trunk/lib/TableGen/TGLexer.cpp =================================================================== --- llvm/trunk/lib/TableGen/TGLexer.cpp +++ llvm/trunk/lib/TableGen/TGLexer.cpp @@ -467,6 +467,11 @@ 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("isa", tgtok::XIsA) .Case("head", tgtok::XHead) Index: llvm/trunk/lib/TableGen/TGParser.cpp =================================================================== --- llvm/trunk/lib/TableGen/TGParser.cpp +++ llvm/trunk/lib/TableGen/TGParser.cpp @@ -974,6 +974,11 @@ case tgtok::XSRL: case tgtok::XSHL: case tgtok::XEq: + case tgtok::XNe: + case tgtok::XLe: + case tgtok::XLt: + case tgtok::XGe: + case tgtok::XGt: case tgtok::XListConcat: case tgtok::XStrConcat: { // Value ::= !binop '(' Value ',' Value ')' tgtok::TokKind OpTok = Lex.getCode(); @@ -991,6 +996,11 @@ case tgtok::XSRL: Code = BinOpInit::SRL; break; case tgtok::XSHL: Code = BinOpInit::SHL; break; case tgtok::XEq: Code = BinOpInit::EQ; break; + case tgtok::XNe: Code = BinOpInit::NE; break; + case tgtok::XLe: Code = BinOpInit::LE; break; + case tgtok::XLt: Code = BinOpInit::LT; break; + case tgtok::XGe: Code = BinOpInit::GE; break; + case tgtok::XGt: Code = BinOpInit::GT; break; case tgtok::XListConcat: Code = BinOpInit::LISTCONCAT; break; case tgtok::XStrConcat: Code = BinOpInit::STRCONCAT; break; } @@ -1014,8 +1024,16 @@ ArgType = IntRecTy::get(); break; case tgtok::XEq: + case tgtok::XNe: Type = BitRecTy::get(); - // ArgType for Eq is not known at this point + // ArgType for Eq / Ne is not known at this point + break; + case tgtok::XLe: + case tgtok::XLt: + case tgtok::XGe: + case tgtok::XGt: + Type = BitRecTy::get(); + ArgType = IntRecTy::get(); break; case tgtok::XListConcat: // We don't know the list type until we parse the first argument @@ -1061,6 +1079,7 @@ } break; case BinOpInit::EQ: + case BinOpInit::NE: if (!ArgType->typeIsConvertibleTo(IntRecTy::get()) && !ArgType->typeIsConvertibleTo(StringRecTy::get())) { Error(InitLoc, Twine("expected int, bits, or string; got value of " @@ -1834,6 +1853,11 @@ case tgtok::XSRL: case tgtok::XSHL: case tgtok::XEq: + case tgtok::XNe: + case tgtok::XLe: + case tgtok::XLt: + case tgtok::XGe: + case tgtok::XGt: case tgtok::XListConcat: case tgtok::XStrConcat: // Value ::= !binop '(' Value ',' Value ')' case tgtok::XIf: Index: llvm/trunk/test/TableGen/compare.td =================================================================== --- llvm/trunk/test/TableGen/compare.td +++ llvm/trunk/test/TableGen/compare.td @@ -0,0 +1,54 @@ +// RUN: llvm-tblgen %s | FileCheck %s +// XFAIL: vg_leak + +// CHECK: --- Defs --- + +// CHECK: def A0 { +// CHECK: bit eq = 1; +// CHECK: bit ne = 0; +// CHECK: bit le = 1; +// CHECK: bit lt = 0; +// CHECK: bit ge = 1; +// CHECK: bit gt = 0; +// CHECK: } + +// CHECK: def A1 { +// CHECK: bit eq = 0; +// CHECK: bit ne = 1; +// CHECK: bit le = 1; +// CHECK: bit lt = 1; +// CHECK: bit ge = 0; +// CHECK: bit gt = 0; +// CHECK: } + +// CHECK: def A2 { +// CHECK: bit eq = 0; +// CHECK: bit ne = 1; +// CHECK: bit le = 0; +// CHECK: bit lt = 0; +// CHECK: bit ge = 1; +// CHECK: bit gt = 1; +// CHECK: } + +// CHECK: def A3 { +// CHECK: bit eq = 0; +// CHECK: bit ne = 1; +// CHECK: bit le = 0; +// CHECK: bit lt = 0; +// CHECK: bit ge = 1; +// CHECK: bit gt = 1; +// CHECK: } + +class A { + bit eq = !eq(x, y); + bit ne = !ne(x, y); + bit le = !le(x, y); + bit lt = !lt(x, y); + bit ge = !ge(x, y); + bit gt = !gt(x, y); +} + +def A0 : A<-3, -3>; +def A1 : A<-1, 4>; +def A2 : A<3, -2>; +def A3 : A<4, 2>; Index: llvm/trunk/test/TableGen/eq.td =================================================================== --- llvm/trunk/test/TableGen/eq.td +++ llvm/trunk/test/TableGen/eq.td @@ -1,7 +1,18 @@ // RUN: llvm-tblgen %s | FileCheck %s // XFAIL: vg_leak -// CHECK: Value = 0 -// CHECK: Value = 1 + +// CHECK-LABEL: def FALSE { +// CHECK: int Value = 0; +// CHECK: } + +// CHECK-LABEL: def TRUE { +// CHECK: int Value = 1; +// CHECK: } + +// CHECK-LABEL: def X_NE { +// CHECK: bit a = 1; +// CHECK: bit b = 0; +// CHECK: } class Base { int Value = V; @@ -12,3 +23,8 @@ def TRUE : Derived<"true">; def FALSE : Derived<"false">; + +def X_NE { + bit a = !ne("true", "false"); + bit b = !ne("foo", "foo"); +} Index: llvm/trunk/test/TableGen/eqbit.td =================================================================== --- llvm/trunk/test/TableGen/eqbit.td +++ llvm/trunk/test/TableGen/eqbit.td @@ -1,10 +1,19 @@ // RUN: llvm-tblgen %s | FileCheck %s // XFAIL: vg_leak -// CHECK: a = 6 -// CHECK: a = 5 + +// CHECK-LABEL: def X { +// CHECK: int a = 6; +// CHECK: int c = 5; +// CHECK: } + +// CHECK-LABEL: def Y { +// CHECK: int a = 5; +// CHECK: int c = 6; +// CHECK: } class A { int a = !if(!eq(b, 1), 5, 6); + int c = !if(!ne(b, 1), 5, 6); } def X : A<0>;