summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/literal.cc131
-rw-r--r--test/dump/hexfloat_f32.txt6
-rw-r--r--test/dump/hexfloat_f64.txt6
-rw-r--r--test/hexfloat.cc94
-rw-r--r--test/spec/const.txt66
-rw-r--r--test/spec/type.txt8
m---------third_party/testsuite0
7 files changed, 235 insertions, 76 deletions
diff --git a/src/literal.cc b/src/literal.cc
index e57f513e..0844ff60 100644
--- a/src/literal.cc
+++ b/src/literal.cc
@@ -27,11 +27,11 @@ namespace wabt {
namespace {
int Clz(uint32_t value) {
- return wabt_clz_u32(value);
+ return value == 0 ? 32 : wabt_clz_u32(value);
}
int Clz(uint64_t value) {
- return wabt_clz_u64(value);
+ return value == 0 ? 64 : wabt_clz_u64(value);
}
template <typename T>
@@ -47,6 +47,8 @@ struct FloatTraitsBase<float> {
static constexpr int kSigBits = 23;
static constexpr float kHugeVal = HUGE_VALF;
static constexpr int kMaxHexBufferSize = WABT_MAX_FLOAT_HEX;
+
+ static float Strto(const char* s, char** endptr) { return strtof(s, endptr); }
};
template <>
@@ -56,6 +58,10 @@ struct FloatTraitsBase<double> {
static constexpr int kSigBits = 52;
static constexpr float kHugeVal = HUGE_VAL;
static constexpr int kMaxHexBufferSize = WABT_MAX_DOUBLE_HEX;
+
+ static double Strto(const char* s, char** endptr) {
+ return strtod(s, endptr);
+ }
};
template <typename T>
@@ -92,12 +98,12 @@ class FloatParser {
static bool StringStartsWith(const char* start,
const char* end,
const char* prefix);
- static Float Strto(const char* s, char** endptr);
static Uint Make(bool sign, int exp, Uint sig);
static Uint ShiftAndRoundToNearest(Uint significand, int shift);
+ static Result ParseFloat(const char* s, const char* end, Uint* out_bits);
static Result ParseNan(const char* s, const char* end, Uint* out_bits);
- static void ParseHex(const char* s, const char* end, Uint* out_bits);
+ static Result ParseHex(const char* s, const char* end, Uint* out_bits);
static void ParseInfinity(const char* s, const char* end, Uint* out_bits);
};
@@ -127,18 +133,40 @@ bool FloatParser<T>::StringStartsWith(const char* start,
}
// static
-template <>
-float FloatParser<float>::Strto(const char* s, char** endptr) {
- return strtof(s, endptr);
-}
+template <typename T>
+Result FloatParser<T>::ParseFloat(const char* s,
+ const char* end,
+ Uint* out_bits) {
+ // Here is the normal behavior for strtof/strtod:
+ //
+ // input | errno | output |
+ // ---------------------------------
+ // overflow | ERANGE | +-HUGE_VAL |
+ // underflow | ERANGE | 0.0 |
+ // otherwise | 0 | value |
+ //
+ // So normally we need to clear errno before calling strto{f,d}, and check
+ // afterward whether it was set to ERANGE.
+ //
+ // glibc seems to have a bug where
+ // strtof("340282356779733661637539395458142568448") will return HUGE_VAL,
+ // but will not set errno to ERANGE. Since this function is only called when
+ // we know that we have parsed a "normal" number (i.e. not "inf"), we know
+ // that if we ever get HUGE_VAL, it must be overflow.
+ //
+ // The WebAssembly spec also ignores underflow, so we don't need to check for
+ // ERANGE at all.
+ char* endptr;
+ Float value = Traits::Strto(s, &endptr);
+ if (endptr != end ||
+ (value == Traits::kHugeVal || value == -Traits::kHugeVal)) {
+ return Result::Error;
+ }
-// static
-template <>
-double FloatParser<double>::Strto(const char* s, char** endptr) {
- return strtod(s, endptr);
+ memcpy(out_bits, &value, sizeof(value));
+ return Result::Ok;
}
-
// static
template <typename T>
typename FloatParser<T>::Uint FloatParser<T>::Make(bool sign,
@@ -207,9 +235,9 @@ Result FloatParser<T>::ParseNan(const char* s,
// static
template <typename T>
-void FloatParser<T>::ParseHex(const char* s, const char* end, Uint* out_bits) {
- static constexpr int kHexDigitBits = 4;
-
+Result FloatParser<T>::ParseHex(const char* s,
+ const char* end,
+ Uint* out_bits) {
bool is_neg = false;
if (*s == '-') {
is_neg = true;
@@ -229,42 +257,28 @@ void FloatParser<T>::ParseHex(const char* s, const char* end, Uint* out_bits) {
// 0x0.000001p0 => significand = 1, significand_exponent = -24
bool seen_dot = false;
Uint significand = 0;
- // How much to shift |significand| if a non-zero value is appended.
- int significand_shift = 0;
- int significand_bits = 0; // Bits of |significand|.
int significand_exponent = 0; // Exponent adjustment due to dot placement.
for (; s < end; ++s) {
uint32_t digit;
if (*s == '.') {
- if (significand != 0)
- significand_exponent += significand_shift;
- significand_shift = 0;
seen_dot = true;
- continue;
- } else if (WABT_FAILED(parse_hexdigit(*s, &digit))) {
+ } else if (WABT_SUCCEEDED(parse_hexdigit(*s, &digit))) {
+ if (Traits::kBits - Clz(significand) <= Traits::kSigPlusOneBits) {
+ significand = (significand << 4) + digit;
+ if (seen_dot)
+ significand_exponent -= 4;
+ } else if (!seen_dot) {
+ significand_exponent += 4;
+ }
+ } else {
break;
}
- significand_shift += kHexDigitBits;
- if (digit != 0 &&
- (significand == 0 || significand_bits + significand_shift <=
- Traits::kSigBits + 1 + kHexDigitBits)) {
- if (significand != 0)
- significand <<= significand_shift;
- if (seen_dot)
- significand_exponent -= significand_shift;
- significand += digit;
- significand_shift = 0;
- significand_bits += kHexDigitBits;
- }
}
- if (!seen_dot)
- significand_exponent += significand_shift;
-
if (significand == 0) {
// 0 or -0.
*out_bits = Make(is_neg, Traits::kMinExp, 0);
- return;
+ return Result::Ok;
}
int exponent = 0;
@@ -297,14 +311,11 @@ void FloatParser<T>::ParseHex(const char* s, const char* end, Uint* out_bits) {
if (exponent_is_neg)
exponent = -exponent;
- significand_bits = Traits::kBits - Clz(significand);
+ int significand_bits = Traits::kBits - Clz(significand);
// -1 for the implicit 1 bit of the significand.
exponent += significand_exponent + significand_bits - 1;
- if (exponent >= Traits::kMaxExp) {
- // inf or -inf.
- *out_bits = Make(is_neg, Traits::kMaxExp, 0);
- } else if (exponent <= Traits::kMinExp) {
+ if (exponent <= Traits::kMinExp) {
// Maybe subnormal.
if (significand_bits > Traits::kSigBits) {
significand = ShiftAndRoundToNearest(significand,
@@ -323,14 +334,14 @@ void FloatParser<T>::ParseHex(const char* s, const char* end, Uint* out_bits) {
if (significand != 0) {
*out_bits = Make(is_neg, exponent, significand);
- return;
+ return Result::Ok;
}
}
// Not subnormal, too small; return 0 or -0.
*out_bits = Make(is_neg, Traits::kMinExp, 0);
} else {
- // Normal value.
+ // Maybe Normal value.
if (significand_bits > Traits::kSigPlusOneBits) {
significand = ShiftAndRoundToNearest(
significand, significand_bits - Traits::kSigPlusOneBits);
@@ -340,8 +351,16 @@ void FloatParser<T>::ParseHex(const char* s, const char* end, Uint* out_bits) {
significand <<= (Traits::kSigPlusOneBits - significand_bits);
}
+ if (exponent >= Traits::kMaxExp) {
+ // Would be inf or -inf, but the spec doesn't allow rounding hex-floats to
+ // infinity.
+ return Result::Error;
+ }
+
*out_bits = Make(is_neg, exponent, significand & Traits::kSigMask);
}
+
+ return Result::Ok;
}
// static
@@ -374,23 +393,11 @@ Result FloatParser<T>::Parse(LiteralType literal_type,
#endif
switch (literal_type) {
case LiteralType::Int:
- case LiteralType::Float: {
- errno = 0;
- char* endptr;
- Float value;
- value = Strto(s, &endptr);
- if (endptr != end || ((value == 0 || value == Traits::kHugeVal ||
- value == -Traits::kHugeVal) &&
- errno != 0))
- return Result::Error;
-
- memcpy(out_bits, &value, sizeof(value));
- return Result::Ok;
- }
+ case LiteralType::Float:
+ return ParseFloat(s, end, out_bits);
case LiteralType::Hexfloat:
- ParseHex(s, end, out_bits);
- return Result::Ok;
+ return ParseHex(s, end, out_bits);
case LiteralType::Infinity:
ParseInfinity(s, end, out_bits);
diff --git a/test/dump/hexfloat_f32.txt b/test/dump/hexfloat_f32.txt
index 2be9bab8..d65ccb24 100644
--- a/test/dump/hexfloat_f32.txt
+++ b/test/dump/hexfloat_f32.txt
@@ -18,7 +18,7 @@
drop
f32.const 0x0.7fffffp127
drop
- f32.const 0x0.ffffffffp128
+ f32.const 0x0.ffffffffp127
drop
f32.const 0x1.ffff88p127
drop
@@ -88,7 +88,7 @@
0000042: feff 7f7e ; f32 literal
0000046: 1a ; drop
0000047: 43 ; f32.const
-0000048: 0000 807f ; f32 literal
+0000048: 0000 007f ; f32 literal
000004c: 1a ; drop
000004d: 43 ; f32.const
000004e: c4ff 7f7f ; f32 literal
@@ -139,7 +139,7 @@ Code Disassembly:
000040: 1a | drop
000041: 43 fe ff 7f 7e | f32.const 0x1.fffffcp+125
000046: 1a | drop
- 000047: 43 00 00 80 7f | f32.const inf
+ 000047: 43 00 00 00 7f | f32.const 0x1p+127
00004c: 1a | drop
00004d: 43 c4 ff 7f 7f | f32.const 0x1.ffff88p+127
000052: 1a | drop
diff --git a/test/dump/hexfloat_f64.txt b/test/dump/hexfloat_f64.txt
index 7f78e752..c81e4a28 100644
--- a/test/dump/hexfloat_f64.txt
+++ b/test/dump/hexfloat_f64.txt
@@ -18,7 +18,7 @@
drop
f64.const 0x0.7fffffffffffp1023
drop
- f64.const 0x0.ffffffffffffffffp1024
+ f64.const 0x0.ffffffffffffffffp1023
drop
f64.const 0x1.ffffffffffffcp1023
drop
@@ -88,7 +88,7 @@
000005e: c0ff ffff ffff cf7f ; f64 literal
0000066: 1a ; drop
0000067: 44 ; f64.const
-0000068: 0000 0000 0000 f07f ; f64 literal
+0000068: 0000 0000 0000 e07f ; f64 literal
0000070: 1a ; drop
0000071: 44 ; f64.const
0000072: fcff ffff ffff ef7f ; f64 literal
@@ -141,7 +141,7 @@ Code Disassembly:
00005e: 1a | drop
00005f: 44 c0 ff ff ff ff ff cf 7f | f64.const 0x1.fffffffffffcp+1021
000068: 1a | drop
- 000069: 44 00 00 00 00 00 00 f0 7f | f64.const inf
+ 000069: 44 00 00 00 00 00 00 e0 7f | f64.const 0x1p+1023
000072: 1a | drop
000073: 44 fc ff ff ff ff ff ef 7f | f64.const 0x1.ffffffffffffcp+1023
00007c: 1a | drop
diff --git a/test/hexfloat.cc b/test/hexfloat.cc
index 70e5c4c4..2b4576b5 100644
--- a/test/hexfloat.cc
+++ b/test/hexfloat.cc
@@ -114,7 +114,8 @@ class AllFloatsParseTest : public ThreadedTest {
int len = snprintf(buffer, sizeof(buffer), "%a", value);
uint32_t me;
- parse_float(LiteralType::Hexfloat, buffer, buffer + len, &me);
+ ASSERT_EQ(Result::Ok,
+ parse_float(LiteralType::Hexfloat, buffer, buffer + len, &me));
ASSERT_EQ(me, bits);
}
LOG_DONE();
@@ -171,7 +172,8 @@ class AllFloatsRoundtripTest : public ThreadedTest {
int len = strlen(buffer);
uint32_t new_bits;
- parse_float(ClassifyFloat(bits), buffer, buffer + len, &new_bits);
+ ASSERT_EQ(Result::Ok, parse_float(ClassifyFloat(bits), buffer,
+ buffer + len, &new_bits));
ASSERT_EQ(new_bits, bits);
}
LOG_DONE();
@@ -197,7 +199,8 @@ class ManyDoublesParseTest : public ThreadedTest {
int len = snprintf(buffer, sizeof(buffer), "%a", value);
uint64_t me;
- parse_double(LiteralType::Hexfloat, buffer, buffer + len, &me);
+ ASSERT_EQ(Result::Ok,
+ parse_double(LiteralType::Hexfloat, buffer, buffer + len, &me));
ASSERT_EQ(me, bits);
}
LOG_DONE();
@@ -256,7 +259,8 @@ class ManyDoublesRoundtripTest : public ThreadedTest {
int len = strlen(buffer);
uint64_t new_bits;
- parse_double(ClassifyDouble(bits), buffer, buffer + len, &new_bits);
+ ASSERT_EQ(Result::Ok, parse_double(ClassifyDouble(bits), buffer,
+ buffer + len, &new_bits));
ASSERT_EQ(new_bits, bits);
}
LOG_DONE();
@@ -266,3 +270,85 @@ class ManyDoublesRoundtripTest : public ThreadedTest {
TEST_F(ManyDoublesRoundtripTest, Run) {
RunThreads();
}
+
+static void AssertHexFloatEquals(uint32_t expected_bits, const char* s) {
+ uint32_t actual_bits;
+ ASSERT_EQ(Result::Ok,
+ parse_float(LiteralType::Hexfloat, s, s + strlen(s), &actual_bits));
+ ASSERT_EQ(expected_bits, actual_bits);
+}
+
+static void AssertHexFloatFails(const char* s) {
+ uint32_t actual_bits;
+ ASSERT_EQ(Result::Error,
+ parse_float(LiteralType::Hexfloat, s, s + strlen(s), &actual_bits));
+}
+
+static void AssertHexDoubleEquals(uint64_t expected_bits, const char* s) {
+ uint64_t actual_bits;
+ ASSERT_EQ(Result::Ok, parse_double(LiteralType::Hexfloat, s, s + strlen(s),
+ &actual_bits));
+ ASSERT_EQ(expected_bits, actual_bits);
+}
+
+static void AssertHexDoubleFails(const char* s) {
+ uint64_t actual_bits;
+ ASSERT_EQ(Result::Error, parse_double(LiteralType::Hexfloat, s, s + strlen(s),
+ &actual_bits));
+}
+
+TEST(ParseFloat, NonCanonical) {
+ AssertHexFloatEquals(0x3f800000, "0x00000000000000000000001.0p0");
+ AssertHexFloatEquals(0x3f800000, "0x1.00000000000000000000000p0");
+ AssertHexFloatEquals(0x3f800000, "0x0.0000000000000000000001p88");
+}
+
+TEST(ParseFloat, Rounding) {
+ // |------- 23 bits -----| V-- extra bit
+ //
+ // 11111111111111111111101 0 ==> no rounding
+ AssertHexFloatEquals(0x7f7ffffd, "0x1.fffffap127");
+ // 11111111111111111111101 1 ==> round up
+ AssertHexFloatEquals(0x7f7ffffe, "0x1.fffffbp127");
+ // 11111111111111111111110 0 ==> no rounding
+ AssertHexFloatEquals(0x7f7ffffe, "0x1.fffffcp127");
+ // 11111111111111111111110 1 ==> round down
+ AssertHexFloatEquals(0x7f7ffffe, "0x1.fffffdp127");
+ // 11111111111111111111111 0 ==> no rounding
+ AssertHexFloatEquals(0x7f7fffff, "0x1.fffffep127");
+}
+
+TEST(ParseFloat, OutOfRange) {
+ AssertHexFloatFails("0x1p128");
+ AssertHexFloatFails("-0x1p128");
+ AssertHexFloatFails("0x1.ffffffp127");
+ AssertHexFloatFails("-0x1.ffffffp127");
+}
+
+TEST(ParseDouble, NonCanonical) {
+ AssertHexDoubleEquals(0x3ff0000000000000, "0x00000000000000000000001.0p0");
+ AssertHexDoubleEquals(0x3ff0000000000000, "0x1.00000000000000000000000p0");
+ AssertHexDoubleEquals(0x3ff0000000000000, "0x0.0000000000000000000001p88");
+}
+
+TEST(ParseDouble, Rounding) {
+ // |-------------------- 52 bits ---------------------| V-- extra bit
+ //
+ // 1111111111111111111111111111111111111111111111111101 0 ==> no rounding
+ AssertHexDoubleEquals(0x7feffffffffffffd, "0x1.ffffffffffffd0p1023");
+ // 1111111111111111111111111111111111111111111111111101 1 ==> round up
+ AssertHexDoubleEquals(0x7feffffffffffffe, "0x1.ffffffffffffd8p1023");
+ // 1111111111111111111111111111111111111111111111111110 0 ==> no rounding
+ AssertHexDoubleEquals(0x7feffffffffffffe, "0x1.ffffffffffffe0p1023");
+ // 1111111111111111111111111111111111111111111111111110 1 ==> round down
+ AssertHexDoubleEquals(0x7feffffffffffffe, "0x1.ffffffffffffe8p1023");
+ // 1111111111111111111111111111111111111111111111111111 0 ==> no rounding
+ AssertHexDoubleEquals(0x7fefffffffffffff, "0x1.fffffffffffff0p1023");
+}
+
+TEST(ParseDouble, OutOfRange) {
+ AssertHexDoubleFails("0x1p1024");
+ AssertHexDoubleFails("-0x1p1024");
+ AssertHexDoubleFails("0x1.fffffffffffff8p1023");
+ AssertHexDoubleFails("-0x1.fffffffffffff8p1023");
+}
diff --git a/test/spec/const.txt b/test/spec/const.txt
index 67592979..4b61a8df 100644
--- a/test/spec/const.txt
+++ b/test/spec/const.txt
@@ -33,5 +33,69 @@ out/third_party/testsuite/const.wast:45: assert_malformed passed:
out/third_party/testsuite/const/const.15.wast:1:18: invalid literal "-9223372036854775809"
(func (i64.const -9223372036854775809) drop)
^^^^^^^^^^^^^^^^^^^^
-8/8 tests passed.
+out/third_party/testsuite/const.wast:56: assert_malformed passed:
+ out/third_party/testsuite/const/const.22.wast:1:18: invalid literal "0x1p128"
+ (func (f32.const 0x1p128) drop)
+ ^^^^^^^
+out/third_party/testsuite/const.wast:60: assert_malformed passed:
+ out/third_party/testsuite/const/const.23.wast:1:18: invalid literal "-0x1p128"
+ (func (f32.const -0x1p128) drop)
+ ^^^^^^^^
+out/third_party/testsuite/const.wast:64: assert_malformed passed:
+ out/third_party/testsuite/const/const.24.wast:1:18: invalid literal "0x1.ffffffp127"
+ (func (f32.const 0x1.ffffffp127) drop)
+ ^^^^^^^^^^^^^^
+out/third_party/testsuite/const.wast:68: assert_malformed passed:
+ out/third_party/testsuite/const/const.25.wast:1:18: invalid literal "-0x1.ffffffp127"
+ (func (f32.const -0x1.ffffffp127) drop)
+ ^^^^^^^^^^^^^^^
+out/third_party/testsuite/const.wast:75: assert_malformed passed:
+ out/third_party/testsuite/const/const.28.wast:1:18: invalid literal "1e39"
+ (func (f32.const 1e39) drop)
+ ^^^^
+out/third_party/testsuite/const.wast:79: assert_malformed passed:
+ out/third_party/testsuite/const/const.29.wast:1:18: invalid literal "-1e39"
+ (func (f32.const -1e39) drop)
+ ^^^^^
+out/third_party/testsuite/const.wast:86: assert_malformed passed:
+ out/third_party/testsuite/const/const.32.wast:1:18: invalid literal "340282356779733661637539395458142568448"
+ (func (f32.const 340282356779733661637539395458142568448) drop)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+out/third_party/testsuite/const.wast:90: assert_malformed passed:
+ out/third_party/testsuite/const/const.33.wast:1:18: invalid literal "-340282356779733661637539395458142568448"
+ (func (f32.const -340282356779733661637539395458142568448) drop)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+out/third_party/testsuite/const.wast:101: assert_malformed passed:
+ out/third_party/testsuite/const/const.40.wast:1:18: invalid literal "0x1p1024"
+ (func (f64.const 0x1p1024) drop)
+ ^^^^^^^^
+out/third_party/testsuite/const.wast:105: assert_malformed passed:
+ out/third_party/testsuite/const/const.41.wast:1:18: invalid literal "-0x1p1024"
+ (func (f64.const -0x1p1024) drop)
+ ^^^^^^^^^
+out/third_party/testsuite/const.wast:109: assert_malformed passed:
+ out/third_party/testsuite/const/const.42.wast:1:18: invalid literal "0x1.fffffffffffff8p1023"
+ (func (f64.const 0x1.fffffffffffff8p1023) drop)
+ ^^^^^^^^^^^^^^^^^^^^^^^
+out/third_party/testsuite/const.wast:113: assert_malformed passed:
+ out/third_party/testsuite/const/const.43.wast:1:18: invalid literal "-0x1.fffffffffffff8p1023"
+ (func (f64.const -0x1.fffffffffffff8p1023) drop)
+ ^^^^^^^^^^^^^^^^^^^^^^^^
+out/third_party/testsuite/const.wast:120: assert_malformed passed:
+ out/third_party/testsuite/const/const.46.wast:1:18: invalid literal "1e309"
+ (func (f64.const 1e309) drop)
+ ^^^^^
+out/third_party/testsuite/const.wast:124: assert_malformed passed:
+ out/third_party/testsuite/const/const.47.wast:1:18: invalid literal "-1e309"
+ (func (f64.const -1e309) drop)
+ ^^^^^^
+out/third_party/testsuite/const.wast:131: assert_malformed passed:
+ out/third_party/testsuite/const/const.50.wast:1:18: invalid literal "269653970229347356221791135597556535197105851288767494898376215204735891170042808140884337949150317257310688430271573696351481990334196274152701320055306275479074865864826923114368235135583993416113802762682700913456874855354834422248712838998185022412196739306217084753107265771378949821875606039276187287552"
+ (func (f64.const 269653970229347356221791135597556535197105851288767494898376...
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+out/third_party/testsuite/const.wast:135: assert_malformed passed:
+ out/third_party/testsuite/const/const.51.wast:1:18: invalid literal "-269653970229347356221791135597556535197105851288767494898376215204735891170042808140884337949150317257310688430271573696351481990334196274152701320055306275479074865864826923114368235135583993416113802762682700913456874855354834422248712838998185022412196739306217084753107265771378949821875606039276187287552"
+ (func (f64.const -26965397022934735622179113559755653519710585128876749489837...
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+24/24 tests passed.
;;; STDOUT ;;)
diff --git a/test/spec/type.txt b/test/spec/type.txt
index 952304eb..1fc10a57 100644
--- a/test/spec/type.txt
+++ b/test/spec/type.txt
@@ -10,7 +10,9 @@ out/third_party/testsuite/type.wast:48: assert_malformed passed:
out/third_party/testsuite/type/type.2.wast:1:21: syntax error, unexpected VAR, expecting ) or VALUE_TYPE
(type (func (result $x i32)))
^^
-out/third_party/testsuite/type.wast:52: expected module to be invalid: "out/third_party/testsuite/type/type.3.wast"
-out/third_party/testsuite/type.wast:56: expected module to be invalid: "out/third_party/testsuite/type/type.4.wast"
-2/4 tests passed.
+out/third_party/testsuite/type.wast:53: assert_invalid passed:
+ error: @0x0000000e: result count must be 0 or 1
+out/third_party/testsuite/type.wast:57: assert_invalid passed:
+ error: @0x0000000e: result count must be 0 or 1
+4/4 tests passed.
;;; STDOUT ;;)
diff --git a/third_party/testsuite b/third_party/testsuite
-Subproject aabd5c2c6fe4d6576ab09bece39b32954d18c44
+Subproject ae1dcc2256cd319975e98f3b25526f55f6be07d