mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-29 14:20:29 +00:00
TableGen: Add !ne, !le, !lt, !ge, and !gt comparisons
Change-Id: I8e2ece677268972d578a787467f7ef52a1f33a71 Differential revision: https://reviews.llvm.org/D44114 llvm-svn: 327496
This commit is contained in:
parent
1faf7228d7
commit
2079f988a9
@ -267,6 +267,13 @@ supported include:
|
||||
on string, int and bit objects. Use !cast<string> 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].
|
||||
|
@ -99,7 +99,8 @@ wide variety of meanings:
|
||||
:!add !shl !sra !srl !and
|
||||
:!or !empty !subst !foreach !strconcat
|
||||
:!cast !listconcat !size !foldl
|
||||
:!isa !dag
|
||||
:!isa !dag !le !lt !ge
|
||||
:!gt !ne
|
||||
|
||||
|
||||
Syntax
|
||||
|
@ -803,7 +803,7 @@ public:
|
||||
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;
|
||||
|
@ -898,23 +898,43 @@ Init *BinOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const {
|
||||
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<IntInit>(LHS->convertInitializerTo(IntRecTy::get()));
|
||||
dyn_cast_or_null<IntInit>(LHS->convertInitializerTo(IntRecTy::get()));
|
||||
IntInit *R =
|
||||
dyn_cast_or_null<IntInit>(RHS->convertInitializerTo(IntRecTy::get()));
|
||||
dyn_cast_or_null<IntInit>(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<StringInit>(LHS);
|
||||
StringInit *RHSs = dyn_cast<StringInit>(RHS);
|
||||
if (getOpcode() == EQ || getOpcode() == NE) {
|
||||
StringInit *LHSs = dyn_cast<StringInit>(LHS);
|
||||
StringInit *RHSs = dyn_cast<StringInit>(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 @@ std::string BinOpInit::getAsString() const {
|
||||
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;
|
||||
}
|
||||
|
@ -467,6 +467,11 @@ tgtok::TokKind TGLexer::LexExclaim() {
|
||||
tgtok::TokKind Kind =
|
||||
StringSwitch<tgtok::TokKind>(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)
|
||||
|
@ -49,6 +49,7 @@ namespace tgtok {
|
||||
// !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,
|
||||
|
@ -974,6 +974,11 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
|
||||
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 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
|
||||
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 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
|
||||
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 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
|
||||
}
|
||||
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 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
|
||||
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:
|
||||
|
54
test/TableGen/compare.td
Normal file
54
test/TableGen/compare.td
Normal file
@ -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<int x, int y> {
|
||||
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>;
|
@ -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 V> {
|
||||
int Value = V;
|
||||
@ -12,3 +23,8 @@ class Derived<string Truth> :
|
||||
|
||||
def TRUE : Derived<"true">;
|
||||
def FALSE : Derived<"false">;
|
||||
|
||||
def X_NE {
|
||||
bit a = !ne("true", "false");
|
||||
bit b = !ne("foo", "foo");
|
||||
}
|
||||
|
@ -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<bit b = 1> {
|
||||
int a = !if(!eq(b, 1), 5, 6);
|
||||
int c = !if(!ne(b, 1), 5, 6);
|
||||
}
|
||||
|
||||
def X : A<0>;
|
||||
|
Loading…
Reference in New Issue
Block a user