From 5a345b53852cfb4892ccc5d30991dce4dde978b3 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 5 Oct 2015 15:19:40 -0700 Subject: [PATCH 01/18] Add more tests, and some more test ideas. --- ml-proto/TestingTodo.md | 50 +++-- ml-proto/test/float_exprs.wast | 243 ++++++++++++++++++++++++ ml-proto/test/i32.wast | 3 + ml-proto/test/i64.wast | 4 +- ml-proto/test/int_exprs.wast | 327 +++++++++++++++++++++++++++++++++ ml-proto/test/traps.wast | 90 +++++++++ 6 files changed, 702 insertions(+), 15 deletions(-) create mode 100644 ml-proto/test/float_exprs.wast create mode 100644 ml-proto/test/int_exprs.wast create mode 100644 ml-proto/test/traps.wast diff --git a/ml-proto/TestingTodo.md b/ml-proto/TestingTodo.md index 39026d9eb6..c9728e8888 100644 --- a/ml-proto/TestingTodo.md +++ b/ml-proto/TestingTodo.md @@ -6,6 +6,7 @@ welcome. Misc semantics: - ~~test that linear memory is little-endian for all integers and floats~~ + - test that 8-bit, 16-bit, and 32-bit atomic operations are lock-free (is this possible?) - test that unaligned and misaligned accesses work, even if slow - ~~test that runaway recursion traps~~ - test that too-big linear memory resize fails appropriately @@ -16,10 +17,10 @@ Misc semantics: Operator semantics: - test that promote/demote, sext/trunc, zext/trunc is bit-preserving if not NaN - ~~test that clz/ctz handle zero~~ - - test that numbers slightly outside of the int32 range round into the int32 range in floating-to-int32 conversion + - ~~test that numbers slightly outside of the int32 range round into the int32 range in floating-to-int32 conversion~~ - ~~test that neg, abs, copysign, reinterpretcast, store+load, set+get, preserve the sign bit and significand bits of NaN and don't canonicalize~~ - ~~test that shifts don't mask their shift count. 32 is particularly nice to test.~~ - - test that `page_size` returns something sane [(power of 2?)](https://github.com/WebAssembly/design/pull/296) + - test that `page_size` returns a power of 2 - ~~test that arithmetic operands are evaluated left-to-right~~ - ~~test that add/sub/mul/wrap/wrapping-store silently wrap on overflow~~ - ~~test that sdiv/udiv/srem/urem trap on divide-by-zero~~ @@ -27,11 +28,14 @@ Operator semantics: - ~~test that srem doesn't trap when the corresponding sdiv would overflow~~ - ~~test that float-to-integer conversion traps on overflow and invalid~~ - ~~test that unsigned operations are properly unsigned~~ + - ~~test that signed integer div rounds toward zero~~ + - ~~test that signed integer mod has the sign of the dividend~~ Floating point semantics: - ~~test for round-to-nearest rounding~~ - ~~test for ties-to-even rounding~~ - ~~test that all operations with floating point inputs correctly handle all their NaN, -0, 0, Infinity, and -Infinity special cases~~ + - ~~test that signaling NaN is indistinguishable from quiet NaN~~ - ~~test that all operations that can overflow produce Infinity and with the correct sign~~ - ~~test that all operations that can divide by zero produce Infinity with the correct sign~~ - ~~test that all operations that can have an invalid produce NaN~~ @@ -40,6 +44,7 @@ Floating point semantics: - ~~test that signalling NaN doesn't cause weirdness~~ - ~~test that signalling/quiet NaNs can have sign bits and payloads in literals~~ - test that conversion from int32/int64 to float32 rounds correctly + - test that [relaxed optimizations](https://gcc.gnu.org/wiki/FloatingPointMath) are not done Linear memory semantics: - test that loading from null works @@ -50,37 +55,43 @@ Linear memory semantics: - test that loadwithoffset traps in overflow cases - test that newly allocated memory is zeroed - test that resize_memory does a full 32-bit unsigned check for page_size divisibility + - test that load/store addreses are full int32 (or int64), and not OCaml int + - test that when allocating 4GiB, accessing index -1 fails Function pointer semantics: - test that function pointers work [correctly](https://github.com/WebAssembly/design/issues/89) Expression optimizer bait: - - test that `a+1>n is not folded to x + +(module + (func $i32.no_fold_shl_shr_s (param $x i32) (result i32) + (i32.shr_s (i32.shl (get_local $x) (i32.const 1)) (i32.const 1))) + (export "i32.no_fold_shl_shr_s" $i32.no_fold_shl_shr_s) + (func $i32.no_fold_shl_shr_u (param $x i32) (result i32) + (i32.shr_u (i32.shl (get_local $x) (i32.const 1)) (i32.const 1))) + (export "i32.no_fold_shl_shr_u" $i32.no_fold_shl_shr_u) + + (func $i64.no_fold_shl_shr_s (param $x i64) (result i64) + (i64.shr_s (i64.shl (get_local $x) (i64.const 1)) (i64.const 1))) + (export "i64.no_fold_shl_shr_s" $i64.no_fold_shl_shr_s) + (func $i64.no_fold_shl_shr_u (param $x i64) (result i64) + (i64.shr_u (i64.shl (get_local $x) (i64.const 1)) (i64.const 1))) + (export "i64.no_fold_shl_shr_u" $i64.no_fold_shl_shr_u) +) + +(assert_return (invoke "i32.no_fold_shl_shr_s" (i32.const 0x80000000)) (i32.const 0)) +(assert_return (invoke "i32.no_fold_shl_shr_u" (i32.const 0x80000000)) (i32.const 0)) +(assert_return (invoke "i64.no_fold_shl_shr_s" (i64.const 0x8000000000000000)) (i64.const 0)) +(assert_return (invoke "i64.no_fold_shl_shr_u" (i64.const 0x8000000000000000)) (i64.const 0)) + +;; Test that x>>n< Date: Tue, 6 Oct 2015 11:52:31 -0700 Subject: [PATCH 02/18] Test x/0 where zero is an immediate constant. --- ml-proto/TestingTodo.md | 2 +- ml-proto/test/float_exprs.wast | 54 ++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/ml-proto/TestingTodo.md b/ml-proto/TestingTodo.md index c9728e8888..b1ed876843 100644 --- a/ml-proto/TestingTodo.md +++ b/ml-proto/TestingTodo.md @@ -72,7 +72,7 @@ Expression optimizer bait: - ~~test that `x != x` is not folded to false, `x == x` is not folded to true, `x < x` is not folded to false, etc.~~ - ~~test that signed integer div of negative by constant power of 2 is not ashr~~ - ~~test unsigned and signed division by 3, 5, 7~~ - - test that floating-point division by immediate 0 and -0 is defined + - ~~test that floating-point division by immediate 0 and -0 is defined~~ - ~~test that floating-point (x*y)/y isn't folded to x~~ - ~~test that floating-point (x+y)-y isn't folded to x~~ - test that ueq/one/etc aren't folded to oeq/une/etc. diff --git a/ml-proto/test/float_exprs.wast b/ml-proto/test/float_exprs.wast index 5ab2307e79..01804b9015 100644 --- a/ml-proto/test/float_exprs.wast +++ b/ml-proto/test/float_exprs.wast @@ -241,3 +241,57 @@ (assert_return (invoke "f64.no_reassociate_mul" (f64.const 0x1.73881a52e0401p-501) (f64.const -0x1.1b68dd9efb1a7p+788) (f64.const 0x1.d1c5e6a3eb27cp-762) (f64.const -0x1.56cb2fcc7546fp+88)) (f64.const 0x1.f508db92c34efp-386)) (assert_return (invoke "f64.no_reassociate_mul" (f64.const 0x1.2efa87859987cp+692) (f64.const 0x1.68e4373e241p-423) (f64.const 0x1.4e2d0fb383a57p+223) (f64.const -0x1.301d3265c737bp-23)) (f64.const -0x1.4b2b6c393f30cp+470)) (assert_return (invoke "f64.no_reassociate_mul" (f64.const 0x1.1013f7498b95fp-234) (f64.const 0x1.d2d1c36fff138p-792) (f64.const -0x1.cbf1824ea7bfdp+728) (f64.const -0x1.440da9c8b836dp-599)) (f64.const 0x1.1a16512881c91p-895)) + +;; Test that x/0 is not folded away. + +(module + (func $f32.no_fold_div_0 (param $x f32) (result f32) + (f32.div (get_local $x) (f32.const 0.0))) + (export "f32.no_fold_div_0" $f32.no_fold_div_0) + + (func $f64.no_fold_div_0 (param $x f64) (result f64) + (f64.div (get_local $x) (f64.const 0.0))) + (export "f64.no_fold_div_0" $f64.no_fold_div_0) +) + +(assert_return (invoke "f32.no_fold_div_0" (f32.const 1.0)) (f32.const infinity)) +(assert_return (invoke "f32.no_fold_div_0" (f32.const -1.0)) (f32.const -infinity)) +(assert_return (invoke "f32.no_fold_div_0" (f32.const infinity)) (f32.const infinity)) +(assert_return (invoke "f32.no_fold_div_0" (f32.const -infinity)) (f32.const -infinity)) +(assert_return_nan (invoke "f32.no_fold_div_0" (f32.const 0))) +(assert_return_nan (invoke "f32.no_fold_div_0" (f32.const -0))) +(assert_return_nan (invoke "f32.no_fold_div_0" (f32.const nan))) +(assert_return (invoke "f64.no_fold_div_0" (f64.const 1.0)) (f64.const infinity)) +(assert_return (invoke "f64.no_fold_div_0" (f64.const -1.0)) (f64.const -infinity)) +(assert_return (invoke "f64.no_fold_div_0" (f64.const infinity)) (f64.const infinity)) +(assert_return (invoke "f64.no_fold_div_0" (f64.const -infinity)) (f64.const -infinity)) +(assert_return_nan (invoke "f64.no_fold_div_0" (f64.const 0))) +(assert_return_nan (invoke "f64.no_fold_div_0" (f64.const -0))) +(assert_return_nan (invoke "f64.no_fold_div_0" (f64.const nan))) + +;; Test that x/-0 is not folded away. + +(module + (func $f32.no_fold_div_0 (param $x f32) (result f32) + (f32.div (get_local $x) (f32.const -0.0))) + (export "f32.no_fold_div_0" $f32.no_fold_div_0) + + (func $f64.no_fold_div_0 (param $x f64) (result f64) + (f64.div (get_local $x) (f64.const -0.0))) + (export "f64.no_fold_div_0" $f64.no_fold_div_0) +) + +(assert_return (invoke "f32.no_fold_div_0" (f32.const 1.0)) (f32.const -infinity)) +(assert_return (invoke "f32.no_fold_div_0" (f32.const -1.0)) (f32.const infinity)) +(assert_return (invoke "f32.no_fold_div_0" (f32.const infinity)) (f32.const -infinity)) +(assert_return (invoke "f32.no_fold_div_0" (f32.const -infinity)) (f32.const infinity)) +(assert_return_nan (invoke "f32.no_fold_div_0" (f32.const 0))) +(assert_return_nan (invoke "f32.no_fold_div_0" (f32.const -0))) +(assert_return_nan (invoke "f32.no_fold_div_0" (f32.const nan))) +(assert_return (invoke "f64.no_fold_div_0" (f64.const 1.0)) (f64.const -infinity)) +(assert_return (invoke "f64.no_fold_div_0" (f64.const -1.0)) (f64.const infinity)) +(assert_return (invoke "f64.no_fold_div_0" (f64.const infinity)) (f64.const -infinity)) +(assert_return (invoke "f64.no_fold_div_0" (f64.const -infinity)) (f64.const infinity)) +(assert_return_nan (invoke "f64.no_fold_div_0" (f64.const 0))) +(assert_return_nan (invoke "f64.no_fold_div_0" (f64.const -0))) +(assert_return_nan (invoke "f64.no_fold_div_0" (f64.const nan))) From 2d53b23efaba8e1cdfe82e37b5ddae8039cf99df Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 6 Oct 2015 12:55:17 -0700 Subject: [PATCH 03/18] Test for load+store optimizations in the presence of mixed types and addresses. --- ml-proto/TestingTodo.md | 2 +- ml-proto/test/memory_redundancy.wast | 44 ++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 ml-proto/test/memory_redundancy.wast diff --git a/ml-proto/TestingTodo.md b/ml-proto/TestingTodo.md index b1ed876843..aaa8c404e9 100644 --- a/ml-proto/TestingTodo.md +++ b/ml-proto/TestingTodo.md @@ -87,7 +87,7 @@ Misc optimizer bait: - ~~test that the impl doesn't constant-fold away or DCE away or speculate operations that should trap, such as `1/0u`, `1/0`, `1%0u`, `1%0, convertToInt(NaN)`, `INT_MIN/-1` and so on.~~ - test that likely constant folding uses the correct rounding mode - test that the scheduler doesn't move a trapping div past a call which may not return - - test that redundant-load elimination, dead-store elimination, and/or store+load forwarding correctly respect interfering stores of different types (aka no TBAA) + - ~~test that redundant-load elimination, dead-store elimination, and/or store+load forwarding correctly respect interfering stores of different types (aka no TBAA)~~ - test that linearized multidimensional array accesses can have overindexing in interesting ways - test that 32-bit loop induction variables that wrap aren't promoted to 64-bit - test that functions with C standard library names aren't assumed to have C standarad library semantics diff --git a/ml-proto/test/memory_redundancy.wast b/ml-proto/test/memory_redundancy.wast new file mode 100644 index 0000000000..cef690ec16 --- /dev/null +++ b/ml-proto/test/memory_redundancy.wast @@ -0,0 +1,44 @@ +;; Test that optimizers don't do redundant-load, store-to-load, or dead-store +;; optimizations when there are interfering stores, even of different types +;; and to non-identical addresses. + +(module + (memory 16 16) + + (export "zero_everything" $zero_everything) + (func $zero_everything + (i32.store (i32.const 0) (i32.const 0)) + (i32.store (i32.const 4) (i32.const 0)) + (i32.store (i32.const 8) (i32.const 0)) + (i32.store (i32.const 12) (i32.const 0)) + ) + + (export "test_store_to_load" $test_store_to_load) + (func $test_store_to_load (result i32) + (i32.store (i32.const 8) (i32.const 0)) + (f32.store (i32.const 5) (f32.const -0.0)) + (i32.load (i32.const 8)) + ) + + (export "test_redundant_load" $test_redundant_load) + (func $test_redundant_load (result i32) + (i32.load (i32.const 8)) + (f32.store (i32.const 5) (f32.const -0.0)) + (i32.load (i32.const 8)) + ) + + (export "test_dead_store" $test_dead_store) + (func $test_dead_store (result f32) + (local $t f32) + (i32.store (i32.const 8) (i32.const 0x23232323)) + (set_local $t (f32.load (i32.const 11))) + (i32.store (i32.const 8) (i32.const 0)) + (get_local $t) + ) +) + +(assert_return (invoke "test_store_to_load") (i32.const 0x00000080)) +(invoke "zero_everything") +(assert_return (invoke "test_redundant_load") (i32.const 0x00000080)) +(invoke "zero_everything") +(assert_return (invoke "test_dead_store") (f32.const 0x1.18p-144)) From b93c2a697ff42f3cfd6b2138ed53d23ce098f519 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 8 Oct 2015 05:14:02 -0700 Subject: [PATCH 04/18] Test that loads and stores don't do x87-style canonicalization. --- ml-proto/TestingTodo.md | 2 +- ml-proto/test/float_memory.wast | 64 +++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 ml-proto/test/float_memory.wast diff --git a/ml-proto/TestingTodo.md b/ml-proto/TestingTodo.md index aaa8c404e9..c137151e2e 100644 --- a/ml-proto/TestingTodo.md +++ b/ml-proto/TestingTodo.md @@ -100,7 +100,7 @@ Misc x87-isms: - ~~test for invalid Precision-Control-style x87 math~~ - ~~test for invalid -ffloat-store-style x87 math~~ - ~~test for evaluating intermediate results at greater precision~~ - - test for loading and storing NaNs + - ~~test for loading and storing NaNs~~ Control flow: - test that continue goes to the right place in `do_while` and `forever` diff --git a/ml-proto/test/float_memory.wast b/ml-proto/test/float_memory.wast new file mode 100644 index 0000000000..01ec5f499b --- /dev/null +++ b/ml-proto/test/float_memory.wast @@ -0,0 +1,64 @@ +;; x87 loads and stores canonicalize some bit patterns. Test that wasm loads and +;; stores don't do this. + +(module + (memory 4 4) + + (func $store_i32 (param $x i32) + (i32.store (i32.const 0) (get_local $x))) + + (func $load_i32 (result i32) + (i32.load (i32.const 0))) + + (func $store_f32 (param $x f32) + (f32.store (i32.const 0) (get_local $x))) + + (func $load_f32 (result f32) + (f32.load (i32.const 0))) + + (export "store_i32" $store_i32) + (export "load_i32" $load_i32) + (export "store_f32" $store_f32) + (export "load_f32" $load_f32) +) + +(invoke "store_i32" (i32.const 0x7f800001)) +(assert_return (invoke "load_f32") (f32.const nan(0x000001))) +(invoke "store_i32" (i32.const 0x80000000)) +(assert_return (invoke "load_f32") (f32.const -0.0)) + +(invoke "store_f32" (f32.const nan(0x000001))) +(assert_return (invoke "load_i32") (i32.const 0x7f800001)) +(invoke "store_f32" (f32.const -0.0)) +(assert_return (invoke "load_i32") (i32.const 0x80000000)) + +(module + (memory 8 8) + + (func $store_i64 (param $x i64) + (i64.store (i32.const 0) (get_local $x))) + + (func $load_i64 (result i64) + (i64.load (i32.const 0))) + + (func $store_f64 (param $x f64) + (f64.store (i32.const 0) (get_local $x))) + + (func $load_f64 (result f64) + (f64.load (i32.const 0))) + + (export "store_i64" $store_i64) + (export "load_i64" $load_i64) + (export "store_f64" $store_f64) + (export "load_f64" $load_f64) +) + +(invoke "store_i64" (i64.const 0x7ff0000000000001)) +(assert_return (invoke "load_f64") (f64.const nan(0x0000000000001))) +(invoke "store_i64" (i64.const 0x8000000000000000)) +(assert_return (invoke "load_f64") (f64.const -0.0)) + +(invoke "store_f64" (f64.const nan(0x0000000000001))) +(assert_return (invoke "load_i64") (i64.const 0x7ff0000000000001)) +(invoke "store_f64" (f64.const -0.0)) +(assert_return (invoke "load_i64") (i64.const 0x8000000000000000)) From 9f2518e79792da961d74d00b0ce4f03df108932c Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 8 Oct 2015 05:14:07 -0700 Subject: [PATCH 05/18] Test that sqrt(x*x+y*y) is not folded to hypot. --- ml-proto/TestingTodo.md | 2 +- ml-proto/test/float_exprs.wast | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/ml-proto/TestingTodo.md b/ml-proto/TestingTodo.md index c137151e2e..a4b1bfb1ea 100644 --- a/ml-proto/TestingTodo.md +++ b/ml-proto/TestingTodo.md @@ -78,7 +78,7 @@ Expression optimizer bait: - test that ueq/one/etc aren't folded to oeq/une/etc. - ~~test that floating point add/mul aren't reassociated even when tempting~~ - ~~test that floating point mul+add isn't folded to fma even when tempting~~ - - test that floating point sqrt(x*x+y*y) isn't folded to hypot even when tempting + - ~~test that floating point sqrt(x*x+y*y) isn't folded to hypot even when tempting~~ - test that 1/x isn't translated into reciprocal-approximate - test that 1/sqrt(x) isn't approximated either - ~~test that fp division by non-power-2 constant gets full precision (isn't a multiply-by-reciprocal deal)?~~ diff --git a/ml-proto/test/float_exprs.wast b/ml-proto/test/float_exprs.wast index 01804b9015..2477bb9554 100644 --- a/ml-proto/test/float_exprs.wast +++ b/ml-proto/test/float_exprs.wast @@ -295,3 +295,28 @@ (assert_return_nan (invoke "f64.no_fold_div_0" (f64.const 0))) (assert_return_nan (invoke "f64.no_fold_div_0" (f64.const -0))) (assert_return_nan (invoke "f64.no_fold_div_0" (f64.const nan))) + +;; Test that sqrt(x*x+y*y) is not folded to hypot. + +(module + (func $f32.no_fold_to_hypot (param $x f32) (param $y f32) (result f32) + (f32.sqrt (f32.add (f32.mul (get_local $x) (get_local $x)) + (f32.mul (get_local $y) (get_local $y))))) + (export "f32.no_fold_to_hypot" $f32.no_fold_to_hypot) + + (func $f64.no_fold_to_hypot (param $x f64) (param $y f64) (result f64) + (f64.sqrt (f64.add (f64.mul (get_local $x) (get_local $x)) + (f64.mul (get_local $y) (get_local $y))))) + (export "f64.no_fold_to_hypot" $f64.no_fold_to_hypot) +) + +(assert_return (invoke "f32.no_fold_to_hypot" (f32.const 0x1.c2f338p-81) (f32.const 0x1.401b5ep-68)) (f32.const 0x1.401cccp-68)) +(assert_return (invoke "f32.no_fold_to_hypot" (f32.const -0x1.c38d1p-71) (f32.const -0x1.359ddp-107)) (f32.const 0x1.c36a62p-71)) +(assert_return (invoke "f32.no_fold_to_hypot" (f32.const -0x1.99e0cap-114) (f32.const -0x1.ed0c6cp-69)) (f32.const 0x1.ed0e48p-69)) +(assert_return (invoke "f32.no_fold_to_hypot" (f32.const -0x1.1b6ceap+5) (f32.const 0x1.5440bep+17)) (f32.const 0x1.5440cp+17)) +(assert_return (invoke "f32.no_fold_to_hypot" (f32.const 0x1.8f019ep-76) (f32.const -0x1.182308p-71)) (f32.const 0x1.17e2bcp-71)) +(assert_return (invoke "f64.no_fold_to_hypot" (f64.const 0x1.1a0ac4f7c8711p-636) (f64.const 0x1.1372ebafff551p-534)) (f64.const 0x1.13463fa37014ep-534)) +(assert_return (invoke "f64.no_fold_to_hypot" (f64.const 0x1.b793512167499p+395) (f64.const -0x1.11cbc52af4c36p+410)) (f64.const 0x1.11cbc530783a2p+410)) +(assert_return (invoke "f64.no_fold_to_hypot" (f64.const 0x1.76777f44ff40bp-536) (f64.const -0x1.c3896e4dc1fbp-766)) (f64.const 0x1.8p-536)) +(assert_return (invoke "f64.no_fold_to_hypot" (f64.const -0x1.889ac72cc6b5dp-521) (f64.const 0x1.8d7084e659f3bp-733)) (f64.const 0x1.889ac72ca843ap-521)) +(assert_return (invoke "f64.no_fold_to_hypot" (f64.const 0x1.5ee588c02cb08p-670) (f64.const -0x1.05ce25788d9ecp-514)) (f64.const 0x1.05ce25788d9dfp-514)) From c5bca44a591b3696849a73377b10fc16270dde9e Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 8 Oct 2015 05:14:10 -0700 Subject: [PATCH 06/18] Test that reciprocal approximations are not used. --- ml-proto/TestingTodo.md | 4 ++-- ml-proto/test/float_exprs.wast | 42 ++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/ml-proto/TestingTodo.md b/ml-proto/TestingTodo.md index a4b1bfb1ea..d0a994ccd9 100644 --- a/ml-proto/TestingTodo.md +++ b/ml-proto/TestingTodo.md @@ -79,8 +79,8 @@ Expression optimizer bait: - ~~test that floating point add/mul aren't reassociated even when tempting~~ - ~~test that floating point mul+add isn't folded to fma even when tempting~~ - ~~test that floating point sqrt(x*x+y*y) isn't folded to hypot even when tempting~~ - - test that 1/x isn't translated into reciprocal-approximate - - test that 1/sqrt(x) isn't approximated either + - ~~test that 1/x isn't translated into reciprocal-approximate~~ + - ~~test that 1/sqrt(x) isn't approximated either~~ - ~~test that fp division by non-power-2 constant gets full precision (isn't a multiply-by-reciprocal deal)?~~ Misc optimizer bait: diff --git a/ml-proto/test/float_exprs.wast b/ml-proto/test/float_exprs.wast index 2477bb9554..b1873f28c9 100644 --- a/ml-proto/test/float_exprs.wast +++ b/ml-proto/test/float_exprs.wast @@ -320,3 +320,45 @@ (assert_return (invoke "f64.no_fold_to_hypot" (f64.const 0x1.76777f44ff40bp-536) (f64.const -0x1.c3896e4dc1fbp-766)) (f64.const 0x1.8p-536)) (assert_return (invoke "f64.no_fold_to_hypot" (f64.const -0x1.889ac72cc6b5dp-521) (f64.const 0x1.8d7084e659f3bp-733)) (f64.const 0x1.889ac72ca843ap-521)) (assert_return (invoke "f64.no_fold_to_hypot" (f64.const 0x1.5ee588c02cb08p-670) (f64.const -0x1.05ce25788d9ecp-514)) (f64.const 0x1.05ce25788d9dfp-514)) + +;; Test that 1.0/x isn't approximated. + +(module + (func $f32.no_approximate_reciprocal (param $x f32) (param $y f32) (result f32) + (f32.div (f32.const 1.0) (get_local $x))) + (export "f32.no_approximate_reciprocal" $f32.no_approximate_reciprocal) +) + +(assert_return (invoke "f32.no_approximate_reciprocal" (f32.const -0x1.2900b6p-10) (f32.const 0x1.d427e8p+56)) (f32.const -0x1.b950d4p+9)) +(assert_return (invoke "f32.no_approximate_reciprocal" (f32.const 0x1.e7212p+127) (f32.const -0x1.55832ap+44)) (f32.const 0x1.0d11f8p-128)) +(assert_return (invoke "f32.no_approximate_reciprocal" (f32.const -0x1.42a466p-93) (f32.const 0x1.7b62d8p+36)) (f32.const -0x1.963ee6p+92)) +(assert_return (invoke "f32.no_approximate_reciprocal" (f32.const 0x1.5d0c32p+76) (f32.const 0x1.d14dccp-74)) (f32.const 0x1.778362p-77)) +(assert_return (invoke "f32.no_approximate_reciprocal" (f32.const -0x1.601de2p-82) (f32.const -0x1.3c7abap+42)) (f32.const -0x1.743d7ep+81)) + +;; Test that 1.0/sqrt(x) isn't approximated. + +(module + (func $f32.no_approximate_reciprocal_sqrt (param $x f32) (param $y f32) (result f32) + (f32.div (f32.const 1.0) (f32.sqrt (get_local $x)))) + (export "f32.no_approximate_reciprocal_sqrt" $f32.no_approximate_reciprocal_sqrt) +) + +(assert_return (invoke "f32.no_approximate_reciprocal_sqrt" (f32.const 0x1.6af12ap-43) (f32.const 0x1.b2113ap-14)) (f32.const 0x1.300ed4p+21)) +(assert_return (invoke "f32.no_approximate_reciprocal_sqrt" (f32.const 0x1.e82fc6p-8) (f32.const -0x1.56a382p-126)) (f32.const 0x1.72c376p+3)) +(assert_return (invoke "f32.no_approximate_reciprocal_sqrt" (f32.const 0x1.b9fa9cp-66) (f32.const -0x1.35394cp+35)) (f32.const 0x1.85a9bap+32)) +(assert_return (invoke "f32.no_approximate_reciprocal_sqrt" (f32.const 0x1.f4f546p-44) (f32.const -0x1.c92ecep+122)) (f32.const 0x1.6e01c2p+21)) +(assert_return (invoke "f32.no_approximate_reciprocal_sqrt" (f32.const 0x1.5da7aap-86) (f32.const -0x1.665652p+119)) (f32.const 0x1.b618cap+42)) + +;; Test that sqrt(1.0/x) isn't approximated. + +(module + (func $f32.no_approximate_sqrt_reciprocal (param $x f32) (param $y f32) (result f32) + (f32.sqrt (f32.div (f32.const 1.0) (get_local $x)))) + (export "f32.no_approximate_sqrt_reciprocal" $f32.no_approximate_sqrt_reciprocal) +) + +(assert_return (invoke "f32.no_approximate_sqrt_reciprocal" (f32.const 0x1.a4c986p+60) (f32.const -0x1.04e29cp-72)) (f32.const 0x1.8f5ac6p-31)) +(assert_return (invoke "f32.no_approximate_sqrt_reciprocal" (f32.const 0x1.50511ep-9) (f32.const -0x1.39228ep-32)) (f32.const 0x1.3bdd46p+4)) +(assert_return (invoke "f32.no_approximate_sqrt_reciprocal" (f32.const 0x1.125ec2p+69) (f32.const -0x1.a7f42ep+92)) (f32.const 0x1.5db572p-35)) +(assert_return (invoke "f32.no_approximate_sqrt_reciprocal" (f32.const 0x1.ba4c5p+13) (f32.const 0x1.947784p-72)) (f32.const 0x1.136f16p-7)) +(assert_return (invoke "f32.no_approximate_sqrt_reciprocal" (f32.const 0x1.4a5be2p+104) (f32.const 0x1.a7b718p-19)) (f32.const 0x1.c2b5bp-53)) From cdbffd97c9c2ac1458568938a99bf4bcb16ec075 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 9 Oct 2015 14:58:20 -0700 Subject: [PATCH 07/18] Replace some inexact decimal literals with exact hexadecimal literals. --- ml-proto/test/conversions.wast | 104 ++++++++++++++++----------------- ml-proto/test/endianness.wast | 8 +-- ml-proto/test/float_misc.wast | 2 +- 3 files changed, 54 insertions(+), 60 deletions(-) diff --git a/ml-proto/test/conversions.wast b/ml-proto/test/conversions.wast index 15ddcab8ed..9ebbd5515e 100644 --- a/ml-proto/test/conversions.wast +++ b/ml-proto/test/conversions.wast @@ -104,8 +104,8 @@ (assert_return (invoke "i32.trunc_s_f32" (f32.const 0.0)) (i32.const 0)) (assert_return (invoke "i32.trunc_s_f32" (f32.const -0.0)) (i32.const 0)) -(assert_return (invoke "i32.trunc_s_f32" (f32.const 1.401298e-45)) (i32.const 0)) -(assert_return (invoke "i32.trunc_s_f32" (f32.const -1.401298e-45)) (i32.const 0)) +(assert_return (invoke "i32.trunc_s_f32" (f32.const 0x1p-149)) (i32.const 0)) +(assert_return (invoke "i32.trunc_s_f32" (f32.const -0x1p-149)) (i32.const 0)) (assert_return (invoke "i32.trunc_s_f32" (f32.const 1.0)) (i32.const 1)) (assert_return (invoke "i32.trunc_s_f32" (f32.const 1.1)) (i32.const 1)) (assert_return (invoke "i32.trunc_s_f32" (f32.const 1.5)) (i32.const 1)) @@ -124,8 +124,8 @@ (assert_return (invoke "i32.trunc_u_f32" (f32.const 0.0)) (i32.const 0)) (assert_return (invoke "i32.trunc_u_f32" (f32.const -0.0)) (i32.const 0)) -(assert_return (invoke "i32.trunc_u_f32" (f32.const 1.401298e-45)) (i32.const 0)) -(assert_return (invoke "i32.trunc_u_f32" (f32.const -1.401298e-45)) (i32.const 0)) +(assert_return (invoke "i32.trunc_u_f32" (f32.const 0x1p-149)) (i32.const 0)) +(assert_return (invoke "i32.trunc_u_f32" (f32.const -0x1p-149)) (i32.const 0)) (assert_return (invoke "i32.trunc_u_f32" (f32.const 1.0)) (i32.const 1)) (assert_return (invoke "i32.trunc_u_f32" (f32.const 1.1)) (i32.const 1)) (assert_return (invoke "i32.trunc_u_f32" (f32.const 1.5)) (i32.const 1)) @@ -142,8 +142,8 @@ (assert_return (invoke "i32.trunc_s_f64" (f64.const 0.0)) (i32.const 0)) (assert_return (invoke "i32.trunc_s_f64" (f64.const -0.0)) (i32.const 0)) -(assert_return (invoke "i32.trunc_s_f64" (f64.const 4.940656e-324)) (i32.const 0)) -(assert_return (invoke "i32.trunc_s_f64" (f64.const -4.940656e-324)) (i32.const 0)) +(assert_return (invoke "i32.trunc_s_f64" (f64.const 0x0.0000000000001p-1022)) (i32.const 0)) +(assert_return (invoke "i32.trunc_s_f64" (f64.const -0x0.0000000000001p-1022)) (i32.const 0)) (assert_return (invoke "i32.trunc_s_f64" (f64.const 1.0)) (i32.const 1)) (assert_return (invoke "i32.trunc_s_f64" (f64.const 1.1)) (i32.const 1)) (assert_return (invoke "i32.trunc_s_f64" (f64.const 1.5)) (i32.const 1)) @@ -162,8 +162,8 @@ (assert_return (invoke "i32.trunc_u_f64" (f64.const 0.0)) (i32.const 0)) (assert_return (invoke "i32.trunc_u_f64" (f64.const -0.0)) (i32.const 0)) -(assert_return (invoke "i32.trunc_u_f64" (f64.const 4.940656e-324)) (i32.const 0)) -(assert_return (invoke "i32.trunc_u_f64" (f64.const -4.940656e-324)) (i32.const 0)) +(assert_return (invoke "i32.trunc_u_f64" (f64.const 0x0.0000000000001p-1022)) (i32.const 0)) +(assert_return (invoke "i32.trunc_u_f64" (f64.const -0x0.0000000000001p-1022)) (i32.const 0)) (assert_return (invoke "i32.trunc_u_f64" (f64.const 1.0)) (i32.const 1)) (assert_return (invoke "i32.trunc_u_f64" (f64.const 1.1)) (i32.const 1)) (assert_return (invoke "i32.trunc_u_f64" (f64.const 1.5)) (i32.const 1)) @@ -184,8 +184,8 @@ (assert_return (invoke "i64.trunc_s_f32" (f32.const 0.0)) (i64.const 0)) (assert_return (invoke "i64.trunc_s_f32" (f32.const -0.0)) (i64.const 0)) -(assert_return (invoke "i64.trunc_s_f32" (f32.const 1.401298e-45)) (i64.const 0)) -(assert_return (invoke "i64.trunc_s_f32" (f32.const -1.401298e-45)) (i64.const 0)) +(assert_return (invoke "i64.trunc_s_f32" (f32.const 0x1p-149)) (i64.const 0)) +(assert_return (invoke "i64.trunc_s_f32" (f32.const -0x1p-149)) (i64.const 0)) (assert_return (invoke "i64.trunc_s_f32" (f32.const 1.0)) (i64.const 1)) (assert_return (invoke "i64.trunc_s_f32" (f32.const 1.1)) (i64.const 1)) (assert_return (invoke "i64.trunc_s_f32" (f32.const 1.5)) (i64.const 1)) @@ -206,8 +206,8 @@ (assert_return (invoke "i64.trunc_u_f32" (f32.const 0.0)) (i64.const 0)) (assert_return (invoke "i64.trunc_u_f32" (f32.const -0.0)) (i64.const 0)) -(assert_return (invoke "i64.trunc_u_f32" (f32.const 1.401298e-45)) (i64.const 0)) -(assert_return (invoke "i64.trunc_u_f32" (f32.const -1.401298e-45)) (i64.const 0)) +(assert_return (invoke "i64.trunc_u_f32" (f32.const 0x1p-149)) (i64.const 0)) +(assert_return (invoke "i64.trunc_u_f32" (f32.const -0x1p-149)) (i64.const 0)) (assert_return (invoke "i64.trunc_u_f32" (f32.const 1.0)) (i64.const 1)) (assert_return (invoke "i64.trunc_u_f32" (f32.const 1.1)) (i64.const 1)) (assert_return (invoke "i64.trunc_u_f32" (f32.const 1.5)) (i64.const 1)) @@ -222,8 +222,8 @@ (assert_return (invoke "i64.trunc_s_f64" (f64.const 0.0)) (i64.const 0)) (assert_return (invoke "i64.trunc_s_f64" (f64.const -0.0)) (i64.const 0)) -(assert_return (invoke "i64.trunc_s_f64" (f64.const 4.940656e-324)) (i64.const 0)) -(assert_return (invoke "i64.trunc_s_f64" (f64.const -4.940656e-324)) (i64.const 0)) +(assert_return (invoke "i64.trunc_s_f64" (f64.const 0x0.0000000000001p-1022)) (i64.const 0)) +(assert_return (invoke "i64.trunc_s_f64" (f64.const -0x0.0000000000001p-1022)) (i64.const 0)) (assert_return (invoke "i64.trunc_s_f64" (f64.const 1.0)) (i64.const 1)) (assert_return (invoke "i64.trunc_s_f64" (f64.const 1.1)) (i64.const 1)) (assert_return (invoke "i64.trunc_s_f64" (f64.const 1.5)) (i64.const 1)) @@ -244,8 +244,8 @@ (assert_return (invoke "i64.trunc_u_f64" (f64.const 0.0)) (i64.const 0)) (assert_return (invoke "i64.trunc_u_f64" (f64.const -0.0)) (i64.const 0)) -(assert_return (invoke "i64.trunc_u_f64" (f64.const 4.940656e-324)) (i64.const 0)) -(assert_return (invoke "i64.trunc_u_f64" (f64.const -4.940656e-324)) (i64.const 0)) +(assert_return (invoke "i64.trunc_u_f64" (f64.const 0x0.0000000000001p-1022)) (i64.const 0)) +(assert_return (invoke "i64.trunc_u_f64" (f64.const -0x0.0000000000001p-1022)) (i64.const 0)) (assert_return (invoke "i64.trunc_u_f64" (f64.const 1.0)) (i64.const 1)) (assert_return (invoke "i64.trunc_u_f64" (f64.const 1.1)) (i64.const 1)) (assert_return (invoke "i64.trunc_u_f64" (f64.const 1.5)) (i64.const 1)) @@ -265,16 +265,16 @@ (assert_return (invoke "f32.convert_s_i32" (i32.const 1)) (f32.const 1.0)) (assert_return (invoke "f32.convert_s_i32" (i32.const -1)) (f32.const -1.0)) (assert_return (invoke "f32.convert_s_i32" (i32.const 0)) (f32.const 0.0)) -(assert_return (invoke "f32.convert_s_i32" (i32.const 2147483647)) (f32.const 2147483647)) +(assert_return (invoke "f32.convert_s_i32" (i32.const 2147483647)) (f32.const 2147483648)) (assert_return (invoke "f32.convert_s_i32" (i32.const -2147483648)) (f32.const -2147483648)) -(assert_return (invoke "f32.convert_s_i32" (i32.const 1234567890)) (f32.const 1234567890)) +(assert_return (invoke "f32.convert_s_i32" (i32.const 1234567890)) (f32.const 0x1.26580cp+30)) (assert_return (invoke "f32.convert_s_i64" (i64.const 1)) (f32.const 1.0)) (assert_return (invoke "f32.convert_s_i64" (i64.const -1)) (f32.const -1.0)) (assert_return (invoke "f32.convert_s_i64" (i64.const 0)) (f32.const 0.0)) (assert_return (invoke "f32.convert_s_i64" (i64.const 9223372036854775807)) (f32.const 9223372036854775807)) (assert_return (invoke "f32.convert_s_i64" (i64.const -9223372036854775808)) (f32.const -9223372036854775808)) -(assert_return (invoke "f32.convert_s_i64" (i64.const 314159265358979)) (f32.const 314159265358979)) ;; PI +(assert_return (invoke "f32.convert_s_i64" (i64.const 314159265358979)) (f32.const 0x1.1db9e8p+48)) ;; PI (assert_return (invoke "f64.convert_s_i32" (i32.const 1)) (f64.const 1.0)) (assert_return (invoke "f64.convert_s_i32" (i32.const -1)) (f64.const -1.0)) @@ -292,9 +292,9 @@ (assert_return (invoke "f32.convert_u_i32" (i32.const 1)) (f32.const 1.0)) (assert_return (invoke "f32.convert_u_i32" (i32.const 0)) (f32.const 0.0)) -(assert_return (invoke "f32.convert_u_i32" (i32.const 2147483647)) (f32.const 2147483647)) +(assert_return (invoke "f32.convert_u_i32" (i32.const 2147483647)) (f32.const 2147483648)) (assert_return (invoke "f32.convert_u_i32" (i32.const -2147483648)) (f32.const 2147483648)) -(assert_return (invoke "f32.convert_u_i32" (i32.const 0x12345678)) (f32.const 305419896)) ;; 0x12345678 +(assert_return (invoke "f32.convert_u_i32" (i32.const 0x12345678)) (f32.const 0x1.234568p+28)) (assert_return (invoke "f32.convert_u_i32" (i32.const 0xffffffff)) (f32.const 4294967296.0)) (assert_return (invoke "f32.convert_u_i64" (i64.const 1)) (f32.const 1.0)) @@ -317,74 +317,68 @@ (assert_return (invoke "f64.promote_f32" (f32.const 0.0)) (f64.const 0.0)) (assert_return (invoke "f64.promote_f32" (f32.const -0.0)) (f64.const -0.0)) -(assert_return (invoke "f64.promote_f32" (f32.const 1.401298e-45)) (f64.const 1.401298464324817e-45)) -(assert_return (invoke "f64.promote_f32" (f32.const -1.401298e-45)) (f64.const -1.401298464324817e-45)) +(assert_return (invoke "f64.promote_f32" (f32.const 0x1p-149)) (f64.const 0x1p-149)) +(assert_return (invoke "f64.promote_f32" (f32.const -0x1p-149)) (f64.const -0x1p-149)) (assert_return (invoke "f64.promote_f32" (f32.const 1.0)) (f64.const 1.0)) (assert_return (invoke "f64.promote_f32" (f32.const -1.0)) (f64.const -1.0)) -(assert_return (invoke "f64.promote_f32" (f32.const 1.4012985e-45)) (f64.const 1.401298464324817e-45)) -(assert_return (invoke "f64.promote_f32" (f32.const -1.4012985e-45)) (f64.const -1.401298464324817e-45)) -(assert_return (invoke "f64.promote_f32" (f32.const -3.4028235e+38)) (f64.const -3.4028234663852886e+38)) -(assert_return (invoke "f64.promote_f32" (f32.const 3.4028235e+38)) (f64.const 3.4028234663852886e+38)) +(assert_return (invoke "f64.promote_f32" (f32.const -0x1.fffffep+127)) (f64.const -0x1.fffffep+127)) +(assert_return (invoke "f64.promote_f32" (f32.const 0x1.fffffep+127)) (f64.const 0x1.fffffep+127)) ;; Generated randomly by picking a random int and reinterpret it to float. -(assert_return (invoke "f64.promote_f32" (f32.const 1.5046328e-36)) (f64.const 1.504632769052528e-36)) +(assert_return (invoke "f64.promote_f32" (f32.const 0x1p-119)) (f64.const 0x1p-119)) ;; Generated randomly by picking a random float. -(assert_return (invoke "f64.promote_f32" (f32.const 6.6382537e+37)) (f64.const 6.6382536710104395e+37)) +(assert_return (invoke "f64.promote_f32" (f32.const 0x1.8f867ep+125)) (f64.const 6.6382536710104395e+37)) (assert_return (invoke "f64.promote_f32" (f32.const infinity)) (f64.const infinity)) (assert_return (invoke "f64.promote_f32" (f32.const -infinity)) (f64.const -infinity)) (assert_return_nan (invoke "f64.promote_f32" (f32.const nan))) (assert_return (invoke "f32.demote_f64" (f64.const 0.0)) (f32.const 0.0)) (assert_return (invoke "f32.demote_f64" (f64.const -0.0)) (f32.const -0.0)) -(assert_return (invoke "f32.demote_f64" (f64.const 4.940656e-324)) (f32.const 0.0)) -(assert_return (invoke "f32.demote_f64" (f64.const -4.940656e-324)) (f32.const -0.0)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x0.0000000000001p-1022)) (f32.const 0.0)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x0.0000000000001p-1022)) (f32.const -0.0)) (assert_return (invoke "f32.demote_f64" (f64.const 1.0)) (f32.const 1.0)) (assert_return (invoke "f32.demote_f64" (f64.const -1.0)) (f32.const -1.0)) -(assert_return (invoke "f32.demote_f64" (f64.const -1.401298464324817e-45)) (f32.const -1.4012985e-45)) -(assert_return (invoke "f32.demote_f64" (f64.const 1.401298464324817e-45)) (f32.const 1.4012985e-45)) -(assert_return (invoke "f32.demote_f64" (f64.const 3.402823466385289e+38)) (f32.const 3.4028235e+38)) -(assert_return (invoke "f32.demote_f64" (f64.const -3.402823466385289e+38)) (f32.const -3.4028235e+38)) -(assert_return (invoke "f32.demote_f64" (f64.const 1.504632769052528e-36)) (f32.const 1.5046328e-36)) -(assert_return (invoke "f32.demote_f64" (f64.const 6.6382536710104395e+37)) (f32.const 6.6382537e+37)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x1p-149)) (f32.const -0x1p-149)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1p-149)) (f32.const 0x1p-149)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1p-119)) (f32.const 0x1p-119)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.8f867ep+125)) (f32.const 0x1.8f867ep+125)) (assert_return (invoke "f32.demote_f64" (f64.const infinity)) (f32.const infinity)) (assert_return (invoke "f32.demote_f64" (f64.const -infinity)) (f32.const -infinity)) (assert_return_nan (invoke "f32.demote_f64" (f64.const nan))) (assert_return (invoke "f32.reinterpret_i32" (i32.const 0)) (f32.const 0.0)) (assert_return (invoke "f32.reinterpret_i32" (i32.const 0x80000000)) (f32.const -0.0)) -(assert_return (invoke "f32.reinterpret_i32" (i32.const 1)) (f32.const 1.4012984e-45)) -(assert_return (invoke "f32.reinterpret_i32" (i32.const 123456789)) (f32.const 1.6535997e-34)) -(assert_return (invoke "f32.reinterpret_i32" (i32.const -2147483647)) (f32.const -1.4012984e-45)) +(assert_return (invoke "f32.reinterpret_i32" (i32.const 1)) (f32.const 0x1p-149)) +(assert_return (invoke "f32.reinterpret_i32" (i32.const 123456789)) (f32.const 0x1.b79a2ap-113)) +(assert_return (invoke "f32.reinterpret_i32" (i32.const -2147483647)) (f32.const -0x1p-149)) (assert_return (invoke "f64.reinterpret_i64" (i64.const 0)) (f64.const 0.0)) -(assert_return (invoke "f64.reinterpret_i64" (i64.const 1)) (f64.const 4.94066e-324)) +(assert_return (invoke "f64.reinterpret_i64" (i64.const 1)) (f64.const 0x0.0000000000001p-1022)) (assert_return (invoke "f64.reinterpret_i64" (i64.const 0x8000000000000000)) (f64.const -0.0)) -(assert_return (invoke "f64.reinterpret_i64" (i64.const 1234567890)) (f64.const 6.099575819077150e-315)) -(assert_return (invoke "f64.reinterpret_i64" (i64.const -9223372036854775807)) (f64.const -4.940656458412465e-324)) +(assert_return (invoke "f64.reinterpret_i64" (i64.const 1234567890)) (f64.const 0x0.00000499602d2p-1022)) +(assert_return (invoke "f64.reinterpret_i64" (i64.const -9223372036854775807)) (f64.const -0x0.0000000000001p-1022)) (assert_return (invoke "i32.reinterpret_f32" (f32.const 0.0)) (i32.const 0)) (assert_return (invoke "i32.reinterpret_f32" (f32.const -0.0)) (i32.const 0x80000000)) -(assert_return (invoke "i32.reinterpret_f32" (f32.const 1.401298e-45)) (i32.const 1)) -(assert_return (invoke "i32.reinterpret_f32" (f32.const -1.401298e-45)) (i32.const 0x80000001)) +(assert_return (invoke "i32.reinterpret_f32" (f32.const 0x1p-149)) (i32.const 1)) +(assert_return (invoke "i32.reinterpret_f32" (f32.const -0x1p-149)) (i32.const 0x80000001)) (assert_return (invoke "i32.reinterpret_f32" (f32.const 1.0)) (i32.const 1065353216)) (assert_return (invoke "i32.reinterpret_f32" (f32.const 3.1415926)) (i32.const 1078530010)) -(assert_return (invoke "i32.reinterpret_f32" (f32.const 3.4028235e+38)) (i32.const 2139095039)) -(assert_return (invoke "i32.reinterpret_f32" (f32.const -3.4028235e+38)) (i32.const -8388609)) -(assert_return (invoke "i32.reinterpret_f32" (f32.const 1.4012984e-45)) (i32.const 1)) -(assert_return (invoke "i32.reinterpret_f32" (f32.const -1.4012984e-45)) (i32.const -2147483647)) +(assert_return (invoke "i32.reinterpret_f32" (f32.const 0x1.fffffep+127)) (i32.const 2139095039)) +(assert_return (invoke "i32.reinterpret_f32" (f32.const -0x1.fffffep+127)) (i32.const -8388609)) (assert_return (invoke "i32.reinterpret_f32" (f32.const infinity)) (i32.const 0x7f800000)) (assert_return (invoke "i32.reinterpret_f32" (f32.const -infinity)) (i32.const 0xff800000)) (assert_return (invoke "i32.reinterpret_f32" (f32.const nan)) (i32.const 0x7fc00000)) (assert_return (invoke "i64.reinterpret_f64" (f64.const 0.0)) (i64.const 0)) (assert_return (invoke "i64.reinterpret_f64" (f64.const -0.0)) (i64.const 0x8000000000000000)) -(assert_return (invoke "i64.reinterpret_f64" (f64.const 4.940656e-324)) (i64.const 1)) -(assert_return (invoke "i64.reinterpret_f64" (f64.const -4.940656e-324)) (i64.const 0x8000000000000001)) +(assert_return (invoke "i64.reinterpret_f64" (f64.const 0x0.0000000000001p-1022)) (i64.const 1)) +(assert_return (invoke "i64.reinterpret_f64" (f64.const -0x0.0000000000001p-1022)) (i64.const 0x8000000000000001)) (assert_return (invoke "i64.reinterpret_f64" (f64.const 1.0)) (i64.const 4607182418800017408)) (assert_return (invoke "i64.reinterpret_f64" (f64.const 3.14159265358979)) (i64.const 4614256656552045841)) -(assert_return (invoke "i64.reinterpret_f64" (f64.const 1.7976931348623157e+308)) (i64.const 9218868437227405311)) -(assert_return (invoke "i64.reinterpret_f64" (f64.const -1.7976931348623157e+308)) (i64.const -4503599627370497)) -(assert_return (invoke "i64.reinterpret_f64" (f64.const 4.9406565e-324)) (i64.const 1)) -(assert_return (invoke "i64.reinterpret_f64" (f64.const -4.9406565e-324)) (i64.const -9223372036854775807)) +(assert_return (invoke "i64.reinterpret_f64" (f64.const 0x1.fffffffffffffp+1023)) (i64.const 9218868437227405311)) +(assert_return (invoke "i64.reinterpret_f64" (f64.const -0x1.fffffffffffffp+1023)) (i64.const -4503599627370497)) (assert_return (invoke "i64.reinterpret_f64" (f64.const infinity)) (i64.const 0x7ff0000000000000)) (assert_return (invoke "i64.reinterpret_f64" (f64.const -infinity)) (i64.const 0xfff0000000000000)) (assert_return (invoke "i64.reinterpret_f64" (f64.const nan)) (i64.const 0x7ff8000000000000)) diff --git a/ml-proto/test/endianness.wast b/ml-proto/test/endianness.wast index 954a55fbd8..1231de58ef 100644 --- a/ml-proto/test/endianness.wast +++ b/ml-proto/test/endianness.wast @@ -197,12 +197,12 @@ (assert_return (invoke "f32_load" (f32.const -1)) (f32.const -1)) (assert_return (invoke "f32_load" (f32.const 1234e-5)) (f32.const 1234e-5)) (assert_return (invoke "f32_load" (f32.const 4242.4242)) (f32.const 4242.4242)) -(assert_return (invoke "f32_load" (f32.const 3.4028e+38)) (f32.const 3.4028e+38)) +(assert_return (invoke "f32_load" (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127)) (assert_return (invoke "f64_load" (f64.const -1)) (f64.const -1)) (assert_return (invoke "f64_load" (f64.const 123456789e-5)) (f64.const 123456789e-5)) (assert_return (invoke "f64_load" (f64.const 424242.424242)) (f64.const 424242.424242)) -(assert_return (invoke "f64_load" (f64.const 1.7976e+308)) (f64.const 1.7976e+308)) +(assert_return (invoke "f64_load" (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023)) (assert_return (invoke "i32_store16" (i32.const -1)) (i32.const 0xFFFF)) @@ -233,9 +233,9 @@ (assert_return (invoke "f32_store" (f32.const -1)) (f32.const -1)) (assert_return (invoke "f32_store" (f32.const 1234e-5)) (f32.const 1234e-5)) (assert_return (invoke "f32_store" (f32.const 4242.4242)) (f32.const 4242.4242)) -(assert_return (invoke "f32_store" (f32.const 3.4028e+38)) (f32.const 3.4028e+38)) +(assert_return (invoke "f32_store" (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127)) (assert_return (invoke "f64_store" (f64.const -1)) (f64.const -1)) (assert_return (invoke "f64_store" (f64.const 123456789e-5)) (f64.const 123456789e-5)) (assert_return (invoke "f64_store" (f64.const 424242.424242)) (f64.const 424242.424242)) -(assert_return (invoke "f64_store" (f64.const 1.7976e+308)) (f64.const 1.7976e+308)) \ No newline at end of file +(assert_return (invoke "f64_store" (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023)) diff --git a/ml-proto/test/float_misc.wast b/ml-proto/test/float_misc.wast index 0d06e1c22c..0a07bc3478 100644 --- a/ml-proto/test/float_misc.wast +++ b/ml-proto/test/float_misc.wast @@ -148,7 +148,7 @@ (assert_return (invoke "f64.mul" (f64.const -0x1.c6a56169e9cep-772) (f64.const 0x1.517d55a474122p-255)) (f64.const -0x0.12baf260afb77p-1022)) (assert_return (invoke "f64.mul" (f64.const -0x1.08951b0b41705p-516) (f64.const -0x1.102dc27168d09p-507)) (f64.const 0x0.8ca6dbf3f592bp-1022)) -(assert_return (invoke "f32.div" (f32.const 1.123456789) (f32.const 100)) (f32.const 0.011234568432)) +(assert_return (invoke "f32.div" (f32.const 1.123456789) (f32.const 100)) (f32.const 0x1.702264p-7)) (assert_return (invoke "f32.div" (f32.const 8391667.0) (f32.const 12582905.0)) (f32.const 0x1.55754p-1)) (assert_return (invoke "f32.div" (f32.const 65536.0) (f32.const 0x1p-37)) (f32.const 0x1p+53)) (assert_return (invoke "f32.div" (f32.const 0x1.dcbf6ap+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1.dcbf68p-128)) From a766cd5ff2ca40a9876537ddb167c1c1938ba491 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 9 Oct 2015 15:22:44 -0700 Subject: [PATCH 08/18] Test that f32.demote/f64 rounds to nearest with ties to even. --- ml-proto/test/conversions.wast | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ml-proto/test/conversions.wast b/ml-proto/test/conversions.wast index 9ebbd5515e..57538c8b3f 100644 --- a/ml-proto/test/conversions.wast +++ b/ml-proto/test/conversions.wast @@ -345,6 +345,15 @@ (assert_return (invoke "f32.demote_f64" (f64.const 0x1.8f867ep+125)) (f32.const 0x1.8f867ep+125)) (assert_return (invoke "f32.demote_f64" (f64.const infinity)) (f32.const infinity)) (assert_return (invoke "f32.demote_f64" (f64.const -infinity)) (f32.const -infinity)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000000000001p+0)) (f32.const 1.0)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffffffffffp-1)) (f32.const 1.0)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000030000000p+0)) (f32.const 0x1.000004p+0)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000050000000p+0)) (f32.const 0x1.000004p+0)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.4eae4f7024c7p+108)) (f32.const 0x1.4eae5p+108)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.a12e71e358685p-113)) (f32.const 0x1.a12e72p-113)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.cb98354d521ffp-127)) (f32.const 0x1.cb9834p-127)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x1.6972b30cfb562p+1)) (f32.const -0x1.6972b4p+1)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x1.bedbe4819d4c4p+112)) (f32.const -0x1.bedbe4p+112)) (assert_return_nan (invoke "f32.demote_f64" (f64.const nan))) (assert_return (invoke "f32.reinterpret_i32" (i32.const 0)) (f32.const 0.0)) From 425f86baddea86ce0e6f15cc28ef4f3f07f2f7ca Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 9 Oct 2015 16:48:48 -0700 Subject: [PATCH 09/18] Add import tests for printing 64-bit values too. --- ml-proto/test/expected-output/imports.wast.log | 3 +++ ml-proto/test/imports.wast | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/ml-proto/test/expected-output/imports.wast.log b/ml-proto/test/expected-output/imports.wast.log index a7eaf5d94d..e00409c10c 100644 --- a/ml-proto/test/expected-output/imports.wast.log +++ b/ml-proto/test/expected-output/imports.wast.log @@ -1,3 +1,6 @@ 13 : i32 14 : i32 42. : f32 +24 : i64 +25 : i64 +53. : f64 diff --git a/ml-proto/test/imports.wast b/ml-proto/test/imports.wast index e086314e4a..6e11899461 100644 --- a/ml-proto/test/imports.wast +++ b/ml-proto/test/imports.wast @@ -1,14 +1,25 @@ (module (import $print_i32 "stdio" "print" (param i32)) + (import $print_i64 "stdio" "print" (param i64)) (import $print_i32_f32 "stdio" "print" (param i32 f32)) - (func $print (param $i i32) + (import $print_i64_f64 "stdio" "print" (param i64 f64)) + (func $print32 (param $i i32) (call_import $print_i32 (get_local $i)) (call_import $print_i32_f32 (i32.add (get_local $i) (i32.const 1)) (f32.const 42) ) ) - (export "print" $print) + (func $print64 (param $i i64) + (call_import $print_i64 (get_local $i)) + (call_import $print_i64_f64 + (i64.add (get_local $i) (i64.const 1)) + (f64.const 53) + ) + ) + (export "print32" $print32) + (export "print64" $print64) ) -(invoke "print" (i32.const 13)) +(invoke "print32" (i32.const 13)) +(invoke "print64" (i64.const 24)) From f2ef2ef3d9c9b6bb23bd1e0dff35615fc0f32d75 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 9 Oct 2015 16:58:29 -0700 Subject: [PATCH 10/18] Test that bytes in between memory segment initializers remain zero. --- ml-proto/test/memory.wast | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/ml-proto/test/memory.wast b/ml-proto/test/memory.wast index a5153317ef..ee1c594943 100644 --- a/ml-proto/test/memory.wast +++ b/ml-proto/test/memory.wast @@ -68,12 +68,24 @@ (func $data (result i32) (i32.and (i32.and - (i32.eq (i32.load8_u (i32.const 0)) (i32.const 65)) - (i32.eq (i32.load8_u (i32.const 3)) (i32.const 167)) + (i32.and + (i32.eq (i32.load8_u (i32.const 0)) (i32.const 65)) + (i32.eq (i32.load8_u (i32.const 3)) (i32.const 167)) + ) + (i32.and + (i32.eq (i32.load8_u (i32.const 6)) (i32.const 0)) + (i32.eq (i32.load8_u (i32.const 19)) (i32.const 0)) + ) ) (i32.and - (i32.eq (i32.load8_u (i32.const 20)) (i32.const 87)) - (i32.eq (i32.load8_u (i32.const 23)) (i32.const 77)) + (i32.and + (i32.eq (i32.load8_u (i32.const 20)) (i32.const 87)) + (i32.eq (i32.load8_u (i32.const 23)) (i32.const 77)) + ) + (i32.and + (i32.eq (i32.load8_u (i32.const 24)) (i32.const 0)) + (i32.eq (i32.load8_u (i32.const 1023)) (i32.const 0)) + ) ) ) ) From 7b243639cf1488034e86bd26d7d7b14e0d02214e Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 9 Oct 2015 17:31:36 -0700 Subject: [PATCH 11/18] Rename hexnum.wast to int_literals.wast, reformat, and add a few more interesting cases. --- ml-proto/test/hexnum.wast | 39 ----------------------- ml-proto/test/int_literals.wast | 55 +++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 39 deletions(-) delete mode 100644 ml-proto/test/hexnum.wast create mode 100644 ml-proto/test/int_literals.wast diff --git a/ml-proto/test/hexnum.wast b/ml-proto/test/hexnum.wast deleted file mode 100644 index cb1cd49e06..0000000000 --- a/ml-proto/test/hexnum.wast +++ /dev/null @@ -1,39 +0,0 @@ -(module - (func $test32 (result i32) - (return (i32.const 0x0bAdD00D)) - ) - - (func $max32 (result i32) - (return (i32.const 0xffffffff)) - ) - - (func $neg32 (result i32) - (return (i32.const -0x7fffffff)) - ) - - (func $test64 (result i64) - (return (i64.const 0x0CABBA6E0ba66a6e)) - ) - - (func $max64 (result i64) - (return (i64.const 0xffffffffffffffff)) - ) - - (func $neg64 (result i64) - (return (i64.const -0x7fffffffffffffff)) - ) - - (export "test32" $test32) - (export "max32" $max32) - (export "neg32" $neg32) - (export "test64" $test64) - (export "max64" $max64) - (export "neg64" $neg64) -) - -(assert_return (invoke "test32") (i32.const 195940365)) -(assert_return (invoke "max32") (i32.const -1)) -(assert_return (invoke "neg32") (i32.const -2147483647)) -(assert_return (invoke "test64") (i64.const 913028331277281902)) -(assert_return (invoke "max64") (i64.const -1)) -(assert_return (invoke "neg64") (i64.const -9223372036854775807)) diff --git a/ml-proto/test/int_literals.wast b/ml-proto/test/int_literals.wast new file mode 100644 index 0000000000..e8d1c09944 --- /dev/null +++ b/ml-proto/test/int_literals.wast @@ -0,0 +1,55 @@ +(module + (func $i32.test (result i32) (return (i32.const 0x0bAdD00D))) + (func $i32.umax (result i32) (return (i32.const 0xffffffff))) + (func $i32.smax (result i32) (return (i32.const 0x7fffffff))) + (func $i32.neg_smax (result i32) (return (i32.const -0x7fffffff))) + (func $i32.smin (result i32) (return (i32.const -0x80000000))) + (func $i32.alt_smin (result i32) (return (i32.const 0x80000000))) + (func $i32.inc_smin (result i32) (return (i32.add (i32.const -0x80000000) (i32.const 1)))) + (func $i32.neg_zero (result i32) (return (i32.const -0x0))) + + (func $i64.test (result i64) (return (i64.const 0x0CABBA6E0ba66a6e))) + (func $i64.umax (result i64) (return (i64.const 0xffffffffffffffff))) + (func $i64.smax (result i64) (return (i64.const 0x7fffffffffffffff))) + (func $i64.neg_smax (result i64) (return (i64.const -0x7fffffffffffffff))) + (func $i64.smin (result i64) (return (i64.const -0x8000000000000000))) + (func $i64.alt_smin (result i64) (return (i64.const 0x8000000000000000))) + (func $i64.inc_smin (result i64) (return (i64.add (i64.const -0x8000000000000000) (i64.const 1)))) + (func $i64.neg_zero (result i64) (return (i64.const -0x0))) + + (export "i32.test" $i32.test) + (export "i32.umax" $i32.umax) + (export "i32.smax" $i32.smax) + (export "i32.neg_smax" $i32.neg_smax) + (export "i32.smin" $i32.smin) + (export "i32.alt_smin" $i32.alt_smin) + (export "i32.inc_smin" $i32.inc_smin) + (export "i32.neg_zero" $i32.neg_zero) + + (export "i64.test" $i64.test) + (export "i64.umax" $i64.umax) + (export "i64.smax" $i64.smax) + (export "i64.neg_smax" $i64.neg_smax) + (export "i64.smin" $i64.smin) + (export "i64.alt_smin" $i64.alt_smin) + (export "i64.inc_smin" $i64.inc_smin) + (export "i64.neg_zero" $i64.neg_zero) +) + +(assert_return (invoke "i32.test") (i32.const 195940365)) +(assert_return (invoke "i32.umax") (i32.const -1)) +(assert_return (invoke "i32.smax") (i32.const 2147483647)) +(assert_return (invoke "i32.neg_smax") (i32.const -2147483647)) +(assert_return (invoke "i32.smin") (i32.const -2147483648)) +(assert_return (invoke "i32.alt_smin") (i32.const -2147483648)) +(assert_return (invoke "i32.inc_smin") (i32.const -2147483647)) +(assert_return (invoke "i32.neg_zero") (i32.const 0)) + +(assert_return (invoke "i64.test") (i64.const 913028331277281902)) +(assert_return (invoke "i64.umax") (i64.const -1)) +(assert_return (invoke "i64.smax") (i64.const 9223372036854775807)) +(assert_return (invoke "i64.neg_smax") (i64.const -9223372036854775807)) +(assert_return (invoke "i64.smin") (i64.const -9223372036854775808)) +(assert_return (invoke "i64.alt_smin") (i64.const -9223372036854775808)) +(assert_return (invoke "i64.inc_smin") (i64.const -9223372036854775807)) +(assert_return (invoke "i64.neg_zero") (i64.const 0)) From 5ba137fdf4edab89cf2f6de95c0a179594ffd95f Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 9 Oct 2015 18:14:51 -0700 Subject: [PATCH 12/18] Add result-value tests to tests for stores. --- ml-proto/test/float_memory.wast | 20 ++++++++++---------- ml-proto/test/memory_trap.wast | 4 ++-- ml-proto/test/resizing.wast | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/ml-proto/test/float_memory.wast b/ml-proto/test/float_memory.wast index 01ec5f499b..4c881725fc 100644 --- a/ml-proto/test/float_memory.wast +++ b/ml-proto/test/float_memory.wast @@ -4,13 +4,13 @@ (module (memory 4 4) - (func $store_i32 (param $x i32) + (func $store_i32 (param $x i32) (result i32) (i32.store (i32.const 0) (get_local $x))) (func $load_i32 (result i32) (i32.load (i32.const 0))) - (func $store_f32 (param $x f32) + (func $store_f32 (param $x f32) (result f32) (f32.store (i32.const 0) (get_local $x))) (func $load_f32 (result f32) @@ -22,14 +22,14 @@ (export "load_f32" $load_f32) ) -(invoke "store_i32" (i32.const 0x7f800001)) +(assert_return (invoke "store_i32" (i32.const 0x7f800001)) (i32.const 0x7f800001)) (assert_return (invoke "load_f32") (f32.const nan(0x000001))) -(invoke "store_i32" (i32.const 0x80000000)) +(assert_return (invoke "store_i32" (i32.const 0x80000000)) (i32.const 0x80000000)) (assert_return (invoke "load_f32") (f32.const -0.0)) -(invoke "store_f32" (f32.const nan(0x000001))) +(assert_return (invoke "store_f32" (f32.const nan(0x000001))) (f32.const nan(0x000001))) (assert_return (invoke "load_i32") (i32.const 0x7f800001)) -(invoke "store_f32" (f32.const -0.0)) +(assert_return (invoke "store_f32" (f32.const -0.0)) (f32.const -0.0)) (assert_return (invoke "load_i32") (i32.const 0x80000000)) (module @@ -53,12 +53,12 @@ (export "load_f64" $load_f64) ) -(invoke "store_i64" (i64.const 0x7ff0000000000001)) +(assert_return (invoke "store_i64" (i64.const 0x7ff0000000000001)) (i64.const 0x7ff0000000000001)) (assert_return (invoke "load_f64") (f64.const nan(0x0000000000001))) -(invoke "store_i64" (i64.const 0x8000000000000000)) +(assert_return (invoke "store_i64" (i64.const 0x8000000000000000)) (i64.const 0x8000000000000000)) (assert_return (invoke "load_f64") (f64.const -0.0)) -(invoke "store_f64" (f64.const nan(0x0000000000001))) +(assert_return (invoke "store_f64" (f64.const nan(0x0000000000001))) (f64.const nan(0x0000000000001))) (assert_return (invoke "load_i64") (i64.const 0x7ff0000000000001)) -(invoke "store_f64" (f64.const -0.0)) +(assert_return (invoke "store_f64" (f64.const -0.0)) (f64.const -0.0)) (assert_return (invoke "load_i64") (i64.const 0x8000000000000000)) diff --git a/ml-proto/test/memory_trap.wast b/ml-proto/test/memory_trap.wast index c5b297348c..64e6848178 100644 --- a/ml-proto/test/memory_trap.wast +++ b/ml-proto/test/memory_trap.wast @@ -2,13 +2,13 @@ (memory 100) (export "store" $store) - (func $store (param $i i32) (param $v i32) (i32.store (i32.add (memory_size) (get_local $i)) (get_local $v))) + (func $store (param $i i32) (param $v i32) (result i32) (i32.store (i32.add (memory_size) (get_local $i)) (get_local $v))) (export "load" $load) (func $load (param $i i32) (result i32) (i32.load (i32.add (memory_size) (get_local $i)))) ) -(invoke "store" (i32.const -4) (i32.const 42)) +(assert_return (invoke "store" (i32.const -4) (i32.const 42)) (i32.const 42)) (assert_return (invoke "load" (i32.const -4)) (i32.const 42)) (assert_trap (invoke "store" (i32.const -3) (i32.const 13)) "runtime: out of bounds memory access") (assert_trap (invoke "load" (i32.const -3)) "runtime: out of bounds memory access") diff --git a/ml-proto/test/resizing.wast b/ml-proto/test/resizing.wast index f7351d033c..eff4887f9f 100644 --- a/ml-proto/test/resizing.wast +++ b/ml-proto/test/resizing.wast @@ -5,7 +5,7 @@ (func $load (param $i i32) (result i32) (i32.load (get_local $i))) (export "store" $store) - (func $store (param $i i32) (param $v i32) (i32.store (get_local $i) (get_local $v))) + (func $store (param $i i32) (param $v i32) (result i32) (i32.store (get_local $i) (get_local $v))) (export "resize" $resize) (func $resize (param $sz i32) (resize_memory (get_local $sz))) @@ -15,7 +15,7 @@ ) (assert_return (invoke "size") (i32.const 4096)) -(invoke "store" (i32.const 0) (i32.const 42)) +(assert_return (invoke "store" (i32.const 0) (i32.const 42)) (i32.const 42)) (assert_return (invoke "load" (i32.const 0)) (i32.const 42)) (assert_trap (invoke "store" (i32.const 4096) (i32.const 42)) "runtime: out of bounds memory access") (assert_trap (invoke "load" (i32.const 4096)) "runtime: out of bounds memory access") @@ -23,7 +23,7 @@ (assert_return (invoke "size") (i32.const 8192)) (assert_return (invoke "load" (i32.const 0)) (i32.const 42)) (assert_return (invoke "load" (i32.const 4096)) (i32.const 0)) -(invoke "store" (i32.const 4096) (i32.const 43)) +(assert_return (invoke "store" (i32.const 4096) (i32.const 43)) (i32.const 43)) (assert_return (invoke "load" (i32.const 4096)) (i32.const 43)) (invoke "resize" (i32.const 4096)) (assert_return (invoke "size") (i32.const 4096)) From 910a040a68695be9abade7510afe47932761ab08 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 9 Oct 2015 18:23:12 -0700 Subject: [PATCH 13/18] Test a few more interesting floating point test cases mentioned by Muller. --- ml-proto/test/float_misc.wast | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ml-proto/test/float_misc.wast b/ml-proto/test/float_misc.wast index 0a07bc3478..6d05970677 100644 --- a/ml-proto/test/float_misc.wast +++ b/ml-proto/test/float_misc.wast @@ -63,6 +63,11 @@ (assert_return (invoke "f64.add" (f64.const 1.1234567890) (f64.const 1.2345e-10)) (f64.const 0x1.1f9add37c11f7p+0)) +;; Test for a case of double rounding, example from: +;; http://perso.ens-lyon.fr/jean-michel.muller/Handbook.html +;; section 3.3.1: A typical problem: "double rounding" +(assert_return (invoke "f64.add" (f64.const 0x1p+63) (f64.const 1024.25)) (f64.const 0x1.0000000000001p+63)) + ;; Computations that round differently in round-to-odd mode. (assert_return (invoke "f64.add" (f64.const 0x1p52) (f64.const 0x1p-1)) (f64.const 0x1p52)) (assert_return (invoke "f64.add" (f64.const 0x1.0000000000001p+52) (f64.const 0x1p-1)) (f64.const 0x1.0000000000002p+52)) @@ -119,6 +124,14 @@ ;; Test that what some systems call signalling NaN behaves as a quiet NaN. (assert_return_nan (invoke "f64.add" (f64.const nan(0x4000000000000)) (f64.const 1.0))) +;; Test for a historic spreadsheet bug. +;; https://blogs.office.com/2007/09/25/calculation-issue-update/ +(assert_return (invoke "f32.sub" (f32.const 65536.0) (f32.const 0x1p-37)) (f32.const 65536.0)) + +;; Test for a historic spreadsheet bug. +;; https://blogs.office.com/2007/09/25/calculation-issue-update/ +(assert_return (invoke "f64.sub" (f64.const 65536.0) (f64.const 0x1p-37)) (f64.const 0x1.fffffffffffffp+15)) + ;; Computations that round differently on x87. (assert_return (invoke "f64.sub" (f64.const 0x1.c21151a709b6cp-78) (f64.const 0x1.0a12fff8910f6p-115)) (f64.const 0x1.c21151a701663p-78)) (assert_return (invoke "f64.sub" (f64.const 0x1.c57912aae2f64p-982) (f64.const 0x1.dbfbd4800b7cfp-1010)) (f64.const 0x1.c579128d2338fp-982)) @@ -130,10 +143,20 @@ (assert_return (invoke "f32.mul" (f32.const 1e20) (f32.const 1e20)) (f32.const infinity)) (assert_return (invoke "f32.mul" (f32.const 1e25) (f32.const 1e25)) (f32.const infinity)) +;; Test for a case of double rounding, example from: +;; http://perso.ens-lyon.fr/jean-michel.muller/Handbook.html +;; section 3.3.1: A typical problem: "double rounding" +(assert_return (invoke "f32.mul" (f32.const 1848874880.0) (f32.const 19954563072.0)) (f32.const 0x1.000002p+65)) + (assert_return (invoke "f64.mul" (f64.const 1e15) (f64.const 1e15)) (f64.const 0x1.93e5939a08ceap+99)) (assert_return (invoke "f64.mul" (f64.const 1e20) (f64.const 1e20)) (f64.const 0x1.d6329f1c35ca5p+132)) (assert_return (invoke "f64.mul" (f64.const 1e25) (f64.const 1e25)) (f64.const 0x1.11b0ec57e649bp+166)) +;; Test for a case of double rounding, example from: +;; http://perso.ens-lyon.fr/jean-michel.muller/Handbook.html +;; section 3.3.1: A typical problem: "double rounding" +(assert_return (invoke "f64.mul" (f64.const 1848874847.0) (f64.const 19954562207.0)) (f64.const 3.6893488147419111424e+19)) + ;; Computations that round differently on x87. (assert_return (invoke "f64.mul" (f64.const 0x1.f99fb602c89b7p-341) (f64.const 0x1.6caab46a31a2ep-575)) (f64.const 0x1.68201f986e9d7p-915)) (assert_return (invoke "f64.mul" (f64.const -0x1.86999c5eee379p-9) (f64.const 0x1.6e3b9e0d53e0dp+723)) (f64.const -0x1.17654a0ef35f5p+715)) From c74ba3212f268ab31196e6189f0c96fc689e7220 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 9 Oct 2015 19:24:57 -0700 Subject: [PATCH 14/18] Test for a bug that once caused Excel to behave strangely. --- ml-proto/test/float_misc.wast | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ml-proto/test/float_misc.wast b/ml-proto/test/float_misc.wast index 6d05970677..7da38945da 100644 --- a/ml-proto/test/float_misc.wast +++ b/ml-proto/test/float_misc.wast @@ -148,6 +148,10 @@ ;; section 3.3.1: A typical problem: "double rounding" (assert_return (invoke "f32.mul" (f32.const 1848874880.0) (f32.const 19954563072.0)) (f32.const 0x1.000002p+65)) +;; Test for a historic spreadsheet bug. +;; http://www.joelonsoftware.com/items/2007/09/26b.html +(assert_return (invoke "f32.mul" (f32.const 77.1) (f32.const 850)) (f32.const 65535)) + (assert_return (invoke "f64.mul" (f64.const 1e15) (f64.const 1e15)) (f64.const 0x1.93e5939a08ceap+99)) (assert_return (invoke "f64.mul" (f64.const 1e20) (f64.const 1e20)) (f64.const 0x1.d6329f1c35ca5p+132)) (assert_return (invoke "f64.mul" (f64.const 1e25) (f64.const 1e25)) (f64.const 0x1.11b0ec57e649bp+166)) @@ -157,6 +161,10 @@ ;; section 3.3.1: A typical problem: "double rounding" (assert_return (invoke "f64.mul" (f64.const 1848874847.0) (f64.const 19954562207.0)) (f64.const 3.6893488147419111424e+19)) +;; Test for a historic spreadsheet bug. +;; http://www.joelonsoftware.com/items/2007/09/26b.html +(assert_return (invoke "f64.mul" (f64.const 77.1) (f64.const 850)) (f64.const 65534.99999999999272404)) + ;; Computations that round differently on x87. (assert_return (invoke "f64.mul" (f64.const 0x1.f99fb602c89b7p-341) (f64.const 0x1.6caab46a31a2ep-575)) (f64.const 0x1.68201f986e9d7p-915)) (assert_return (invoke "f64.mul" (f64.const -0x1.86999c5eee379p-9) (f64.const 0x1.6e3b9e0d53e0dp+723)) (f64.const -0x1.17654a0ef35f5p+715)) From 84a94dc8cbe66614ebf36ff65d28dc6e1cf70bdd Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 9 Oct 2015 19:25:02 -0700 Subject: [PATCH 15/18] Test floating point literals that once caused PHP to hang. http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ --- ml-proto/test/float_literals.wast | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ml-proto/test/float_literals.wast b/ml-proto/test/float_literals.wast index 7146249a56..27ed205ee7 100644 --- a/ml-proto/test/float_literals.wast +++ b/ml-proto/test/float_literals.wast @@ -19,6 +19,7 @@ (func $f32.min_positive (result i32) (i32.reinterpret/f32 (f32.const 0x1p-149))) (func $f32.max_finite (result i32) (i32.reinterpret/f32 (f32.const 0x1.fffffep+127))) (func $f32.trailing_dot (result i32) (i32.reinterpret/f32 (f32.const 0x1.p4))) + (func $f32.max_subnormal (result i32) (i32.reinterpret/f32 (f32.const 1.1754942106924410e-38))) (func $f64.nan (result i64) (i64.reinterpret/f64 (f64.const nan))) (func $f64.positive_nan (result i64) (i64.reinterpret/f64 (f64.const +nan))) @@ -40,7 +41,7 @@ (func $f64.min_positive (result i64) (i64.reinterpret/f64 (f64.const 0x0.0000000000001p-1022))) (func $f64.max_finite (result i64) (i64.reinterpret/f64 (f64.const 0x1.fffffffffffffp+1023))) (func $f64.trailing_dot (result i64) (i64.reinterpret/f64 (f64.const 0x1.p4))) - + (func $f64.max_subnormal (result i64) (i64.reinterpret/f64 (f64.const 2.2250738585072011e-308))) (export "f32.nan" $f32.nan) (export "f32.positive_nan" $f32.positive_nan) (export "f32.negative_nan" $f32.negative_nan) @@ -61,6 +62,7 @@ (export "f32.min_positive" $f32.min_positive) (export "f32.max_finite" $f32.max_finite) (export "f32.trailing_dot" $f32.trailing_dot) + (export "f32.max_subnormal" $f32.max_subnormal) (export "f64.nan" $f64.nan) (export "f64.positive_nan" $f64.positive_nan) @@ -82,6 +84,7 @@ (export "f64.min_positive" $f64.min_positive) (export "f64.max_finite" $f64.max_finite) (export "f64.trailing_dot" $f64.trailing_dot) + (export "f64.max_subnormal" $f64.max_subnormal) ) (assert_return (invoke "f32.nan") (i32.const 0x7fc00000)) @@ -104,6 +107,7 @@ (assert_return (invoke "f32.min_positive") (i32.const 1)) (assert_return (invoke "f32.max_finite") (i32.const 0x7f7fffff)) (assert_return (invoke "f32.trailing_dot") (i32.const 0x41800000)) +(assert_return (invoke "f32.max_subnormal") (i32.const 0x7fffff)) (assert_return (invoke "f64.nan") (i64.const 0x7ff8000000000000)) (assert_return (invoke "f64.positive_nan") (i64.const 0x7ff8000000000000)) @@ -125,3 +129,4 @@ (assert_return (invoke "f64.min_positive") (i64.const 1)) (assert_return (invoke "f64.max_finite") (i64.const 0x7fefffffffffffff)) (assert_return (invoke "f64.trailing_dot") (i64.const 0x4030000000000000)) +(assert_return (invoke "f64.max_subnormal") (i64.const 0xfffffffffffff)) From b827e3478293bda172722a162c15e25239be87b7 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 9 Oct 2015 07:53:34 -0700 Subject: [PATCH 16/18] Test adding and subtracting very small values with 1.0. --- ml-proto/test/float_misc.wast | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ml-proto/test/float_misc.wast b/ml-proto/test/float_misc.wast index 7da38945da..f8dd6c43a7 100644 --- a/ml-proto/test/float_misc.wast +++ b/ml-proto/test/float_misc.wast @@ -54,6 +54,11 @@ (assert_return (invoke "f32.add" (f32.const 1.1234567890) (f32.const 1.2345e-10)) (f32.const 1.123456789)) +;; Test adding the greatest value to 1.0 that rounds back to 1.0, and the +;; least that rounds to something greater. +(assert_return (invoke "f32.add" (f32.const 1.0) (f32.const 0x1p-24)) (f32.const 0x1.0p+0)) +(assert_return (invoke "f32.add" (f32.const 1.0) (f32.const 0x1.000002p-24)) (f32.const 0x1.000002p+0)) + ;; Computations that round differently in ties-to-odd mode. (assert_return (invoke "f32.add" (f32.const 0x1p23) (f32.const 0x1p-1)) (f32.const 0x1p23)) (assert_return (invoke "f32.add" (f32.const 0x1.000002p+23) (f32.const 0x1p-1)) (f32.const 0x1.000004p+23)) @@ -68,6 +73,11 @@ ;; section 3.3.1: A typical problem: "double rounding" (assert_return (invoke "f64.add" (f64.const 0x1p+63) (f64.const 1024.25)) (f64.const 0x1.0000000000001p+63)) +;; Test adding the greatest value to 1.0 that rounds back to 1.0, and the +;; least that rounds to something greater. +(assert_return (invoke "f64.add" (f64.const 1.0) (f64.const 0x1p-53)) (f64.const 0x1.0p+0)) +(assert_return (invoke "f64.add" (f64.const 1.0) (f64.const 0x1.0000000000001p-53)) (f64.const 0x1.0000000000001p+0)) + ;; Computations that round differently in round-to-odd mode. (assert_return (invoke "f64.add" (f64.const 0x1p52) (f64.const 0x1p-1)) (f64.const 0x1p52)) (assert_return (invoke "f64.add" (f64.const 0x1.0000000000001p+52) (f64.const 0x1p-1)) (f64.const 0x1.0000000000002p+52)) @@ -132,6 +142,16 @@ ;; https://blogs.office.com/2007/09/25/calculation-issue-update/ (assert_return (invoke "f64.sub" (f64.const 65536.0) (f64.const 0x1p-37)) (f64.const 0x1.fffffffffffffp+15)) +;; Test subtracting the greatest value from 1.0 that rounds back to 1.0, and the +;; least that rounds to something less. +(assert_return (invoke "f32.sub" (f32.const 1.0) (f32.const 0x1p-25)) (f32.const 0x1.0p+0)) +(assert_return (invoke "f32.sub" (f32.const 1.0) (f32.const 0x1.000002p-25)) (f32.const 0x1.fffffep-1)) + +;; Test subtracting the greatest value from 1.0 that rounds back to 1.0, and the +;; least that rounds to something less. +(assert_return (invoke "f64.sub" (f64.const 1.0) (f64.const 0x1p-54)) (f64.const 0x1.0p+0)) +(assert_return (invoke "f64.sub" (f64.const 1.0) (f64.const 0x1.0000000000001p-54)) (f64.const 0x1.fffffffffffffp-1)) + ;; Computations that round differently on x87. (assert_return (invoke "f64.sub" (f64.const 0x1.c21151a709b6cp-78) (f64.const 0x1.0a12fff8910f6p-115)) (f64.const 0x1.c21151a701663p-78)) (assert_return (invoke "f64.sub" (f64.const 0x1.c57912aae2f64p-982) (f64.const 0x1.dbfbd4800b7cfp-1010)) (f64.const 0x1.c579128d2338fp-982)) From 5a4179a577e965e8f5675f8fee61a068b7c557fd Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 9 Oct 2015 07:53:42 -0700 Subject: [PATCH 17/18] Test for a "tricky" case from MMIX. --- ml-proto/test/float_misc.wast | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ml-proto/test/float_misc.wast b/ml-proto/test/float_misc.wast index f8dd6c43a7..12a8f2da20 100644 --- a/ml-proto/test/float_misc.wast +++ b/ml-proto/test/float_misc.wast @@ -73,6 +73,10 @@ ;; section 3.3.1: A typical problem: "double rounding" (assert_return (invoke "f64.add" (f64.const 0x1p+63) (f64.const 1024.25)) (f64.const 0x1.0000000000001p+63)) +;; Test a case that was "tricky" on MMIX. +;; http://mmix.cs.hm.edu/bugs/bug_rounding.html +(assert_return (invoke "f64.add" (f64.const -0x1p-1008) (f64.const 0x0.0000000001716p-1022)) (f64.const -0x1.fffffffffffffp-1009)) + ;; Test adding the greatest value to 1.0 that rounds back to 1.0, and the ;; least that rounds to something greater. (assert_return (invoke "f64.add" (f64.const 1.0) (f64.const 0x1p-53)) (f64.const 0x1.0p+0)) From 66effffcc2d8ae20ab9ec9d9325d3a8d3efbb610 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 12 Oct 2015 07:53:18 -0700 Subject: [PATCH 18/18] Add a todo item for call and store operand evaluation order. --- ml-proto/TestingTodo.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ml-proto/TestingTodo.md b/ml-proto/TestingTodo.md index d0a994ccd9..063fbc64b3 100644 --- a/ml-proto/TestingTodo.md +++ b/ml-proto/TestingTodo.md @@ -22,6 +22,7 @@ Operator semantics: - ~~test that shifts don't mask their shift count. 32 is particularly nice to test.~~ - test that `page_size` returns a power of 2 - ~~test that arithmetic operands are evaluated left-to-right~~ + - test that call and store operands are evaluated left-to-right too - ~~test that add/sub/mul/wrap/wrapping-store silently wrap on overflow~~ - ~~test that sdiv/udiv/srem/urem trap on divide-by-zero~~ - ~~test that sdiv traps on overflow~~