// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <math.h>
+
#include "src/types.h"
#include "src/ostreams.h"
namespace v8 {
namespace internal {
+
+// -----------------------------------------------------------------------------
+// Range-related custom order on doubles.
+// We want -0 to be less than +0.
+
+static bool dle(double x, double y) {
+ return x <= y && copysign(1, x) <= copysign(1, y);
+}
+
+
+static bool deq(double x, double y) {
+ return dle(x, y) && dle(y, x);
+}
+
+
// -----------------------------------------------------------------------------
// Glb and lub computation.
type->AsClass()->Bound(NULL)->AsBitset();
} else if (type->IsConstant()) {
return type->AsConstant()->Bound()->AsBitset();
+ } else if (type->IsRange()) {
+ return type->AsRange()->Bound()->AsBitset();
} else if (type->IsContext()) {
return type->AsContext()->Bound()->AsBitset();
} else if (type->IsArray()) {
return Lub(*type->AsClass()->Map());
} else if (type->IsConstant()) {
return Lub(*type->AsConstant()->Value());
+ } else if (type->IsRange()) {
+ return Lub(type->AsRange()->Min(), type->AsRange()->Max());
} else if (type->IsContext()) {
return kInternal & kTaggedPtr;
} else if (type->IsArray()) {
template<class Config>
+int TypeImpl<Config>::BitsetType::Lub(double min, double max) {
+ DisallowHeapAllocation no_allocation;
+ DCHECK(dle(min, max));
+ if (deq(min, max)) return BitsetType::Lub(min); // Singleton range.
+ int bitset = BitsetType::kNumber ^ SEMANTIC(BitsetType::kNaN);
+ if (dle(0, min) || max < 0) bitset ^= SEMANTIC(BitsetType::kMinusZero);
+ return bitset;
+ // TODO(neis): Could refine this further by doing more checks on min/max.
+}
+
+
+template<class Config>
int TypeImpl<Config>::BitsetType::Lub(int32_t value) {
if (value >= 0x40000000) {
return i::SmiValuesAre31Bits() ? kOtherUnsigned31 : kUnsignedSmall;
&& *this->AsConstant()->Value() == *that->AsConstant()->Value()
&& this->AsConstant()->Bound()->Is(that->AsConstant()->Bound());
}
+ if (that->IsRange()) {
+ return this->IsRange()
+ && this->AsRange()->Bound()->Is(that->AsRange()->Bound())
+ && dle(that->AsRange()->Min(), this->AsRange()->Min())
+ && dle(this->AsRange()->Max(), that->AsRange()->Max());
+ }
if (that->IsContext()) {
return this->IsContext()
&& this->AsContext()->Outer()->Equals(that->AsContext()->Outer());
template<class Config>
bool TypeImpl<Config>::Contains(i::Object* value) {
DisallowHeapAllocation no_allocation;
+ if (this->IsRange()) {
+ return value->IsNumber() &&
+ dle(this->AsRange()->Min(), value->Number()) &&
+ dle(value->Number(), this->AsRange()->Max()) &&
+ BitsetType::Is(BitsetType::Lub(value), this->BitsetLub());
+ }
for (Iterator<i::Object> it = this->Constants(); !it.Done(); it.Advance()) {
if (*it.Current() == value) return true;
}
return ClassType::New(this->AsClass()->Map(), bound, region);
} else if (this->IsConstant()) {
return ConstantType::New(this->AsConstant()->Value(), bound, region);
+ } else if (this->IsRange()) {
+ return RangeType::New(
+ this->AsRange()->Min(), this->AsRange()->Max(), bound, region);
} else if (this->IsContext()) {
return ContextType::New(this->AsContext()->Outer(), bound, region);
} else if (this->IsArray()) {
}
}
} else if (!type->IsBitset()) {
- DCHECK(type->IsClass() || type->IsConstant() ||
- type->IsArray() || type->IsFunction() || type->IsContext());
+ DCHECK(type->IsClass() || type->IsConstant() || type->IsRange() ||
+ type->IsContext() || type->IsArray() || type->IsFunction());
int inherent_bound = type->InherentBitsetLub();
int old_bound = type->BitsetLub();
int other_bound = type->BoundBy(other->unhandle()) & inherent_bound;
} else if (type->IsConstant()) {
TypeHandle bound = Convert<OtherType>(type->AsConstant()->Bound(), region);
return ConstantType::New(type->AsConstant()->Value(), bound, region);
+ } else if (type->IsRange()) {
+ TypeHandle bound = Convert<OtherType>(type->AsRange()->Bound(), region);
+ return RangeType::New(
+ type->AsRange()->Min(), type->AsRange()->Max(), bound, region);
} else if (type->IsContext()) {
TypeHandle bound = Convert<OtherType>(type->AsContext()->Bound(), region);
TypeHandle outer = Convert<OtherType>(type->AsContext()->Outer(), region);
return ClassType::New(map, region);
}
static TypeHandle Constant(i::Handle<i::Object> value, Region* region) {
- // TODO(neis): return RangeType for numerical values
+ // TODO(neis): Return RangeType for numerical values.
return ConstantType::New(value, region);
}
static TypeHandle Range(double min, double max, Region* region) {
static int Lub(int32_t value);
static int Lub(uint32_t value);
static int Lub(i::Map* map);
+ static int Lub(double min, double max);
static int InherentLub(TypeImpl* type);
static const char* Name(int bitset);
static RangeHandle New(
double min, double max, TypeHandle bound, Region* region) {
- DCHECK(BitsetType::Is(bound->AsBitset(), BitsetType::kNumber));
- DCHECK(!std::isnan(min) && !std::isnan(max) && min <= max);
+ DCHECK(BitsetType::Is(bound->AsBitset(), BitsetType::Lub(min, max)));
RangeHandle type = Config::template cast<RangeType>(
StructuralType::New(StructuralType::kRangeTag, 3, region));
type->Set(0, bound);
}
static RangeHandle New(double min, double max, Region* region) {
- TypeHandle bound = BitsetType::New(BitsetType::kNumber, region);
+ TypeHandle bound = BitsetType::New(BitsetType::Lub(min, max), region);
return New(min, max, bound, region);
}
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <math.h>
#include <vector>
#include "src/hydrogen-types.h"
NumberFunction2 = Type::Function(Number, Number, Number, region);
MethodFunction = Type::Function(String, Object, 0, region);
- for (int i = 0; i < 40; ++i) {
+ for (int i = 0; i < 30; ++i) {
types.push_back(Fuzz());
}
}
ValueVector values;
DoubleVector doubles; // Some floating-point values, excluding NaN.
+ // Range type helper functions, partially copied from types.cc.
+ // Note: dle(dmin(x,y), dmax(x,y)) holds iff neither x nor y is NaN.
+ bool dle(double x, double y) {
+ return x <= y && copysign(1, x) <= copysign(1, y);
+ }
+ bool deq(double x, double y) {
+ return dle(x, y) && dle(y, x);
+ }
+ double dmin(double x, double y) {
+ return dle(x, y) ? x : y;
+ }
+ double dmax(double x, double y) {
+ return dle(x, y) ? y : x;
+ }
+
TypeHandle Of(Handle<i::Object> value) {
return Type::Of(value, region_);
}
// Constructor
for (DoubleIterator i = T.doubles.begin(); i != T.doubles.end(); ++i) {
for (DoubleIterator j = T.doubles.begin(); j != T.doubles.end(); ++j) {
- double min = std::min(*i, *j);
- double max = std::max(*i, *j);
+ double min = T.dmin(*i, *j);
+ double max = T.dmax(*i, *j);
TypeHandle type = T.Range(min, max);
CHECK(type->IsRange());
}
// Range attributes
for (DoubleIterator i = T.doubles.begin(); i != T.doubles.end(); ++i) {
for (DoubleIterator j = T.doubles.begin(); j != T.doubles.end(); ++j) {
- double min = std::min(*i, *j);
- double max = std::max(*i, *j);
+ double min = T.dmin(*i, *j);
+ double max = T.dmax(*i, *j);
printf("RangeType: min, max = %f, %f\n", min, max);
TypeHandle type = T.Range(min, max);
printf("RangeType: Min, Max = %f, %f\n",
// i2 != T.doubles.end(); ++i2) {
// for (DoubleIterator j2 = T.doubles.begin();
// j2 != T.doubles.end(); ++j2) {
-// double min1 = std::min(*i1, *j1);
-// double max1 = std::max(*i1, *j1);
-// double min2 = std::min(*i2, *j2);
-// double max2 = std::max(*i2, *j2);
+// double min1 = T.dmin(*i1, *j1);
+// double max1 = T.dmax(*i1, *j1);
+// double min2 = T.dmin(*i2, *j2);
+// double max2 = T.dmax(*i2, *j2);
// TypeHandle type1 = T.Range(min1, max1);
// TypeHandle type2 = T.Range(min2, max2);
-// CHECK(Equal(type1, type2) == (min1 == min2 && max1 == max2));
+// CHECK(Equal(type1, type2) ==
+// (T.deq(min1, min2) && T.deq(max1, max2)));
// }
// }
// }