summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/interp/interp.cc102
1 files changed, 50 insertions, 52 deletions
diff --git a/src/interp/interp.cc b/src/interp/interp.cc
index 822f003d..f6490695 100644
--- a/src/interp/interp.cc
+++ b/src/interp/interp.cc
@@ -445,7 +445,6 @@ struct FloatTraits<float> {
static const uint32_t kNegZero = 0x80000000U;
static const uint32_t kQuietNan = 0x7fc00000U;
static const uint32_t kQuietNegNan = 0xffc00000U;
- static const uint32_t kQuietNanBit = 0x00400000U;
static const int kSigBits = 23;
static const uint32_t kSigMask = 0x7fffff;
static const uint32_t kSignMask = 0x80000000U;
@@ -463,6 +462,10 @@ struct FloatTraits<float> {
static bool IsArithmeticNan(uint32_t bits) {
return (bits & kQuietNan) == kQuietNan;
}
+
+ static uint32_t CanonicalizeNan(uint32_t bits) {
+ return WABT_UNLIKELY(IsNan(bits)) ? kQuietNan : bits;
+ }
};
bool IsCanonicalNan(uint32_t bits) {
@@ -531,7 +534,6 @@ struct FloatTraits<double> {
static const uint64_t kNegZero = 0x8000000000000000ULL;
static const uint64_t kQuietNan = 0x7ff8000000000000ULL;
static const uint64_t kQuietNegNan = 0xfff8000000000000ULL;
- static const uint64_t kQuietNanBit = 0x0008000000000000ULL;
static const int kSigBits = 52;
static const uint64_t kSigMask = 0xfffffffffffffULL;
static const uint64_t kSignMask = 0x8000000000000000ULL;
@@ -549,6 +551,10 @@ struct FloatTraits<double> {
static bool IsArithmeticNan(uint64_t bits) {
return (bits & kQuietNan) == kQuietNan;
}
+
+ static uint64_t CanonicalizeNan(uint64_t bits) {
+ return WABT_UNLIKELY(IsNan(bits)) ? kQuietNan : bits;
+ }
};
bool IsCanonicalNan(uint64_t bits) {
@@ -698,6 +704,21 @@ template<> uint32_t GetValue<float>(Value v) { return v.f32_bits; }
template<> uint64_t GetValue<double>(Value v) { return v.f64_bits; }
template<> v128 GetValue<v128>(Value v) { return v.v128_bits; }
+template <typename T>
+ValueTypeRep<T> CanonicalizeNan(ValueTypeRep<T> rep) {
+ return rep;
+}
+
+template <>
+ValueTypeRep<float> CanonicalizeNan<float>(ValueTypeRep<float> rep) {
+ return FloatTraits<float>::CanonicalizeNan(rep);
+}
+
+template <>
+ValueTypeRep<double> CanonicalizeNan<double>(ValueTypeRep<double> rep) {
+ return FloatTraits<double>::CanonicalizeNan(rep);
+}
+
#define TRAP(type) return Result::Trap##type
#define TRAP_UNLESS(cond, type) TRAP_IF(!(cond), type)
#define TRAP_IF(cond, type) \
@@ -1005,7 +1026,7 @@ Result Thread::BinopTrap(BinopTrapFunc<R, T> func) {
// {i,f}{32,64}.add
template <typename T>
ValueTypeRep<T> Add(ValueTypeRep<T> lhs_rep, ValueTypeRep<T> rhs_rep) {
- return ToRep(FromRep<T>(lhs_rep) + FromRep<T>(rhs_rep));
+ return CanonicalizeNan<T>(ToRep(FromRep<T>(lhs_rep) + FromRep<T>(rhs_rep)));
}
template <typename T, typename R>
@@ -1063,13 +1084,13 @@ int32_t SimdIsLaneTrue(ValueTypeRep<T> value, int32_t true_cond) {
// {i,f}{32,64}.sub
template <typename T>
ValueTypeRep<T> Sub(ValueTypeRep<T> lhs_rep, ValueTypeRep<T> rhs_rep) {
- return ToRep(FromRep<T>(lhs_rep) - FromRep<T>(rhs_rep));
+ return CanonicalizeNan<T>(ToRep(FromRep<T>(lhs_rep) - FromRep<T>(rhs_rep)));
}
// {i,f}{32,64}.mul
template <typename T>
ValueTypeRep<T> Mul(ValueTypeRep<T> lhs_rep, ValueTypeRep<T> rhs_rep) {
- return ToRep(FromRep<T>(lhs_rep) * FromRep<T>(rhs_rep));
+ return CanonicalizeNan<T>(ToRep(FromRep<T>(lhs_rep) * FromRep<T>(rhs_rep)));
}
// i{32,64}.{div,rem}_s are special-cased because they trap when dividing the
@@ -1140,16 +1161,15 @@ ValueTypeRep<T> FloatDiv(ValueTypeRep<T> lhs_rep, ValueTypeRep<T> rhs_rep) {
typedef FloatTraits<T> Traits;
ValueTypeRep<T> result;
if (WABT_UNLIKELY(Traits::IsZero(rhs_rep))) {
- if (Traits::IsNan(lhs_rep)) {
- result = lhs_rep | Traits::kQuietNan;
- } else if (Traits::IsZero(lhs_rep)) {
+ if (Traits::IsNan(lhs_rep) || Traits::IsZero(lhs_rep)) {
result = Traits::kQuietNan;
} else {
auto sign = (lhs_rep & Traits::kSignMask) ^ (rhs_rep & Traits::kSignMask);
result = sign | Traits::kInf;
}
} else {
- result = ToRep(FromRep<T>(lhs_rep) / FromRep<T>(rhs_rep));
+ result =
+ CanonicalizeNan<T>(ToRep(FromRep<T>(lhs_rep) / FromRep<T>(rhs_rep)));
}
return result;
}
@@ -1245,51 +1265,31 @@ ValueTypeRep<T> FloatNeg(ValueTypeRep<T> v_rep) {
// f{32,64}.ceil
template <typename T>
ValueTypeRep<T> FloatCeil(ValueTypeRep<T> v_rep) {
- auto result = ToRep(std::ceil(FromRep<T>(v_rep)));
- if (WABT_UNLIKELY(FloatTraits<T>::IsNan(result))) {
- result |= FloatTraits<T>::kQuietNanBit;
- }
- return result;
+ return CanonicalizeNan<T>(ToRep(std::ceil(FromRep<T>(v_rep))));
}
// f{32,64}.floor
template <typename T>
ValueTypeRep<T> FloatFloor(ValueTypeRep<T> v_rep) {
- auto result = ToRep(std::floor(FromRep<T>(v_rep)));
- if (WABT_UNLIKELY(FloatTraits<T>::IsNan(result))) {
- result |= FloatTraits<T>::kQuietNanBit;
- }
- return result;
+ return CanonicalizeNan<T>(ToRep(std::floor(FromRep<T>(v_rep))));
}
// f{32,64}.trunc
template <typename T>
ValueTypeRep<T> FloatTrunc(ValueTypeRep<T> v_rep) {
- auto result = ToRep(std::trunc(FromRep<T>(v_rep)));
- if (WABT_UNLIKELY(FloatTraits<T>::IsNan(result))) {
- result |= FloatTraits<T>::kQuietNanBit;
- }
- return result;
+ return CanonicalizeNan<T>(ToRep(std::trunc(FromRep<T>(v_rep))));
}
// f{32,64}.nearest
template <typename T>
ValueTypeRep<T> FloatNearest(ValueTypeRep<T> v_rep) {
- auto result = ToRep(std::nearbyint(FromRep<T>(v_rep)));
- if (WABT_UNLIKELY(FloatTraits<T>::IsNan(result))) {
- result |= FloatTraits<T>::kQuietNanBit;
- }
- return result;
+ return CanonicalizeNan<T>(ToRep(std::nearbyint(FromRep<T>(v_rep))));
}
// f{32,64}.sqrt
template <typename T>
ValueTypeRep<T> FloatSqrt(ValueTypeRep<T> v_rep) {
- auto result = ToRep(std::sqrt(FromRep<T>(v_rep)));
- if (WABT_UNLIKELY(FloatTraits<T>::IsNan(result))) {
- result |= FloatTraits<T>::kQuietNanBit;
- }
- return result;
+ return CanonicalizeNan<T>(ToRep(std::sqrt(FromRep<T>(v_rep))));
}
// f{32,64}.min
@@ -1297,10 +1297,8 @@ template <typename T>
ValueTypeRep<T> FloatMin(ValueTypeRep<T> lhs_rep, ValueTypeRep<T> rhs_rep) {
typedef FloatTraits<T> Traits;
- if (WABT_UNLIKELY(Traits::IsNan(lhs_rep))) {
- return lhs_rep | Traits::kQuietNanBit;
- } else if (WABT_UNLIKELY(Traits::IsNan(rhs_rep))) {
- return rhs_rep | Traits::kQuietNanBit;
+ if (WABT_UNLIKELY(Traits::IsNan(lhs_rep) || Traits::IsNan(rhs_rep))) {
+ return Traits::kQuietNan;
} else if (WABT_UNLIKELY(Traits::IsZero(lhs_rep) &&
Traits::IsZero(rhs_rep))) {
// min(0.0, -0.0) == -0.0, but std::min won't produce the correct result.
@@ -1317,10 +1315,8 @@ template <typename T>
ValueTypeRep<T> FloatMax(ValueTypeRep<T> lhs_rep, ValueTypeRep<T> rhs_rep) {
typedef FloatTraits<T> Traits;
- if (WABT_UNLIKELY(Traits::IsNan(lhs_rep))) {
- return lhs_rep | Traits::kQuietNanBit;
- } else if (WABT_UNLIKELY(Traits::IsNan(rhs_rep))) {
- return rhs_rep | Traits::kQuietNanBit;
+ if (WABT_UNLIKELY(Traits::IsNan(lhs_rep) || Traits::IsNan(rhs_rep))) {
+ return Traits::kQuietNan;
} else if (WABT_UNLIKELY(Traits::IsZero(lhs_rep) &&
Traits::IsZero(rhs_rep))) {
// min(0.0, -0.0) == -0.0, but std::min won't produce the correct result.
@@ -2393,7 +2389,6 @@ Result Thread::Run(int num_instructions) {
case Opcode::F32DemoteF64: {
typedef FloatTraits<float> F32Traits;
- typedef FloatTraits<double> F64Traits;
uint64_t value = PopRep<double>();
if (WABT_LIKELY((IsConversionInRange<float, double>(value)))) {
@@ -2402,15 +2397,12 @@ Result Thread::Run(int num_instructions) {
CHECK_TRAP(PushRep<float>(F32Traits::kMax));
} else if (IsInRangeF64DemoteF32RoundToNegF32Max(value)) {
CHECK_TRAP(PushRep<float>(F32Traits::kNegMax));
+ } else if (FloatTraits<double>::IsNan(value)) {
+ CHECK_TRAP(PushRep<float>(F32Traits::kQuietNan));
} else {
+ // Infinity.
uint32_t sign = (value >> 32) & F32Traits::kSignMask;
- uint32_t tag = 0;
- if (F64Traits::IsNan(value)) {
- tag = F32Traits::kQuietNanBit |
- ((value >> (F64Traits::kSigBits - F32Traits::kSigBits)) &
- F32Traits::kSigMask);
- }
- CHECK_TRAP(PushRep<float>(sign | F32Traits::kInf | tag));
+ CHECK_TRAP(PushRep<float>(sign | F32Traits::kInf));
}
break;
}
@@ -2436,9 +2428,15 @@ Result Thread::Run(int num_instructions) {
Push<double>(wabt_convert_uint64_to_double(Pop<uint64_t>())));
break;
- case Opcode::F64PromoteF32:
- CHECK_TRAP(Push<double>(Pop<float>()));
+ case Opcode::F64PromoteF32: {
+ uint32_t value = PopRep<float>();
+ if (WABT_UNLIKELY(FloatTraits<float>::IsNan(value))) {
+ CHECK_TRAP(PushRep<double>(FloatTraits<double>::kQuietNan));
+ } else {
+ CHECK_TRAP(Push<double>(Bitcast<float>(value)));
+ }
break;
+ }
case Opcode::F64ReinterpretI64:
CHECK_TRAP(PushRep<double>(Pop<uint64_t>()));