From 548f5a0b751aafba88473e4863c2baf7741b56a5 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 13 Dec 2010 01:46:19 +0000 Subject: [PATCH] Add support for using the `!if' operator when initializing variables: class A 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 --- test/TableGen/if.td | 30 ++++++++++++++-- utils/TableGen/Record.cpp | 72 +++++++++++++++++++++++++++++++------ utils/TableGen/Record.h | 2 ++ utils/TableGen/TGParser.cpp | 44 ++++++++++++++++++----- 4 files changed, 127 insertions(+), 21 deletions(-) diff --git a/test/TableGen/if.td b/test/TableGen/if.td index 0bac0bac3e9..bff927802bf 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 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 first = [1, 2, 3]; +// CHECK-NEXT: list rest = [1, 2, 3]; + +// CHECK: def OneB +// CHECK-NEXT: list vals = [1, 2, 3]; + +// CHECK: def Two +// CHECK-NEXT: list first = [1, 2, 3]; +// CHECK-NEXT: list rest = [4, 5, 6]; + +// CHECK: def TwoB +// CHECK-NEXT: list vals = [4, 5, 6]; + class A> vals> { list first = vals[0]; list 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 v> { list vals = v; diff --git a/utils/TableGen/Record.cpp b/utils/TableGen/Record.cpp index a34618c9817..00bb2a734ba 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(VI->getType())) { BitsInit *Ret = new BitsInit(1); Ret->setBit(0, VI); return Ret; } + if (TernOpInit *Tern = dynamic_cast(VI)) { + if (Tern->getOpcode() == TernOpInit::IF) { + Init *LHS = Tern->getLHS(); + Init *MHS = Tern->getMHS(); + Init *RHS = Tern->getRHS(); + + IntInit *MHSi = dynamic_cast(MHS); + IntInit *RHSi = dynamic_cast(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(MHS); + BitsInit *RHSbs = dynamic_cast(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 0853037fe3e..f8873cf43cb 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 d99632e9e4e..57e9f833393 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(MHS); - TypedInit *RHSt = dynamic_cast(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(MHS); + TypedInit *RHSt = dynamic_cast(RHS); + + RecTy *MHSTy = 0; + RecTy *RHSTy = 0; + + if (MHSt == 0 && RHSt == 0) { + BitsInit *MHSbits = dynamic_cast(MHS); + BitsInit *RHSbits = dynamic_cast(RHS); + + if (MHSbits && RHSbits && + MHSbits->getNumBits() == RHSbits->getNumBits()) { + Type = new BitRecTy(); + break; + } else { + BitInit *MHSbit = dynamic_cast(MHS); + BitInit *RHSbit = dynamic_cast(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;