From cbcfd0312672244265f7779eb875bc71a7fa1da6 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Sat, 3 Oct 2020 02:06:15 +0300 Subject: [PATCH 01/14] add tests for neg dividers --- .../optimize-instructions_all-features.txt | 40 +++++++++++++++++++ .../optimize-instructions_all-features.wast | 40 ++++++++++++++++++- 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/test/passes/optimize-instructions_all-features.txt b/test/passes/optimize-instructions_all-features.txt index 5bbaccfeaa6..09bb94de4e3 100644 --- a/test/passes/optimize-instructions_all-features.txt +++ b/test/passes/optimize-instructions_all-features.txt @@ -2762,6 +2762,22 @@ ) ) ) + (drop + (i32.eqz + (i32.rem_s + (local.get $x) + (i32.const -4) + ) + ) + ) + (drop + (i64.eqz + (i64.rem_s + (local.get $y) + (i64.const -4) + ) + ) + ) (drop (i32.eqz (i32.and @@ -2778,6 +2794,22 @@ ) ) ) + (drop + (i32.eqz + (i32.rem_s + (local.get $x) + (i32.const -4) + ) + ) + ) + (drop + (i64.eqz + (i64.rem_s + (local.get $y) + (i64.const -4) + ) + ) + ) (drop (i32.ne (i32.and @@ -2795,6 +2827,14 @@ ) ) ) + (drop + (i32.eqz + (i32.rem_s + (local.get $x) + (i32.const -2147483648) + ) + ) + ) (drop (i32.eqz (i32.rem_s diff --git a/test/passes/optimize-instructions_all-features.wast b/test/passes/optimize-instructions_all-features.wast index c8a48391ce7..13a140e56a3 100644 --- a/test/passes/optimize-instructions_all-features.wast +++ b/test/passes/optimize-instructions_all-features.wast @@ -3118,6 +3118,19 @@ (i64.const 4) ) )) + ;; eqz((signed)x % -4) + (drop (i32.eqz + (i32.rem_s + (local.get $x) + (i32.const -4) + ) + )) + (drop (i64.eqz + (i64.rem_s + (local.get $y) + (i64.const -4) + ) + )) ;; (signed)x % 4 == 0 (drop (i32.eq (i32.rem_s @@ -3133,7 +3146,22 @@ ) (i64.const 0) )) - ;; ;; (signed)x % 2 != 0 + ;; (signed)x % -4 == 0 + (drop (i32.eq + (i32.rem_s + (local.get $x) + (i32.const -4) + ) + (i32.const 0) + )) + (drop (i64.eq + (i64.rem_s + (local.get $y) + (i64.const -4) + ) + (i64.const 0) + )) + ;; (signed)x % 2 != 0 (drop (i32.ne (i32.rem_s (local.get $x) @@ -3148,7 +3176,15 @@ ) (i64.const 0) )) - ;; ;; + ;; (signed)x % 0x80000000 + (drop (i32.eq + (i32.rem_s + (local.get $x) + (i32.const 0x80000000) + ) + (i32.const 0) + )) + ;; (drop (i32.eq (i32.rem_s (local.get $x) From 9e21dfa080a5a70a0babd85cf598795271c3d18a Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Sat, 3 Oct 2020 03:02:27 +0300 Subject: [PATCH 02/14] improve rules + extra tests --- src/passes/OptimizeInstructions.cpp | 18 ++++++--- .../optimize-instructions_all-features.txt | 38 +++++++++++++------ .../optimize-instructions_all-features.wast | 18 ++++++++- 3 files changed, 55 insertions(+), 19 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 86951277421..44b345606aa 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -298,15 +298,18 @@ struct OptimizeInstructions } } { - // eqz((signed)x % C_pot) => eqz(x & (C_pot - 1)) + // eqz((signed)x % C_pot) => eqz(x & (abs(C_pot) - 1)) + // eqz((signed)x % (i32|i64).min_s) => eqz(x & (i32|i64).max_s) Const* c; Binary* inner; if (matches(curr, unary(Abstract::EqZ, binary(&inner, Abstract::RemS, any(), ival(&c)))) && - Bits::isPowerOf2((uint64_t)c->value.getInteger())) { + (Bits::isPowerOf2(c->value.abs().getInteger()) || + c->value.getUnsigned() == + (1ULL << (c->type.getByteSize() * 8 - 1)))) { inner->op = Abstract::getBinary(c->type, Abstract::And); - c->value = c->value.sub(Literal::makeFromInt32(1, c->type)); + c->value = c->value.abs().sub(Literal::makeFromInt32(1, c->type)); return curr; } } @@ -1307,7 +1310,8 @@ struct OptimizeInstructions right->value = Literal::makeSingleZero(type); return right; } - // (signed)x % C_pot != 0 ==> x & (C_pot - 1) != 0 + // (signed)x % C_pot != 0 ==> (x & (abs(C_pot) - 1)) != 0 + // (signed)x % (i32|i64).min_s != 0 ==> (x & (i32|i64).max_s) != 0 { Const* c; Binary* inner; @@ -1315,9 +1319,11 @@ struct OptimizeInstructions binary(Abstract::Ne, binary(&inner, Abstract::RemS, any(), ival(&c)), ival(0))) && - Bits::isPowerOf2((uint64_t)c->value.getInteger())) { + (Bits::isPowerOf2(c->value.abs().getInteger()) || + c->value.getUnsigned() == + (1ULL << (c->type.getByteSize() * 8 - 1)))) { inner->op = Abstract::getBinary(c->type, Abstract::And); - c->value = c->value.sub(Literal::makeFromInt32(1, c->type)); + c->value = c->value.abs().sub(Literal::makeFromInt32(1, c->type)); return curr; } } diff --git a/test/passes/optimize-instructions_all-features.txt b/test/passes/optimize-instructions_all-features.txt index 09bb94de4e3..5cbf1220970 100644 --- a/test/passes/optimize-instructions_all-features.txt +++ b/test/passes/optimize-instructions_all-features.txt @@ -2764,17 +2764,17 @@ ) (drop (i32.eqz - (i32.rem_s + (i32.and (local.get $x) - (i32.const -4) + (i32.const 3) ) ) ) (drop (i64.eqz - (i64.rem_s + (i64.and (local.get $y) - (i64.const -4) + (i64.const 3) ) ) ) @@ -2796,17 +2796,17 @@ ) (drop (i32.eqz - (i32.rem_s + (i32.and (local.get $x) - (i32.const -4) + (i32.const 3) ) ) ) (drop (i64.eqz - (i64.rem_s + (i64.and (local.get $y) - (i64.const -4) + (i64.const 3) ) ) ) @@ -2829,12 +2829,26 @@ ) (drop (i32.eqz - (i32.rem_s + (i32.const 0) + ) + ) + (drop + (i32.eqz + (i32.and (local.get $x) - (i32.const -2147483648) + (i32.const 2147483647) ) ) ) + (drop + (i32.ne + (i32.and + (local.get $x) + (i32.const 2147483647) + ) + (i32.const 0) + ) + ) (drop (i32.eqz (i32.rem_s @@ -2845,9 +2859,9 @@ ) (drop (i32.eqz - (i32.rem_s + (i32.and (local.get $x) - (i32.const -4) + (i32.const 3) ) ) ) diff --git a/test/passes/optimize-instructions_all-features.wast b/test/passes/optimize-instructions_all-features.wast index 13a140e56a3..51297ecc0c7 100644 --- a/test/passes/optimize-instructions_all-features.wast +++ b/test/passes/optimize-instructions_all-features.wast @@ -3176,8 +3176,24 @@ ) (i64.const 0) )) - ;; (signed)x % 0x80000000 + ;; (signed)x % -1 == 0 -> 0 == 0 (drop (i32.eq + (i32.rem_s + (local.get $x) + (i32.const -1) + ) + (i32.const 0) + )) + ;; (signed)x % 0x80000000 == 0 + (drop (i32.eq + (i32.rem_s + (local.get $x) + (i32.const 0x80000000) + ) + (i32.const 0) + )) + ;; (signed)x % 0x80000000 != 0 + (drop (i32.ne (i32.rem_s (local.get $x) (i32.const 0x80000000) From 4da2539b5e4ef62449a021d2bd4ca31eb70563fb Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Sat, 3 Oct 2020 12:07:29 +0300 Subject: [PATCH 03/14] add signed/unsigned min/max for check and creation. Refactor --- src/literal.h | 60 +++++++++++++++++++++++++++++ src/passes/OptimizeInstructions.cpp | 18 ++++++--- 2 files changed, 72 insertions(+), 6 deletions(-) diff --git a/src/literal.h b/src/literal.h index eedccabcc25..db8eeb6627e 100644 --- a/src/literal.h +++ b/src/literal.h @@ -96,6 +96,46 @@ class Literal { } return false; } + bool isSignedMin() const { + switch (type.getBasic()) { + case Type::i32: + return i32 == std::numeric_limits::min(); + case Type::i64: + return i64 == std::numeric_limits::min(); + default: + WASM_UNREACHABLE("unexpected type"); + } + } + bool isSignedMax() const { + switch (type.getBasic()) { + case Type::i32: + return i32 == std::numeric_limits::max(); + case Type::i64: + return i64 == std::numeric_limits::max(); + default: + WASM_UNREACHABLE("unexpected type"); + } + } + bool isUnsignedMin() const { + switch (type.getBasic()) { + case Type::i32: + return uint32_t(i32) == std::numeric_limits::min(); + case Type::i64: + return uint64_t(i64) == std::numeric_limits::min(); + default: + WASM_UNREACHABLE("unexpected type"); + } + } + bool isUnsignedMax() const { + switch (type.getBasic()) { + case Type::i32: + return uint32_t(i32) == std::numeric_limits::max(); + case Type::i64: + return uint64_t(i64) == std::numeric_limits::max(); + default: + WASM_UNREACHABLE("unexpected type"); + } + } static Literal makeFromInt32(int32_t x, Type type) { switch (type.getBasic()) { @@ -134,6 +174,26 @@ class Literal { static Literals makeZero(Type type); static Literal makeSingleZero(Type type); + static Literal makeSignedMin(Type type) { + switch (type.getBasic()) { + case Type::i32: + return Literal(std::numeric_limits::min()); + case Type::i64: + return Literal(std::numeric_limits::min()); + default: + WASM_UNREACHABLE("unexpected type"); + } + } + static Literal makeSignedMax(Type type) { + switch (type.getBasic()) { + case Type::i32: + return Literal(std::numeric_limits::max()); + case Type::i64: + return Literal(std::numeric_limits::max()); + default: + WASM_UNREACHABLE("unexpected type"); + } + } static Literal makeNull(Type type) { assert(type.isNullable()); diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 44b345606aa..42a5f205398 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -306,10 +306,13 @@ struct OptimizeInstructions unary(Abstract::EqZ, binary(&inner, Abstract::RemS, any(), ival(&c)))) && (Bits::isPowerOf2(c->value.abs().getInteger()) || - c->value.getUnsigned() == - (1ULL << (c->type.getByteSize() * 8 - 1)))) { + c->value.isSignedMin())) { inner->op = Abstract::getBinary(c->type, Abstract::And); - c->value = c->value.abs().sub(Literal::makeFromInt32(1, c->type)); + if (c->value.isSignedMin()) { + c->value = Literal::makeSignedMax(c->type); + } else { + c->value = c->value.abs().sub(Literal::makeFromInt32(1, c->type)); + } return curr; } } @@ -1320,10 +1323,13 @@ struct OptimizeInstructions binary(&inner, Abstract::RemS, any(), ival(&c)), ival(0))) && (Bits::isPowerOf2(c->value.abs().getInteger()) || - c->value.getUnsigned() == - (1ULL << (c->type.getByteSize() * 8 - 1)))) { + c->value.isSignedMin())) { inner->op = Abstract::getBinary(c->type, Abstract::And); - c->value = c->value.abs().sub(Literal::makeFromInt32(1, c->type)); + if (c->value.isSignedMin()) { + c->value = Literal::makeSignedMax(c->type); + } else { + c->value = c->value.abs().sub(Literal::makeFromInt32(1, c->type)); + } return curr; } } From 2cfbeaf9b3d0b2230d621d385890aee0d2c739ef Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Sat, 3 Oct 2020 12:12:11 +0300 Subject: [PATCH 04/14] remove x % -4 from skipped cases --- test/passes/optimize-instructions_all-features.txt | 8 -------- test/passes/optimize-instructions_all-features.wast | 7 ------- 2 files changed, 15 deletions(-) diff --git a/test/passes/optimize-instructions_all-features.txt b/test/passes/optimize-instructions_all-features.txt index 5cbf1220970..1b49175834b 100644 --- a/test/passes/optimize-instructions_all-features.txt +++ b/test/passes/optimize-instructions_all-features.txt @@ -2857,14 +2857,6 @@ ) ) ) - (drop - (i32.eqz - (i32.and - (local.get $x) - (i32.const 3) - ) - ) - ) (drop (i64.eqz (i64.rem_s diff --git a/test/passes/optimize-instructions_all-features.wast b/test/passes/optimize-instructions_all-features.wast index 51297ecc0c7..ec4865fe247 100644 --- a/test/passes/optimize-instructions_all-features.wast +++ b/test/passes/optimize-instructions_all-features.wast @@ -3208,13 +3208,6 @@ ) (i32.const 0) )) - (drop (i32.eq - (i32.rem_s - (local.get $x) - (i32.const -4) ;; skip - ) - (i32.const 0) - )) (drop (i64.eq (i64.rem_s (local.get $y) From 0d2fb67307b7edaaeea990d2b76625ece49817dc Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Sat, 3 Oct 2020 12:18:16 +0300 Subject: [PATCH 05/14] 64-bit tests for special case --- .../optimize-instructions_all-features.txt | 17 +++++++++++++++++ .../optimize-instructions_all-features.wast | 16 ++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/test/passes/optimize-instructions_all-features.txt b/test/passes/optimize-instructions_all-features.txt index 1b49175834b..7e89cc21b47 100644 --- a/test/passes/optimize-instructions_all-features.txt +++ b/test/passes/optimize-instructions_all-features.txt @@ -2849,6 +2849,23 @@ (i32.const 0) ) ) + (drop + (i64.eqz + (i64.and + (local.get $y) + (i64.const 9223372036854775807) + ) + ) + ) + (drop + (i64.ne + (i64.and + (local.get $y) + (i64.const 9223372036854775807) + ) + (i64.const 0) + ) + ) (drop (i32.eqz (i32.rem_s diff --git a/test/passes/optimize-instructions_all-features.wast b/test/passes/optimize-instructions_all-features.wast index ec4865fe247..e48ca20d774 100644 --- a/test/passes/optimize-instructions_all-features.wast +++ b/test/passes/optimize-instructions_all-features.wast @@ -3200,6 +3200,22 @@ ) (i32.const 0) )) + ;; (signed)x % 0x8000000000000000 == 0 + (drop (i64.eq + (i64.rem_s + (local.get $y) + (i64.const 0x8000000000000000) + ) + (i64.const 0) + )) + ;; (signed)x % 0x8000000000000000 != 0 + (drop (i64.ne + (i64.rem_s + (local.get $y) + (i64.const 0x8000000000000000) + ) + (i64.const 0) + )) ;; (drop (i32.eq (i32.rem_s From 6a0b74a6aedb041c528546eb0c6aa782dbbeb010 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Sat, 3 Oct 2020 12:52:49 +0300 Subject: [PATCH 06/14] fix? --- src/passes/OptimizeInstructions.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 42a5f205398..c034a5e28de 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -305,8 +305,8 @@ struct OptimizeInstructions if (matches(curr, unary(Abstract::EqZ, binary(&inner, Abstract::RemS, any(), ival(&c)))) && - (Bits::isPowerOf2(c->value.abs().getInteger()) || - c->value.isSignedMin())) { + (c->value.isSignedMin() || + Bits::isPowerOf2(c->value.abs().getInteger()))) { inner->op = Abstract::getBinary(c->type, Abstract::And); if (c->value.isSignedMin()) { c->value = Literal::makeSignedMax(c->type); @@ -1322,8 +1322,8 @@ struct OptimizeInstructions binary(Abstract::Ne, binary(&inner, Abstract::RemS, any(), ival(&c)), ival(0))) && - (Bits::isPowerOf2(c->value.abs().getInteger()) || - c->value.isSignedMin())) { + (c->value.isSignedMin() || + Bits::isPowerOf2(c->value.abs().getInteger()))) { inner->op = Abstract::getBinary(c->type, Abstract::And); if (c->value.isSignedMin()) { c->value = Literal::makeSignedMax(c->type); From 6f3f03b6fa221898a24aec3f59723ad537970914 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Sat, 3 Oct 2020 15:04:13 +0300 Subject: [PATCH 07/14] more general. Move x % min_s to external rule without cmp with zero --- src/passes/OptimizeInstructions.cpp | 32 +++++++++---------- .../optimize-instructions_all-features.txt | 14 +++++++- .../optimize-instructions_all-features.wast | 12 ++++++- 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index c034a5e28de..5c089f6cf30 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -299,20 +299,15 @@ struct OptimizeInstructions } { // eqz((signed)x % C_pot) => eqz(x & (abs(C_pot) - 1)) - // eqz((signed)x % (i32|i64).min_s) => eqz(x & (i32|i64).max_s) Const* c; Binary* inner; if (matches(curr, unary(Abstract::EqZ, binary(&inner, Abstract::RemS, any(), ival(&c)))) && - (c->value.isSignedMin() || - Bits::isPowerOf2(c->value.abs().getInteger()))) { + !c->value.isSignedMin() && + Bits::isPowerOf2(c->value.abs().getInteger())) { inner->op = Abstract::getBinary(c->type, Abstract::And); - if (c->value.isSignedMin()) { - c->value = Literal::makeSignedMax(c->type); - } else { - c->value = c->value.abs().sub(Literal::makeFromInt32(1, c->type)); - } + c->value = c->value.abs().sub(Literal::makeFromInt32(1, c->type)); return curr; } } @@ -1313,8 +1308,17 @@ struct OptimizeInstructions right->value = Literal::makeSingleZero(type); return right; } + { + // (signed)x % (i32|i64).min_s ==> (x & (i32|i64).max_s) + Const* c; + if (matches(curr, binary(Abstract::RemS, any(&left), ival(&c))) && + c->value.isSignedMin()) { + curr->op = Abstract::getBinary(type, Abstract::And); + right->value = Literal::makeSignedMax(type); + return curr; + } + } // (signed)x % C_pot != 0 ==> (x & (abs(C_pot) - 1)) != 0 - // (signed)x % (i32|i64).min_s != 0 ==> (x & (i32|i64).max_s) != 0 { Const* c; Binary* inner; @@ -1322,14 +1326,10 @@ struct OptimizeInstructions binary(Abstract::Ne, binary(&inner, Abstract::RemS, any(), ival(&c)), ival(0))) && - (c->value.isSignedMin() || - Bits::isPowerOf2(c->value.abs().getInteger()))) { + !c->value.isSignedMin() && + Bits::isPowerOf2(c->value.abs().getInteger())) { inner->op = Abstract::getBinary(c->type, Abstract::And); - if (c->value.isSignedMin()) { - c->value = Literal::makeSignedMax(c->type); - } else { - c->value = c->value.abs().sub(Literal::makeFromInt32(1, c->type)); - } + c->value = c->value.abs().sub(Literal::makeFromInt32(1, c->type)); return curr; } } diff --git a/test/passes/optimize-instructions_all-features.txt b/test/passes/optimize-instructions_all-features.txt index 7e89cc21b47..dc06f5f6f07 100644 --- a/test/passes/optimize-instructions_all-features.txt +++ b/test/passes/optimize-instructions_all-features.txt @@ -2737,13 +2737,25 @@ ) (unreachable) ) - (func $srem-by-1 (param $x i32) (param $y i64) + (func $srem-by-const (param $x i32) (param $y i64) (drop (i32.const 0) ) (drop (i64.const 0) ) + (drop + (i32.and + (local.get $x) + (i32.const 2147483647) + ) + ) + (drop + (i64.and + (local.get $y) + (i64.const 9223372036854775807) + ) + ) ) (func $srem-by-pot-eq-ne-zero (param $x i32) (param $y i64) (drop diff --git a/test/passes/optimize-instructions_all-features.wast b/test/passes/optimize-instructions_all-features.wast index e48ca20d774..787551618d3 100644 --- a/test/passes/optimize-instructions_all-features.wast +++ b/test/passes/optimize-instructions_all-features.wast @@ -3093,7 +3093,7 @@ ) (unreachable) ) - (func $srem-by-1 (param $x i32) (param $y i64) + (func $srem-by-const (param $x i32) (param $y i64) ;; (signed)x % 1 (drop (i32.rem_s (local.get $x) @@ -3103,6 +3103,16 @@ (local.get $y) (i64.const 1) )) + ;; (signed)x % 0x80000000 -> x & 0x7FFFFFFF + (drop (i32.rem_s + (local.get $x) + (i32.const 0x80000000) + )) + ;; (signed)x % 0x8000000000000000 -> x & 0x7FFFFFFFFFFFFFFF + (drop (i64.rem_s + (local.get $y) + (i64.const 0x8000000000000000) + )) ) (func $srem-by-pot-eq-ne-zero (param $x i32) (param $y i64) ;; eqz((signed)x % 4) From d574dfec010d62253700e59cbddb65a6649c5987 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Sat, 3 Oct 2020 15:53:17 +0300 Subject: [PATCH 08/14] add isZero to Literal --- src/literal.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/literal.h b/src/literal.h index db8eeb6627e..a8a7fda6ae1 100644 --- a/src/literal.h +++ b/src/literal.h @@ -96,6 +96,24 @@ class Literal { } return false; } + bool isZero() const { + switch (type.getBasic()) { + case Type::i32: + return i32 == 0; + case Type::i64: + return i64 == 0LL; + case Type::f32: + return bit_cast(i32) == 0.0f; + case Type::f64: + return bit_cast(i64) == 0.0; + case Type::v128: { + uint8_t zeros[16] = {0}; + return memcmp(&v128, zeros, 16) == 0; + } + default: + WASM_UNREACHABLE("unexpected type"); + } + } bool isSignedMin() const { switch (type.getBasic()) { case Type::i32: From e6d2b192c019447e78beb8b3bfc945efdeff85e0 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Sat, 3 Oct 2020 17:08:46 +0300 Subject: [PATCH 09/14] add makeUnsignedMin / makeUnsignedMax for consistency --- src/literal.h | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/literal.h b/src/literal.h index a8a7fda6ae1..1dbf4574486 100644 --- a/src/literal.h +++ b/src/literal.h @@ -155,6 +155,8 @@ class Literal { } } + static Literals makeZero(Type type); + static Literal makeSingleZero(Type type); static Literal makeFromInt32(int32_t x, Type type) { switch (type.getBasic()) { case Type::i32: @@ -174,7 +176,6 @@ class Literal { WASM_UNREACHABLE("unexpected type"); } } - static Literal makeFromUInt64(uint64_t x, Type type) { switch (type.getBasic()) { case Type::i32: @@ -189,9 +190,6 @@ class Literal { WASM_UNREACHABLE("unexpected type"); } } - - static Literals makeZero(Type type); - static Literal makeSingleZero(Type type); static Literal makeSignedMin(Type type) { switch (type.getBasic()) { case Type::i32: @@ -212,7 +210,17 @@ class Literal { WASM_UNREACHABLE("unexpected type"); } } - + static Literal makeUnsignedMin(Type type) { return makeSingleZero(type); } + static Literal makeUnsignedMax(Type type) { + switch (type.getBasic()) { + case Type::i32: + return Literal(std::numeric_limits::max()); + case Type::i64: + return Literal(std::numeric_limits::max()); + default: + WASM_UNREACHABLE("unexpected type"); + } + } static Literal makeNull(Type type) { assert(type.isNullable()); return Literal(type); From 9708dd6273da6e49f7d840a2beffa708af4bf900 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Sat, 3 Oct 2020 17:24:42 +0300 Subject: [PATCH 10/14] separate to isZero and isSingleZero --- src/literal.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/literal.h b/src/literal.h index 1dbf4574486..4eae83f7f76 100644 --- a/src/literal.h +++ b/src/literal.h @@ -97,6 +97,13 @@ class Literal { return false; } bool isZero() const { + if (type.isVector()) { + uint8_t zeros[16] = {0}; + return memcmp(&v128, zeros, 16) == 0; + } + return isSignleZero(); + } + bool isSignleZero() const { switch (type.getBasic()) { case Type::i32: return i32 == 0; @@ -106,10 +113,6 @@ class Literal { return bit_cast(i32) == 0.0f; case Type::f64: return bit_cast(i64) == 0.0; - case Type::v128: { - uint8_t zeros[16] = {0}; - return memcmp(&v128, zeros, 16) == 0; - } default: WASM_UNREACHABLE("unexpected type"); } From 17e50821df4d203c02500077117a40437c6630dc Mon Sep 17 00:00:00 2001 From: Max Graey Date: Mon, 5 Oct 2020 01:55:16 +0300 Subject: [PATCH 11/14] Update src/passes/OptimizeInstructions.cpp Co-authored-by: Thomas Lively <7121787+tlively@users.noreply.github.com> --- src/passes/OptimizeInstructions.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 5c089f6cf30..cdbca762e81 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -1310,9 +1310,8 @@ struct OptimizeInstructions } { // (signed)x % (i32|i64).min_s ==> (x & (i32|i64).max_s) - Const* c; - if (matches(curr, binary(Abstract::RemS, any(&left), ival(&c))) && - c->value.isSignedMin()) { + if (matches(curr, binary(Abstract::RemS, any(&left), ival())) && + right->value.isSignedMin()) { curr->op = Abstract::getBinary(type, Abstract::And); right->value = Literal::makeSignedMax(type); return curr; From 3f4925552da183a41c2f4e1bebec6a1afa5a26b0 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Mon, 5 Oct 2020 01:56:55 +0300 Subject: [PATCH 12/14] fix typo --- src/literal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/literal.h b/src/literal.h index 4eae83f7f76..ae542597166 100644 --- a/src/literal.h +++ b/src/literal.h @@ -101,9 +101,9 @@ class Literal { uint8_t zeros[16] = {0}; return memcmp(&v128, zeros, 16) == 0; } - return isSignleZero(); + return isSingleZero(); } - bool isSignleZero() const { + bool isSingleZero() const { switch (type.getBasic()) { case Type::i32: return i32 == 0; From 57dfba0ceb69bb67110b531e167fd192ae014d04 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Mon, 5 Oct 2020 01:58:36 +0300 Subject: [PATCH 13/14] remove isUnsignedMin and makeUnsignedMin --- src/literal.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/literal.h b/src/literal.h index ae542597166..a12786b9851 100644 --- a/src/literal.h +++ b/src/literal.h @@ -137,16 +137,6 @@ class Literal { WASM_UNREACHABLE("unexpected type"); } } - bool isUnsignedMin() const { - switch (type.getBasic()) { - case Type::i32: - return uint32_t(i32) == std::numeric_limits::min(); - case Type::i64: - return uint64_t(i64) == std::numeric_limits::min(); - default: - WASM_UNREACHABLE("unexpected type"); - } - } bool isUnsignedMax() const { switch (type.getBasic()) { case Type::i32: @@ -213,7 +203,6 @@ class Literal { WASM_UNREACHABLE("unexpected type"); } } - static Literal makeUnsignedMin(Type type) { return makeSingleZero(type); } static Literal makeUnsignedMax(Type type) { switch (type.getBasic()) { case Type::i32: From 12d2a882d126b3b846313cee65996011d5903ec3 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Mon, 5 Oct 2020 09:53:13 +0300 Subject: [PATCH 14/14] unify to single isZero --- src/literal.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/literal.h b/src/literal.h index a12786b9851..33300c920f8 100644 --- a/src/literal.h +++ b/src/literal.h @@ -97,13 +97,6 @@ class Literal { return false; } bool isZero() const { - if (type.isVector()) { - uint8_t zeros[16] = {0}; - return memcmp(&v128, zeros, 16) == 0; - } - return isSingleZero(); - } - bool isSingleZero() const { switch (type.getBasic()) { case Type::i32: return i32 == 0; @@ -113,6 +106,10 @@ class Literal { return bit_cast(i32) == 0.0f; case Type::f64: return bit_cast(i64) == 0.0; + case Type::v128: { + uint8_t zeros[16] = {0}; + return memcmp(&v128, zeros, 16) == 0; + } default: WASM_UNREACHABLE("unexpected type"); }