summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBen Smith <binjimin@gmail.com>2016-05-02 14:47:11 -0700
committerJF Bastien <github@jfbastien.com>2016-05-02 14:47:11 -0700
commit2559cb90937b4b88377a0e17e0725771511a08a7 (patch)
tree3f2576d5cb25e709f7f906510de84ce2c0c34c5a /src
parent203d8b2f4021e61dede148a9f0ada0f0b0a02da9 (diff)
downloadbinaryen-2559cb90937b4b88377a0e17e0725771511a08a7.tar.gz
binaryen-2559cb90937b4b88377a0e17e0725771511a08a7.tar.bz2
binaryen-2559cb90937b4b88377a0e17e0725771511a08a7.zip
Fix {i32,i64}.trunc_{s,u}/{f32,f64} in interpreter (#421)
Check the binary representation of the float instead of converting it to a float first.
Diffstat (limited to 'src')
-rw-r--r--src/support/safe_integer.cpp92
-rw-r--r--src/support/safe_integer.h10
-rw-r--r--src/wasm-interpreter.h30
3 files changed, 124 insertions, 8 deletions
diff --git a/src/support/safe_integer.cpp b/src/support/safe_integer.cpp
index bce2cbc39..fd60e560f 100644
--- a/src/support/safe_integer.cpp
+++ b/src/support/safe_integer.cpp
@@ -71,3 +71,95 @@ int64_t wasm::toSInteger64(double x) {
: (std::signbit(x) ? std::numeric_limits<int64_t>::min()
: std::numeric_limits<int64_t>::max());
}
+
+/* 3 32222222 222...00
+ * 1 09876543 210...10
+ * -------------------
+ * 0 00000000 000...00 => 0x00000000 => 0
+ * 0 10011101 111...11 => 0x4effffff => 2147483520 (~INT32_MAX)
+ * 0 10011110 000...00 => 0x4f000000 => 2147483648
+ * 0 10011110 111...11 => 0x4f7fffff => 4294967040 (~UINT32_MAX)
+ * 0 10111110 111...11 => 0x5effffff => 9223371487098961920 (~INT64_MAX)
+ * 0 10111110 000...00 => 0x5f000000 => 9223372036854775808
+ * 0 10111111 111...11 => 0x5f7fffff => 18446742974197923840 (~UINT64_MAX)
+ * 0 10111111 000...00 => 0x5f800000 => 18446744073709551616
+ * 0 11111111 000...00 => 0x7f800000 => inf
+ * 0 11111111 000...01 => 0x7f800001 => nan(0x1)
+ * 0 11111111 111...11 => 0x7fffffff => nan(0x7fffff)
+ * 1 00000000 000...00 => 0x80000000 => -0
+ * 1 01111110 111...11 => 0xbf7fffff => -1 + ulp (~UINT32_MIN, ~UINT64_MIN)
+ * 1 01111111 000...00 => 0xbf800000 => -1
+ * 1 10011110 000...00 => 0xcf000000 => -2147483648 (INT32_MIN)
+ * 1 10111110 000...00 => 0xdf000000 => -9223372036854775808 (INT64_MIN)
+ * 1 11111111 000...00 => 0xff800000 => -inf
+ * 1 11111111 000...01 => 0xff800001 => -nan(0x1)
+ * 1 11111111 111...11 => 0xffffffff => -nan(0x7fffff)
+ */
+
+bool wasm::isInRangeI32TruncS(int32_t i) {
+ uint32_t u = i;
+ return (u < 0x4f000000U) || (u >= 0x80000000U && u <= 0xcf000000U);
+}
+
+bool wasm::isInRangeI64TruncS(int32_t i) {
+ uint32_t u = i;
+ return (u < 0x5f000000U) || (u >= 0x80000000U && u <= 0xdf000000U);
+}
+
+bool wasm::isInRangeI32TruncU(int32_t i) {
+ uint32_t u = i;
+ return (u < 0x4f800000U) || (u >= 0x80000000U && u < 0xbf800000U);
+}
+
+bool wasm::isInRangeI64TruncU(int32_t i) {
+ uint32_t u = i;
+ return (u < 0x5f800000U) || (u >= 0x80000000U && u < 0xbf800000U);
+}
+
+/*
+ * 6 66655555555 5544...222221...000
+ * 3 21098765432 1098...432109...210
+ * ---------------------------------
+ * 0 00000000000 0000...000000...000 0x0000000000000000 => 0
+ * 0 10000011101 1111...111000...000 0x41dfffffffc00000 => 2147483647 (INT32_MAX)
+ * 0 10000011110 1111...111100...000 0x41efffffffe00000 => 4294967295 (UINT32_MAX)
+ * 0 10000111101 1111...111111...111 0x43dfffffffffffff => 9223372036854774784 (~INT64_MAX)
+ * 0 10000111110 0000...000000...000 0x43e0000000000000 => 9223372036854775808
+ * 0 10000111110 1111...111111...111 0x43efffffffffffff => 18446744073709549568 (~UINT64_MAX)
+ * 0 10000111111 0000...000000...000 0x43f0000000000000 => 18446744073709551616
+ * 0 11111111111 0000...000000...000 0x7ff0000000000000 => inf
+ * 0 11111111111 0000...000000...001 0x7ff0000000000001 => nan(0x1)
+ * 0 11111111111 1111...111111...111 0x7fffffffffffffff => nan(0xfff...)
+ * 1 00000000000 0000...000000...000 0x8000000000000000 => -0
+ * 1 01111111110 1111...111111...111 0xbfefffffffffffff => -1 + ulp (~UINT32_MIN, ~UINT64_MIN)
+ * 1 01111111111 0000...000000...000 0xbff0000000000000 => -1
+ * 1 10000011110 0000...000000...000 0xc1e0000000000000 => -2147483648 (INT32_MIN)
+ * 1 10000111110 0000...000000...000 0xc3e0000000000000 => -9223372036854775808 (INT64_MIN)
+ * 1 11111111111 0000...000000...000 0xfff0000000000000 => -inf
+ * 1 11111111111 0000...000000...001 0xfff0000000000001 => -nan(0x1)
+ * 1 11111111111 1111...111111...111 0xffffffffffffffff => -nan(0xfff...)
+ */
+
+bool wasm::isInRangeI32TruncS(int64_t i) {
+ uint64_t u = i;
+ return (u <= 0x41dfffffffc00000ULL) ||
+ (u >= 0x8000000000000000ULL && u <= 0xc1e0000000000000ULL);
+}
+
+bool wasm::isInRangeI32TruncU(int64_t i) {
+ uint64_t u = i;
+ return (u <= 0x41efffffffe00000ULL) ||
+ (u >= 0x8000000000000000ULL && u <= 0xbfefffffffffffffULL);
+}
+
+bool wasm::isInRangeI64TruncS(int64_t i) {
+ uint64_t u = i;
+ return (u < 0x43e0000000000000ULL) ||
+ (u >= 0x8000000000000000ULL && u <= 0xc3e0000000000000ULL);
+}
+
+bool wasm::isInRangeI64TruncU(int64_t i) {
+ uint64_t u = i;
+ return (u < 0x43f0000000000000ULL) ||
+ (u >= 0x8000000000000000ULL && u <= 0xbfefffffffffffffULL);
+}
diff --git a/src/support/safe_integer.h b/src/support/safe_integer.h
index f240644c8..ea5e16425 100644
--- a/src/support/safe_integer.h
+++ b/src/support/safe_integer.h
@@ -29,6 +29,16 @@ bool isUInteger64(double x);
bool isSInteger64(double x);
uint64_t toUInteger64(double x);
int64_t toSInteger64(double x);
+// The isInRange* functions all expect to be passed the binary representation
+// of a float or double.
+bool isInRangeI32TruncS(int32_t i);
+bool isInRangeI64TruncS(int32_t i);
+bool isInRangeI32TruncU(int32_t i);
+bool isInRangeI64TruncU(int32_t i);
+bool isInRangeI32TruncS(int64_t i);
+bool isInRangeI32TruncU(int64_t i);
+bool isInRangeI64TruncS(int64_t i);
+bool isInRangeI64TruncU(int64_t i);
} // namespace wasm
#endif // wasm_safe_integer_h
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 3d4eea722..d0e64c91e 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -640,12 +640,19 @@ private:
double val = value.getFloat();
if (std::isnan(val)) trap("truncSFloat of nan");
if (curr->type == i32) {
- if (val > (double)std::numeric_limits<int32_t>::max() || val < (double)std::numeric_limits<int32_t>::min()) trap("i32.truncSFloat overflow");
+ if (value.type == f32) {
+ if (!isInRangeI32TruncS(value.reinterpreti32())) trap("i32.truncSFloat overflow");
+ } else {
+ if (!isInRangeI32TruncS(value.reinterpreti64())) trap("i32.truncSFloat overflow");
+ }
return Literal(int32_t(val));
} else {
- int64_t converted = (int64_t)val;
- if ((val >= 1 && converted <= 0) || val < (double)LLONG_MIN) trap("i64.truncSFloat overflow");
- return Literal(converted);
+ if (value.type == f32) {
+ if (!isInRangeI64TruncS(value.reinterpreti32())) trap("i64.truncSFloat overflow");
+ } else {
+ if (!isInRangeI64TruncS(value.reinterpreti64())) trap("i64.truncSFloat overflow");
+ }
+ return Literal(int64_t(val));
}
}
@@ -653,12 +660,19 @@ private:
double val = value.getFloat();
if (std::isnan(val)) trap("truncUFloat of nan");
if (curr->type == i32) {
- if (val > (double)std::numeric_limits<uint32_t>::max() || val <= (double)-1) trap("i32.truncUFloat overflow");
+ if (value.type == f32) {
+ if (!isInRangeI32TruncU(value.reinterpreti32())) trap("i32.truncUFloat overflow");
+ } else {
+ if (!isInRangeI32TruncU(value.reinterpreti64())) trap("i32.truncUFloat overflow");
+ }
return Literal(uint32_t(val));
} else {
- uint64_t converted = (uint64_t)val;
- if (converted < val - 1 || val <= (double)-1) trap("i64.truncUFloat overflow");
- return Literal(converted);
+ if (value.type == f32) {
+ if (!isInRangeI64TruncU(value.reinterpreti32())) trap("i64.truncUFloat overflow");
+ } else {
+ if (!isInRangeI64TruncU(value.reinterpreti64())) trap("i64.truncUFloat overflow");
+ }
+ return Literal(uint64_t(val));
}
}