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
This commit is contained in:
Bill Wendling 2010-12-13 01:46:19 +00:00
parent dcb54ce3da
commit 548f5a0b75
4 changed files with 127 additions and 21 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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;