aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBill Wendling <isanbard@gmail.com>2010-12-13 01:46:19 +0000
committerBill Wendling <isanbard@gmail.com>2010-12-13 01:46:19 +0000
commit548f5a0b751aafba88473e4863c2baf7741b56a5 (patch)
treea27b4776c6bc3c5ee1d938632121d9d6e2664e61
parentdcb54ce3da15ba41adeee020288e6c62cfae8c42 (diff)
downloadexternal_llvm-548f5a0b751aafba88473e4863c2baf7741b56a5.zip
external_llvm-548f5a0b751aafba88473e4863c2baf7741b56a5.tar.gz
external_llvm-548f5a0b751aafba88473e4863c2baf7741b56a5.tar.bz2
Add support for using the `!if' operator when initializing variables:
class A<bit a, bits<3> x, bits<3> y> { bits<3> z; let z = !if(a, x, y); } The variable z will get the value of x when 'a' is 1 and 'y' when a is '0'. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@121666 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--test/TableGen/if.td30
-rw-r--r--utils/TableGen/Record.cpp72
-rw-r--r--utils/TableGen/Record.h2
-rw-r--r--utils/TableGen/TGParser.cpp44
4 files changed, 127 insertions, 21 deletions
diff --git a/test/TableGen/if.td b/test/TableGen/if.td
index 0bac0ba..bff9278 100644
--- a/test/TableGen/if.td
+++ b/test/TableGen/if.td
@@ -1,14 +1,38 @@
-// RUN: tblgen %s | grep {\\\[1, 2, 3\\\]} | count 4
-// RUN: tblgen %s | grep {\\\[4, 5, 6\\\]} | count 2
+// RUN: tblgen %s | FileCheck %s
// XFAIL: vg_leak
+// Support for an `!if' operator as part of a `let' statement.
+// CHECK: class C
+// CHECK-NEXT: bits<16> n = { ?, ?, ?, ?, ?, ?, ?, !if({ C:x{2} }, 0, 1), !if({ C:x{2} }, 1, 1), !if({ C:x{2} }, 0, 0), !if({ C:x{1} }, C:y{3}, 0), !if({ C:x{1} }, C:y{2}, 1), !if({ C:x{0} }, C:y{3}, C:z), !if({ C:x{0} }, C:y{2}, C:y{2}), !if({ C:x{0} }, C:y{1}, C:y{1}), !if({ C:x{0} }, C:y{0}, C:y{0}) };
+class C<bits<3> x, bits<4> y, bit z> {
+ bits<16> n;
+
+ let n{8-6} = !if(x{2}, 0b010, 0b110);
+ let n{5-4} = !if(x{1}, y{3-2}, {0, 1});
+ let n{3-0} = !if(x{0}, y{3-0}, {z, y{2}, y{1}, y{0}});
+}
+
+// CHECK: def One
+// CHECK-NEXT: list<int> first = [1, 2, 3];
+// CHECK-NEXT: list<int> rest = [1, 2, 3];
+
+// CHECK: def OneB
+// CHECK-NEXT: list<int> vals = [1, 2, 3];
+
+// CHECK: def Two
+// CHECK-NEXT: list<int> first = [1, 2, 3];
+// CHECK-NEXT: list<int> rest = [4, 5, 6];
+
+// CHECK: def TwoB
+// CHECK-NEXT: list<int> vals = [4, 5, 6];
+
class A<list<list<int>> vals> {
list<int> first = vals[0];
list<int> rest = !if(!null(!cdr(vals)), vals[0], vals[1]);
}
def One : A<[[1,2,3]]>;
-def Two : A<[[1,2,3],[4,5,6]]>;
+def Two : A<[[1,2,3], [4,5,6]]>;
class B<list<int> v> {
list<int> vals = v;
diff --git a/utils/TableGen/Record.cpp b/utils/TableGen/Record.cpp
index a34618c..00bb2a7 100644
--- a/utils/TableGen/Record.cpp
+++ b/utils/TableGen/Record.cpp
@@ -65,19 +65,27 @@ Init *BitsRecTy::convertValue(BitInit *UI) {
return Ret;
}
-// convertValue from Int initializer to bits type: Split the integer up into the
-// appropriate bits.
-//
+/// canFitInBitfield - Return true if the number of bits is large enough to hold
+/// the integer value.
+static bool canFitInBitfield(int64_t Value, unsigned NumBits) {
+ if (Value >= 0) {
+ if (Value & ~((1LL << NumBits) - 1))
+ return false;
+ } else if ((Value >> NumBits) != -1 || (Value & (1LL << (NumBits-1))) == 0) {
+ return false;
+ }
+
+ return true;
+}
+
+/// convertValue from Int initializer to bits type: Split the integer up into the
+/// appropriate bits.
+///
Init *BitsRecTy::convertValue(IntInit *II) {
int64_t Value = II->getValue();
// Make sure this bitfield is large enough to hold the integer value.
- if (Value >= 0) {
- if (Value & ~((1LL << Size)-1))
- return 0;
- } else {
- if ((Value >> Size) != -1 || ((Value & (1LL << (Size-1))) == 0))
- return 0;
- }
+ if (!canFitInBitfield(Value, Size))
+ return 0;
BitsInit *Ret = new BitsInit(Size);
for (unsigned i = 0; i != Size; ++i)
@@ -101,12 +109,56 @@ Init *BitsRecTy::convertValue(TypedInit *VI) {
Ret->setBit(i, new VarBitInit(VI, i));
return Ret;
}
+
if (Size == 1 && dynamic_cast<BitRecTy*>(VI->getType())) {
BitsInit *Ret = new BitsInit(1);
Ret->setBit(0, VI);
return Ret;
}
+ if (TernOpInit *Tern = dynamic_cast<TernOpInit*>(VI)) {
+ if (Tern->getOpcode() == TernOpInit::IF) {
+ Init *LHS = Tern->getLHS();
+ Init *MHS = Tern->getMHS();
+ Init *RHS = Tern->getRHS();
+
+ IntInit *MHSi = dynamic_cast<IntInit*>(MHS);
+ IntInit *RHSi = dynamic_cast<IntInit*>(RHS);
+
+ if (MHSi && RHSi) {
+ int64_t MHSVal = MHSi->getValue();
+ int64_t RHSVal = RHSi->getValue();
+
+ if (canFitInBitfield(MHSVal, Size) && canFitInBitfield(RHSVal, Size)) {
+ BitsInit *Ret = new BitsInit(Size);
+
+ for (unsigned i = 0; i != Size; ++i)
+ Ret->setBit(i, new TernOpInit(TernOpInit::IF, LHS,
+ new IntInit((MHSVal & (1LL << i)) ? 1 : 0),
+ new IntInit((RHSVal & (1LL << i)) ? 1 : 0),
+ VI->getType()));
+
+ return Ret;
+ }
+ } else {
+ BitsInit *MHSbs = dynamic_cast<BitsInit*>(MHS);
+ BitsInit *RHSbs = dynamic_cast<BitsInit*>(RHS);
+
+ if (MHSbs && RHSbs) {
+ BitsInit *Ret = new BitsInit(Size);
+
+ for (unsigned i = 0; i != Size; ++i)
+ Ret->setBit(i, new TernOpInit(TernOpInit::IF, LHS,
+ MHSbs->getBit(i),
+ RHSbs->getBit(i),
+ VI->getType()));
+
+ return Ret;
+ }
+ }
+ }
+ }
+
return 0;
}
diff --git a/utils/TableGen/Record.h b/utils/TableGen/Record.h
index 0853037..f8873cf 100644
--- a/utils/TableGen/Record.h
+++ b/utils/TableGen/Record.h
@@ -931,6 +931,8 @@ public:
// possible to fold.
Init *Fold(Record *CurRec, MultiClass *CurMultiClass);
+ virtual bool isComplete() const { return false; }
+
virtual Init *resolveReferences(Record &R, const RecordVal *RV);
virtual std::string getAsString() const;
diff --git a/utils/TableGen/TGParser.cpp b/utils/TableGen/TGParser.cpp
index d99632e..57e9f83 100644
--- a/utils/TableGen/TGParser.cpp
+++ b/utils/TableGen/TGParser.cpp
@@ -868,7 +868,6 @@ Init *TGParser::ParseOperation(Record *CurRec) {
TernOpInit::TernaryOp Code;
RecTy *Type = 0;
-
tgtok::TokKind LexCode = Lex.getCode();
Lex.Lex(); // eat the operation
switch (LexCode) {
@@ -919,16 +918,45 @@ Init *TGParser::ParseOperation(Record *CurRec) {
switch (LexCode) {
default: assert(0 && "Unhandled code!");
case tgtok::XIf: {
- TypedInit *MHSt = dynamic_cast<TypedInit *>(MHS);
- TypedInit *RHSt = dynamic_cast<TypedInit *>(RHS);
- if (MHSt == 0 || RHSt == 0) {
+ // FIXME: The `!if' operator doesn't handle non-TypedInit well at
+ // all. This can be made much more robust.
+ TypedInit *MHSt = dynamic_cast<TypedInit*>(MHS);
+ TypedInit *RHSt = dynamic_cast<TypedInit*>(RHS);
+
+ RecTy *MHSTy = 0;
+ RecTy *RHSTy = 0;
+
+ if (MHSt == 0 && RHSt == 0) {
+ BitsInit *MHSbits = dynamic_cast<BitsInit*>(MHS);
+ BitsInit *RHSbits = dynamic_cast<BitsInit*>(RHS);
+
+ if (MHSbits && RHSbits &&
+ MHSbits->getNumBits() == RHSbits->getNumBits()) {
+ Type = new BitRecTy();
+ break;
+ } else {
+ BitInit *MHSbit = dynamic_cast<BitInit*>(MHS);
+ BitInit *RHSbit = dynamic_cast<BitInit*>(RHS);
+
+ if (MHSbit && RHSbit) {
+ Type = new BitRecTy();
+ break;
+ }
+ }
+ } else if (MHSt != 0 && RHSt != 0) {
+ MHSTy = MHSt->getType();
+ RHSTy = RHSt->getType();
+ }
+
+ if (!MHSTy || !RHSTy) {
TokError("could not get type for !if");
return 0;
}
- if (MHSt->getType()->typeIsConvertibleTo(RHSt->getType())) {
- Type = RHSt->getType();
- } else if (RHSt->getType()->typeIsConvertibleTo(MHSt->getType())) {
- Type = MHSt->getType();
+
+ if (MHSTy->typeIsConvertibleTo(RHSTy)) {
+ Type = RHSTy;
+ } else if (RHSTy->typeIsConvertibleTo(MHSTy)) {
+ Type = MHSTy;
} else {
TokError("inconsistent types for !if");
return 0;