Commit c0756abf authored by Patrick Thier's avatar Patrick Thier Committed by V8 LUCI CQ

[turbofan] Extend Type system BitsetType to 64 bit.

Extend BitsetType of TF's type system from 32 to 64 bit.
At the moment all 32 bits are used, so we can't add any new types.
This CL only adds support for > 32 types to C++. The bitset is also
mirrored in Torque. In the Torque definition, we just expose an
unstructured uint32 for the higher bits of the bitfield, because Toruqe
can't deal with 64 bit types on 32 bit platforms (yet) and we also can't
have multiple 1-bit bitfields within a single class (yet).

Bug: v8:12392, chromium:1262750
Change-Id: If571491443e86e4e47eb88d3f15eca485344d12d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3281922Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Patrick Thier <pthier@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77962}
parent 8414adc6
...@@ -119,12 +119,12 @@ Type::bitset Type::BitsetLub() const { ...@@ -119,12 +119,12 @@ Type::bitset Type::BitsetLub() const {
if (IsUnion()) { if (IsUnion()) {
// Take the representation from the first element, which is always // Take the representation from the first element, which is always
// a bitset. // a bitset.
int bitset = AsUnion()->Get(0).BitsetLub(); bitset lub = AsUnion()->Get(0).BitsetLub();
for (int i = 0, n = AsUnion()->Length(); i < n; ++i) { for (int i = 0, n = AsUnion()->Length(); i < n; ++i) {
// Other elements only contribute their semantic part. // Other elements only contribute their semantic part.
bitset |= AsUnion()->Get(i).BitsetLub(); lub |= AsUnion()->Get(i).BitsetLub();
} }
return bitset; return lub;
} }
if (IsHeapConstant()) return AsHeapConstant()->Lub(); if (IsHeapConstant()) return AsHeapConstant()->Lub();
if (IsOtherNumberConstant()) { if (IsOtherNumberConstant()) {
...@@ -415,7 +415,7 @@ Type::bitset BitsetType::ExpandInternals(Type::bitset bits) { ...@@ -415,7 +415,7 @@ Type::bitset BitsetType::ExpandInternals(Type::bitset bits) {
Type::bitset BitsetType::Lub(double min, double max) { Type::bitset BitsetType::Lub(double min, double max) {
DisallowGarbageCollection no_gc; DisallowGarbageCollection no_gc;
int lub = kNone; bitset lub = kNone;
const Boundary* mins = Boundaries(); const Boundary* mins = Boundaries();
for (size_t i = 1; i < BoundariesSize(); ++i) { for (size_t i = 1; i < BoundariesSize(); ++i) {
...@@ -431,7 +431,7 @@ Type::bitset BitsetType::NumberBits(bitset bits) { return bits & kPlainNumber; } ...@@ -431,7 +431,7 @@ Type::bitset BitsetType::NumberBits(bitset bits) { return bits & kPlainNumber; }
Type::bitset BitsetType::Glb(double min, double max) { Type::bitset BitsetType::Glb(double min, double max) {
DisallowGarbageCollection no_gc; DisallowGarbageCollection no_gc;
int glb = kNone; bitset glb = kNone;
const Boundary* mins = Boundaries(); const Boundary* mins = Boundaries();
// If the range does not touch 0, the bound is empty. // If the range does not touch 0, the bound is empty.
...@@ -1146,7 +1146,10 @@ std::ostream& operator<<(std::ostream& os, Type type) { ...@@ -1146,7 +1146,10 @@ std::ostream& operator<<(std::ostream& os, Type type) {
Handle<TurbofanType> Type::AllocateOnHeap(Factory* factory) { Handle<TurbofanType> Type::AllocateOnHeap(Factory* factory) {
DCHECK(CanBeAsserted()); DCHECK(CanBeAsserted());
if (IsBitset()) { if (IsBitset()) {
return factory->NewTurbofanBitsetType(AsBitset(), AllocationType::kYoung); const bitset bits = AsBitset();
uint32_t low = bits & 0xffffffff;
uint32_t high = (bits >> 32) & 0xffffffff;
return factory->NewTurbofanBitsetType(low, high, AllocationType::kYoung);
} else if (IsUnion()) { } else if (IsUnion()) {
const UnionType* union_type = AsUnion(); const UnionType* union_type = AsUnion();
Handle<TurbofanType> result = union_type->Get(0).AllocateOnHeap(factory); Handle<TurbofanType> result = union_type->Get(0).AllocateOnHeap(factory);
...@@ -1171,12 +1174,18 @@ Handle<TurbofanType> Type::AllocateOnHeap(Factory* factory) { ...@@ -1171,12 +1174,18 @@ Handle<TurbofanType> Type::AllocateOnHeap(Factory* factory) {
} }
} }
#define VERIFY_TORQUE_BITSET_AGREEMENT(Name, _) \ #define VERIFY_TORQUE_LOW_BITSET_AGREEMENT(Name, _) \
STATIC_ASSERT(static_cast<uint32_t>(BitsetType::k##Name) == \ STATIC_ASSERT(static_cast<uint32_t>(BitsetType::k##Name) == \
static_cast<uint32_t>(TurbofanTypeBits::k##Name)); static_cast<uint32_t>(TurbofanTypeLowBits::k##Name));
INTERNAL_BITSET_TYPE_LIST(VERIFY_TORQUE_BITSET_AGREEMENT) #define VERIFY_TORQUE_HIGH_BITSET_AGREEMENT(Name, _) \
PROPER_ATOMIC_BITSET_TYPE_LIST(VERIFY_TORQUE_BITSET_AGREEMENT) STATIC_ASSERT(static_cast<uint32_t>( \
#undef VERIFY_TORQUE_BITSET_AGREEMENT static_cast<uint64_t>(BitsetType::k##Name) >> 32) == \
static_cast<uint32_t>(TurbofanTypeHighBits::k##Name));
INTERNAL_BITSET_TYPE_LIST(VERIFY_TORQUE_LOW_BITSET_AGREEMENT)
PROPER_ATOMIC_BITSET_TYPE_LOW_LIST(VERIFY_TORQUE_LOW_BITSET_AGREEMENT)
PROPER_ATOMIC_BITSET_TYPE_HIGH_LIST(VERIFY_TORQUE_HIGH_BITSET_AGREEMENT)
#undef VERIFY_TORQUE_HIGH_BITSET_AGREEMENT
#undef VERIFY_TORQUE_LOW_BITSET_AGREEMENT
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
......
...@@ -96,45 +96,50 @@ namespace compiler { ...@@ -96,45 +96,50 @@ namespace compiler {
// clang-format off // clang-format off
#define INTERNAL_BITSET_TYPE_LIST(V) \ #define INTERNAL_BITSET_TYPE_LIST(V) \
V(OtherUnsigned31, 1u << 1) \ V(OtherUnsigned31, uint64_t{1} << 1) \
V(OtherUnsigned32, 1u << 2) \ V(OtherUnsigned32, uint64_t{1} << 2) \
V(OtherSigned32, 1u << 3) \ V(OtherSigned32, uint64_t{1} << 3) \
V(OtherNumber, 1u << 4) \ V(OtherNumber, uint64_t{1} << 4) \
V(OtherString, 1u << 5) \ V(OtherString, uint64_t{1} << 5) \
#define PROPER_ATOMIC_BITSET_TYPE_LIST(V) \ #define PROPER_ATOMIC_BITSET_TYPE_LOW_LIST(V) \
V(Negative31, 1u << 6) \ V(Negative31, uint64_t{1} << 6) \
V(Null, 1u << 7) \ V(Null, uint64_t{1} << 7) \
V(Undefined, 1u << 8) \ V(Undefined, uint64_t{1} << 8) \
V(Boolean, 1u << 9) \ V(Boolean, uint64_t{1} << 9) \
V(Unsigned30, 1u << 10) \ V(Unsigned30, uint64_t{1} << 10) \
V(MinusZero, 1u << 11) \ V(MinusZero, uint64_t{1} << 11) \
V(NaN, 1u << 12) \ V(NaN, uint64_t{1} << 12) \
V(Symbol, 1u << 13) \ V(Symbol, uint64_t{1} << 13) \
V(InternalizedString, 1u << 14) \ V(InternalizedString, uint64_t{1} << 14) \
V(OtherCallable, 1u << 15) \ V(OtherCallable, uint64_t{1} << 15) \
V(OtherObject, 1u << 16) \ V(OtherObject, uint64_t{1} << 16) \
V(OtherUndetectable, 1u << 17) \ V(OtherUndetectable, uint64_t{1} << 17) \
V(CallableProxy, 1u << 18) \ V(CallableProxy, uint64_t{1} << 18) \
V(OtherProxy, 1u << 19) \ V(OtherProxy, uint64_t{1} << 19) \
V(Function, 1u << 20) \ V(Function, uint64_t{1} << 20) \
V(BoundFunction, 1u << 21) \ V(BoundFunction, uint64_t{1} << 21) \
V(Hole, 1u << 22) \ V(Hole, uint64_t{1} << 22) \
V(OtherInternal, 1u << 23) \ V(OtherInternal, uint64_t{1} << 23) \
V(ExternalPointer, 1u << 24) \ V(ExternalPointer, uint64_t{1} << 24) \
V(Array, 1u << 25) \ V(Array, uint64_t{1} << 25) \
V(UnsignedBigInt63, 1u << 26) \ V(UnsignedBigInt63, uint64_t{1} << 26) \
V(OtherUnsignedBigInt64, 1u << 27) \ V(OtherUnsignedBigInt64, uint64_t{1} << 27) \
V(NegativeBigInt63, 1u << 28) \ V(NegativeBigInt63, uint64_t{1} << 28) \
V(OtherBigInt, 1u << 29) \ V(OtherBigInt, uint64_t{1} << 29) \
/* TODO(v8:10391): Remove this type once all ExternalPointer usages are */ \ /* TODO(v8:10391): Remove this type once all ExternalPointer usages are */ \
/* sandbox-ready. */ \ /* sandbox-ready. */ \
V(SandboxedExternalPointer, 1u << 30) \ V(SandboxedExternalPointer, uint64_t{1} << 30) \
V(CagedPointer, 1u << 31) \ V(CagedPointer, uint64_t{1} << 31)
// For future use.
// Types defined in the high 32 bit are currently only supported in C++.
#define PROPER_ATOMIC_BITSET_TYPE_HIGH_LIST(V)
#define PROPER_BITSET_TYPE_LIST(V) \ #define PROPER_BITSET_TYPE_LIST(V) \
V(None, 0u) \ V(None, uint64_t{0}) \
PROPER_ATOMIC_BITSET_TYPE_LIST(V) \ PROPER_ATOMIC_BITSET_TYPE_LOW_LIST(V) \
PROPER_ATOMIC_BITSET_TYPE_HIGH_LIST(V) \
V(Signed31, kUnsigned30 | kNegative31) \ V(Signed31, kUnsigned30 | kNegative31) \
V(Signed32, kSigned31 | kOtherUnsigned31 | \ V(Signed32, kSigned31 | kOtherUnsigned31 | \
kOtherSigned32) \ kOtherSigned32) \
...@@ -207,7 +212,7 @@ namespace compiler { ...@@ -207,7 +212,7 @@ namespace compiler {
V(NonInternal, kPrimitive | kReceiver) \ V(NonInternal, kPrimitive | kReceiver) \
V(NonBigInt, kNonBigIntPrimitive | kReceiver) \ V(NonBigInt, kNonBigIntPrimitive | kReceiver) \
V(NonNumber, kBigInt | kUnique | kString | kInternal) \ V(NonNumber, kBigInt | kUnique | kString | kInternal) \
V(Any, 0xfffffffeu) V(Any, uint64_t{0xfffffffffffffffe})
// clang-format on // clang-format on
...@@ -243,9 +248,9 @@ class UnionType; ...@@ -243,9 +248,9 @@ class UnionType;
class V8_EXPORT_PRIVATE BitsetType { class V8_EXPORT_PRIVATE BitsetType {
public: public:
using bitset = uint32_t; // Internal using bitset = uint64_t; // Internal
enum : uint32_t { enum : bitset {
#define DECLARE_TYPE(type, value) k##type = (value), #define DECLARE_TYPE(type, value) k##type = (value),
BITSET_TYPE_LIST(DECLARE_TYPE) BITSET_TYPE_LIST(DECLARE_TYPE)
#undef DECLARE_TYPE #undef DECLARE_TYPE
...@@ -376,7 +381,7 @@ class V8_EXPORT_PRIVATE Type { ...@@ -376,7 +381,7 @@ class V8_EXPORT_PRIVATE Type {
PROPER_BITSET_TYPE_LIST(DEFINE_TYPE_CONSTRUCTOR) PROPER_BITSET_TYPE_LIST(DEFINE_TYPE_CONSTRUCTOR)
#undef DEFINE_TYPE_CONSTRUCTOR #undef DEFINE_TYPE_CONSTRUCTOR
Type() : payload_(0) {} Type() : payload_(uint64_t{0}) {}
static Type SignedSmall() { return NewBitset(BitsetType::SignedSmall()); } static Type SignedSmall() { return NewBitset(BitsetType::SignedSmall()); }
static Type UnsignedSmall() { return NewBitset(BitsetType::UnsignedSmall()); } static Type UnsignedSmall() { return NewBitset(BitsetType::UnsignedSmall()); }
...@@ -396,7 +401,7 @@ class V8_EXPORT_PRIVATE Type { ...@@ -396,7 +401,7 @@ class V8_EXPORT_PRIVATE Type {
// Predicates. // Predicates.
bool IsNone() const { return payload_ == None().payload_; } bool IsNone() const { return payload_ == None().payload_; }
bool IsInvalid() const { return payload_ == 0u; } bool IsInvalid() const { return payload_ == uint64_t{0}; }
bool Is(Type that) const { bool Is(Type that) const {
return payload_ == that.payload_ || this->SlowIs(that); return payload_ == that.payload_ || this->SlowIs(that);
...@@ -405,7 +410,7 @@ class V8_EXPORT_PRIVATE Type { ...@@ -405,7 +410,7 @@ class V8_EXPORT_PRIVATE Type {
bool Equals(Type that) const { return this->Is(that) && that.Is(*this); } bool Equals(Type that) const { return this->Is(that) && that.Is(*this); }
// Inspection. // Inspection.
bool IsBitset() const { return payload_ & 1; } bool IsBitset() const { return payload_ & uint64_t{1}; }
bool IsRange() const { return IsKind(TypeBase::kRange); } bool IsRange() const { return IsKind(TypeBase::kRange); }
bool IsHeapConstant() const { return IsKind(TypeBase::kHeapConstant); } bool IsHeapConstant() const { return IsKind(TypeBase::kHeapConstant); }
bool IsOtherNumberConstant() const { bool IsOtherNumberConstant() const {
...@@ -469,10 +474,10 @@ class V8_EXPORT_PRIVATE Type { ...@@ -469,10 +474,10 @@ class V8_EXPORT_PRIVATE Type {
friend UnionType; friend UnionType;
friend size_t hash_value(Type type); friend size_t hash_value(Type type);
explicit Type(bitset bits) : payload_(bits | 1u) {} explicit Type(bitset bits) : payload_(bits | uint64_t{1}) {}
Type(TypeBase* type_base) // NOLINT(runtime/explicit) Type(TypeBase* type_base) // NOLINT(runtime/explicit)
: payload_(reinterpret_cast<uintptr_t>(type_base)) {} : payload_(reinterpret_cast<uint64_t>(type_base)) {}
// Internal inspection. // Internal inspection.
bool IsKind(TypeBase::Kind kind) const { bool IsKind(TypeBase::Kind kind) const {
...@@ -491,7 +496,7 @@ class V8_EXPORT_PRIVATE Type { ...@@ -491,7 +496,7 @@ class V8_EXPORT_PRIVATE Type {
bitset AsBitset() const { bitset AsBitset() const {
DCHECK(IsBitset()); DCHECK(IsBitset());
return static_cast<bitset>(payload_) ^ 1u; return static_cast<bitset>(payload_) ^ uint64_t { 1 };
} }
const UnionType* AsUnion() const; const UnionType* AsUnion() const;
...@@ -526,7 +531,7 @@ class V8_EXPORT_PRIVATE Type { ...@@ -526,7 +531,7 @@ class V8_EXPORT_PRIVATE Type {
// If LSB is set, the payload is a bitset; if LSB is clear, the payload is // If LSB is set, the payload is a bitset; if LSB is clear, the payload is
// a pointer to a subtype of the TypeBase class. // a pointer to a subtype of the TypeBase class.
uintptr_t payload_; uint64_t payload_;
}; };
inline size_t hash_value(Type type) { return type.payload_; } inline size_t hash_value(Type type) { return type.payload_; }
......
...@@ -17,9 +17,14 @@ namespace internal { ...@@ -17,9 +17,14 @@ namespace internal {
#include "torque-generated/src/objects/turbofan-types-tq.inc" #include "torque-generated/src/objects/turbofan-types-tq.inc"
class TurbofanTypeBits { class TurbofanTypeLowBits {
public: public:
DEFINE_TORQUE_GENERATED_TURBOFAN_TYPE_BITS() DEFINE_TORQUE_GENERATED_TURBOFAN_TYPE_LOW_BITS()
};
class TurbofanTypeHighBits {
public:
DEFINE_TORQUE_GENERATED_TURBOFAN_TYPE_HIGH_BITS()
}; };
} // namespace internal } // namespace internal
......
...@@ -9,7 +9,10 @@ ...@@ -9,7 +9,10 @@
class TurbofanType extends HeapObject { class TurbofanType extends HeapObject {
} }
bitfield struct TurbofanTypeBits extends uint32 { // TurbofanBitsetType is 64 bit.
// We use two separate 32 bit bitsets in Torque, due to limitted support
// of 64 bit bitsets.
bitfield struct TurbofanTypeLowBits extends uint32 {
_unused_padding_field_1: bool: 1 bit; _unused_padding_field_1: bool: 1 bit;
other_unsigned31: bool: 1 bit; other_unsigned31: bool: 1 bit;
other_unsigned32: bool: 1 bit; other_unsigned32: bool: 1 bit;
...@@ -44,9 +47,14 @@ bitfield struct TurbofanTypeBits extends uint32 { ...@@ -44,9 +47,14 @@ bitfield struct TurbofanTypeBits extends uint32 {
caged_pointer: bool: 1 bit; caged_pointer: bool: 1 bit;
} }
bitfield struct TurbofanTypeHighBits extends uint32 {
_unused_field: bool: 1 bit;
}
@export @export
class TurbofanBitsetType extends TurbofanType { class TurbofanBitsetType extends TurbofanType {
bitset: TurbofanTypeBits; bitset_low: TurbofanTypeLowBits;
bitset_high: TurbofanTypeHighBits;
} }
@export @export
...@@ -75,81 +83,85 @@ macro IsMinusZero(x: float64): bool { ...@@ -75,81 +83,85 @@ macro IsMinusZero(x: float64): bool {
return x == 0 && 1 / x < 0; return x == 0 && 1 / x < 0;
} }
macro TestTurbofanBitsetType(value: Object, bitset: TurbofanTypeBits): bool { macro TestTurbofanBitsetType(
value: Object, bitsetLow: TurbofanTypeLowBits,
_bitsetHigh: TurbofanTypeHighBits): bool {
typeswitch (value) { typeswitch (value) {
case (value: Number): { case (value: Number): {
const valueF = Convert<float64>(value); const valueF = Convert<float64>(value);
if (IsInteger(value)) { if (IsInteger(value)) {
if (IsMinusZero(valueF)) { if (IsMinusZero(valueF)) {
return bitset.minus_zero; return bitsetLow.minus_zero;
} else if (valueF < Convert<float64>(-0x80000000)) { } else if (valueF < Convert<float64>(-0x80000000)) {
return bitset.other_number; return bitsetLow.other_number;
} else if (valueF < -0x40000000) { } else if (valueF < -0x40000000) {
return bitset.other_signed32; return bitsetLow.other_signed32;
} else if (valueF < 0) { } else if (valueF < 0) {
return bitset.negative31; return bitsetLow.negative31;
} else if (valueF < Convert<float64>(0x40000000)) { } else if (valueF < Convert<float64>(0x40000000)) {
return bitset.unsigned30; return bitsetLow.unsigned30;
} else if (valueF < 0x80000000) { } else if (valueF < 0x80000000) {
return bitset.other_unsigned31; return bitsetLow.other_unsigned31;
} else if (valueF <= 0xffffffff) { } else if (valueF <= 0xffffffff) {
return bitset.other_unsigned32; return bitsetLow.other_unsigned32;
} else { } else {
return bitset.other_number; return bitsetLow.other_number;
} }
} else if (Float64IsNaN(valueF)) { } else if (Float64IsNaN(valueF)) {
return bitset.naN; return bitsetLow.naN;
} else { } else {
return bitset.other_number; return bitsetLow.other_number;
} }
} }
case (Null): { case (Null): {
return bitset.null; return bitsetLow.null;
} }
case (Undefined): { case (Undefined): {
return bitset.undefined; return bitsetLow.undefined;
} }
case (Boolean): { case (Boolean): {
return bitset.boolean; return bitsetLow.boolean;
} }
case (Symbol): { case (Symbol): {
return bitset.symbol; return bitsetLow.symbol;
} }
case (s: String): { case (s: String): {
if (s.IsNotInternalized()) { if (s.IsNotInternalized()) {
return bitset.other_string; return bitsetLow.other_string;
} else { } else {
return bitset.internalized_string; return bitsetLow.internalized_string;
} }
} }
case (proxy: JSProxy): { case (proxy: JSProxy): {
return Is<Callable>(proxy) ? bitset.callable_proxy : bitset.other_proxy; return Is<Callable>(proxy) ? bitsetLow.callable_proxy :
bitsetLow.other_proxy;
} }
case (JSFunction): { case (JSFunction): {
return bitset.function; return bitsetLow.function;
} }
case (JSBoundFunction): { case (JSBoundFunction): {
return bitset.bound_function; return bitsetLow.bound_function;
} }
case (TheHole): { case (TheHole): {
return bitset.hole; return bitsetLow.hole;
} }
case (JSArray): { case (JSArray): {
return bitset.array; return bitsetLow.array;
} }
case (BigInt): { case (BigInt): {
// TODO (tebbi): Distinguish different BigInt types. // TODO (tebbi): Distinguish different BigInt types.
return bitset.unsigned_big_int_63 | bitset.other_unsigned_big_int_64 | return bitsetLow.unsigned_big_int_63 |
bitset.negative_big_int_63 | bitset.other_big_int; bitsetLow.other_unsigned_big_int_64 | bitsetLow.negative_big_int_63 |
bitsetLow.other_big_int;
} }
case (Callable): { case (Callable): {
return bitset.other_callable; return bitsetLow.other_callable;
} }
case (object: JSObject): { case (object: JSObject): {
if (object.map.IsUndetectable()) { if (object.map.IsUndetectable()) {
return bitset.other_undetectable; return bitsetLow.other_undetectable;
} else { } else {
return bitset.other_object; return bitsetLow.other_object;
} }
} }
case (Object): { case (Object): {
...@@ -162,7 +174,8 @@ builtin TestTurbofanType(implicit context: Context)( ...@@ -162,7 +174,8 @@ builtin TestTurbofanType(implicit context: Context)(
value: Object, expectedType: TurbofanType): Boolean { value: Object, expectedType: TurbofanType): Boolean {
typeswitch (expectedType) { typeswitch (expectedType) {
case (t: TurbofanBitsetType): { case (t: TurbofanBitsetType): {
return Convert<Boolean>(TestTurbofanBitsetType(value, t.bitset)); return Convert<Boolean>(
TestTurbofanBitsetType(value, t.bitset_low, t.bitset_high));
} }
case (t: TurbofanUnionType): { case (t: TurbofanUnionType): {
return Convert<Boolean>( return Convert<Boolean>(
......
...@@ -26,7 +26,7 @@ static bool IsInteger(double x) { ...@@ -26,7 +26,7 @@ static bool IsInteger(double x) {
return nearbyint(x) == x && !i::IsMinusZero(x); // Allows for infinities. return nearbyint(x) == x && !i::IsMinusZero(x); // Allows for infinities.
} }
using bitset = uint32_t; using bitset = Type::bitset;
struct Tests { struct Tests {
using TypeIterator = Types::TypeVector::iterator; using TypeIterator = Types::TypeVector::iterator;
...@@ -114,7 +114,7 @@ struct Tests { ...@@ -114,7 +114,7 @@ struct Tests {
CHECK(this->IsBitset(T.Any)); CHECK(this->IsBitset(T.Any));
CHECK(bitset(0) == this->AsBitset(T.None)); CHECK(bitset(0) == this->AsBitset(T.None));
CHECK(bitset(0xFFFFFFFEu) == this->AsBitset(T.Any)); CHECK(bitset(0xFFFFFFFFFFFFFFFEu) == this->AsBitset(T.Any));
// Union(T1, T2) is bitset for bitsets T1,T2 // Union(T1, T2) is bitset for bitsets T1,T2
for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment