summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ir/abstract.h40
-rw-r--r--src/passes/OptimizeInstructions.cpp119
-rw-r--r--test/binaryen.js/sieve.js.txt4
-rw-r--r--test/emcc_hello_world.fromasm92
-rw-r--r--test/emcc_hello_world.fromasm.clamp92
-rw-r--r--test/emcc_hello_world.fromasm.imprecise92
-rw-r--r--test/passes/inlining-optimizing_optimize-level=3.txt112
-rw-r--r--test/passes/optimize-instructions_all-features.txt267
-rw-r--r--test/passes/optimize-instructions_all-features.wast245
-rw-r--r--test/wasm2js/i64-ctz.2asm.js.opt2
-rw-r--r--test/wasm2js/unary-ops.2asm.js.opt2
11 files changed, 749 insertions, 318 deletions
diff --git a/src/ir/abstract.h b/src/ir/abstract.h
index e23ffad17..3071e6dd6 100644
--- a/src/ir/abstract.h
+++ b/src/ir/abstract.h
@@ -46,6 +46,14 @@ enum Op {
// Relational
Eq,
Ne,
+ LtS,
+ LtU,
+ LeS,
+ LeU,
+ GtS,
+ GtU,
+ GeS,
+ GeU
};
// Provide a wasm type and an abstract op and get the concrete one. For example,
@@ -126,6 +134,22 @@ inline BinaryOp getBinary(Type type, Op op) {
return EqInt32;
case Ne:
return NeInt32;
+ case LtS:
+ return LtSInt32;
+ case LtU:
+ return LtUInt32;
+ case LeS:
+ return LeSInt32;
+ case LeU:
+ return LeUInt32;
+ case GtS:
+ return GtSInt32;
+ case GtU:
+ return GtUInt32;
+ case GeS:
+ return GeSInt32;
+ case GeU:
+ return GeUInt32;
default:
return InvalidBinary;
}
@@ -163,6 +187,22 @@ inline BinaryOp getBinary(Type type, Op op) {
return EqInt64;
case Ne:
return NeInt64;
+ case LtS:
+ return LtSInt64;
+ case LtU:
+ return LtUInt64;
+ case LeS:
+ return LeSInt64;
+ case LeU:
+ return LeUInt64;
+ case GtS:
+ return GtSInt64;
+ case GtU:
+ return GtUInt64;
+ case GeS:
+ return GeSInt64;
+ case GeU:
+ return GeUInt64;
default:
return InvalidBinary;
}
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index 3e3863e95..cbd8c9323 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -19,6 +19,7 @@
//
#include <algorithm>
+#include <type_traits>
#include <ir/abstract.h>
#include <ir/cost.h>
@@ -578,10 +579,30 @@ struct OptimizeInstructions
if (right->type == Type::i32) {
uint32_t c = right->value.geti32();
if (IsPowerOf2(c)) {
- if (binary->op == MulInt32) {
- return optimizePowerOf2Mul(binary, c);
- } else if (binary->op == RemUInt32) {
- return optimizePowerOf2URem(binary, c);
+ switch (binary->op) {
+ case MulInt32:
+ return optimizePowerOf2Mul(binary, c);
+ case RemUInt32:
+ return optimizePowerOf2URem(binary, c);
+ case DivUInt32:
+ return optimizePowerOf2UDiv(binary, c);
+ default:
+ break;
+ }
+ }
+ }
+ if (right->type == Type::i64) {
+ uint64_t c = right->value.geti64();
+ if (IsPowerOf2(c)) {
+ switch (binary->op) {
+ case MulInt64:
+ return optimizePowerOf2Mul(binary, c);
+ case RemUInt64:
+ return optimizePowerOf2URem(binary, c);
+ case DivUInt64:
+ return optimizePowerOf2UDiv(binary, c);
+ default:
+ break;
}
}
}
@@ -1265,22 +1286,37 @@ private:
// but it's still worth doing since
// * Often shifts are more common than muls.
// * The constant is smaller.
- Expression* optimizePowerOf2Mul(Binary* binary, uint32_t c) {
- uint32_t shifts = CountTrailingZeroes(c);
- binary->op = ShlInt32;
- binary->right->cast<Const>()->value = Literal(int32_t(shifts));
+ template<typename T> Expression* optimizePowerOf2Mul(Binary* binary, T c) {
+ static_assert(std::is_same<T, uint32_t>::value ||
+ std::is_same<T, uint64_t>::value,
+ "type mismatch");
+ auto shifts = CountTrailingZeroes<T>(c);
+ binary->op = std::is_same<T, uint32_t>::value ? ShlInt32 : ShlInt64;
+ binary->right->cast<Const>()->value = Literal(static_cast<T>(shifts));
return binary;
}
- // Optimize an unsigned divide by a power of two on the right,
- // which can be an AND mask
+ // Optimize an unsigned divide / remainder by a power of two on the right
// This doesn't shrink code size, and VMs likely optimize it anyhow,
// but it's still worth doing since
// * Usually ands are more common than urems.
// * The constant is slightly smaller.
- Expression* optimizePowerOf2URem(Binary* binary, uint32_t c) {
- binary->op = AndInt32;
- binary->right->cast<Const>()->value = Literal(int32_t(c - 1));
+ template<typename T> Expression* optimizePowerOf2UDiv(Binary* binary, T c) {
+ static_assert(std::is_same<T, uint32_t>::value ||
+ std::is_same<T, uint64_t>::value,
+ "type mismatch");
+ auto shifts = CountTrailingZeroes<T>(c);
+ binary->op = std::is_same<T, uint32_t>::value ? ShrUInt32 : ShrUInt64;
+ binary->right->cast<Const>()->value = Literal(static_cast<T>(shifts));
+ return binary;
+ }
+
+ template<typename T> Expression* optimizePowerOf2URem(Binary* binary, T c) {
+ static_assert(std::is_same<T, uint32_t>::value ||
+ std::is_same<T, uint64_t>::value,
+ "type mismatch");
+ binary->op = std::is_same<T, uint32_t>::value ? AndInt32 : AndInt64;
+ binary->right->cast<Const>()->value = Literal(c - 1);
return binary;
}
@@ -1327,8 +1363,9 @@ private:
auto type = binary->right->type;
auto* right = binary->right->cast<Const>();
if (type.isInteger()) {
+ auto constRight = right->value.getInteger();
// operations on zero
- if (right->value == Literal::makeFromInt32(0, type)) {
+ if (constRight == 0LL) {
if (binary->op == Abstract::getBinary(type, Abstract::Shl) ||
binary->op == Abstract::getBinary(type, Abstract::ShrU) ||
binary->op == Abstract::getBinary(type, Abstract::ShrS) ||
@@ -1344,16 +1381,62 @@ private:
return Builder(*getModule()).makeUnary(EqZInt64, binary->left);
}
}
+ // operations on one
+ if (constRight == 1LL) {
+ // (signed)x % 1 ==> 0
+ if (binary->op == Abstract::getBinary(type, Abstract::RemS) &&
+ !EffectAnalyzer(getPassOptions(), features, binary->left)
+ .hasSideEffects()) {
+ right->value = Literal::makeSingleZero(type);
+ return right;
+ }
+ }
// operations on all 1s
- // TODO: shortcut method to create an all-ones?
- if (right->value == Literal(int32_t(-1)) ||
- right->value == Literal(int64_t(-1))) {
+ if (constRight == -1LL) {
if (binary->op == Abstract::getBinary(type, Abstract::And)) {
+ // x & -1 ==> x
return binary->left;
} else if (binary->op == Abstract::getBinary(type, Abstract::Or) &&
!EffectAnalyzer(getPassOptions(), features, binary->left)
.hasSideEffects()) {
+ // x | -1 ==> -1
return binary->right;
+ } else if (binary->op == Abstract::getBinary(type, Abstract::RemS) &&
+ !EffectAnalyzer(getPassOptions(), features, binary->left)
+ .hasSideEffects()) {
+ // (signed)x % -1 ==> 0
+ right->value = Literal::makeSingleZero(type);
+ return right;
+ } else if (binary->op == Abstract::getBinary(type, Abstract::GtU) &&
+ !EffectAnalyzer(getPassOptions(), features, binary->left)
+ .hasSideEffects()) {
+ // (unsigned)x > -1 ==> 0
+ right->value = Literal::makeSingleZero(Type::i32);
+ right->type = Type::i32;
+ return right;
+ } else if (binary->op == Abstract::getBinary(type, Abstract::LtU)) {
+ // (unsigned)x < -1 ==> x != -1
+ // friendlier to JS emitting as we don't need to write an unsigned
+ // -1 value which is large.
+ binary->op = Abstract::getBinary(type, Abstract::Ne);
+ return binary;
+ } else if (binary->op == DivUInt32) {
+ // (unsigned)x / -1 ==> x == -1
+ binary->op = Abstract::getBinary(type, Abstract::Eq);
+ return binary;
+ } else if (binary->op == Abstract::getBinary(type, Abstract::Mul)) {
+ // x * -1 ==> 0 - x
+ binary->op = Abstract::getBinary(type, Abstract::Sub);
+ right->value = Literal::makeSingleZero(type);
+ std::swap(binary->left, binary->right);
+ return binary;
+ } else if (binary->op == Abstract::getBinary(type, Abstract::LeU) &&
+ !EffectAnalyzer(getPassOptions(), features, binary->left)
+ .hasSideEffects()) {
+ // (unsigned)x <= -1 ==> 1
+ right->value = Literal::makeFromInt32(1, Type::i32);
+ right->type = Type::i32;
+ return right;
}
}
// wasm binary encoding uses signed LEBs, which slightly favor negative
@@ -1364,7 +1447,7 @@ private:
// subtractions than the more common additions).
if (binary->op == Abstract::getBinary(type, Abstract::Add) ||
binary->op == Abstract::getBinary(type, Abstract::Sub)) {
- auto value = right->value.getInteger();
+ auto value = constRight;
if (value == 0x40 || value == 0x2000 || value == 0x100000 ||
value == 0x8000000 || value == 0x400000000LL ||
value == 0x20000000000LL || value == 0x1000000000000LL ||
diff --git a/test/binaryen.js/sieve.js.txt b/test/binaryen.js/sieve.js.txt
index 7a4223cd8..1da65a09f 100644
--- a/test/binaryen.js/sieve.js.txt
+++ b/test/binaryen.js/sieve.js.txt
@@ -73,12 +73,12 @@ optimized:
(drop
(memory.grow
(i32.sub
- (i32.div_u
+ (i32.shr_u
(i32.add
(local.get $0)
(i32.const 65535)
)
- (i32.const 65536)
+ (i32.const 16)
)
(memory.size)
)
diff --git a/test/emcc_hello_world.fromasm b/test/emcc_hello_world.fromasm
index 774740dc1..b66b70c56 100644
--- a/test/emcc_hello_world.fromasm
+++ b/test/emcc_hello_world.fromasm
@@ -7118,78 +7118,48 @@
)
(func $_fmt_u (; has Stack IR ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(local $3 i32)
- (local $4 i32)
(if
- (i32.or
- (i32.and
- (i32.eqz
- (local.get $1)
- )
- (i32.gt_u
- (local.get $0)
- (i32.const -1)
- )
- )
- (i32.gt_u
- (local.get $1)
- (i32.const 0)
- )
+ (i32.gt_u
+ (local.get $1)
+ (i32.const 0)
)
- (local.set $0
- (loop $while-in (result i32)
- (i32.store8
- (local.tee $2
- (i32.add
- (local.get $2)
- (i32.const -1)
- )
- )
- (i32.or
- (call $___uremdi3
- (local.get $0)
- (local.get $1)
- (i32.const 10)
- )
- (i32.const 48)
+ (loop $while-in
+ (i32.store8
+ (local.tee $2
+ (i32.add
+ (local.get $2)
+ (i32.const -1)
)
)
- (local.set $3
- (call $___udivdi3
+ (i32.or
+ (call $___uremdi3
(local.get $0)
(local.get $1)
(i32.const 10)
)
+ (i32.const 48)
)
- (local.set $4
- (global.get $tempRet0)
+ )
+ (local.set $0
+ (call $___udivdi3
+ (local.get $0)
+ (local.get $1)
+ (i32.const 10)
)
- (if (result i32)
- (i32.or
- (i32.and
- (i32.eq
- (local.get $1)
- (i32.const 9)
- )
- (i32.gt_u
- (local.get $0)
- (i32.const -1)
- )
- )
- (i32.gt_u
- (local.get $1)
- (i32.const 9)
- )
- )
- (block
- (local.set $0
- (local.get $3)
- )
- (local.set $1
- (local.get $4)
- )
- (br $while-in)
+ )
+ (local.set $3
+ (global.get $tempRet0)
+ )
+ (if
+ (i32.gt_u
+ (local.get $1)
+ (i32.const 9)
+ )
+ (block
+ (local.set $1
+ (local.get $3)
)
- (local.get $3)
+ (br $while-in)
)
)
)
diff --git a/test/emcc_hello_world.fromasm.clamp b/test/emcc_hello_world.fromasm.clamp
index fecd5a564..d3b16ddc2 100644
--- a/test/emcc_hello_world.fromasm.clamp
+++ b/test/emcc_hello_world.fromasm.clamp
@@ -7169,78 +7169,48 @@
)
(func $_fmt_u (; has Stack IR ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(local $3 i32)
- (local $4 i32)
(if
- (i32.or
- (i32.and
- (i32.eqz
- (local.get $1)
- )
- (i32.gt_u
- (local.get $0)
- (i32.const -1)
- )
- )
- (i32.gt_u
- (local.get $1)
- (i32.const 0)
- )
+ (i32.gt_u
+ (local.get $1)
+ (i32.const 0)
)
- (local.set $0
- (loop $while-in (result i32)
- (i32.store8
- (local.tee $2
- (i32.add
- (local.get $2)
- (i32.const -1)
- )
- )
- (i32.or
- (call $___uremdi3
- (local.get $0)
- (local.get $1)
- (i32.const 10)
- )
- (i32.const 48)
+ (loop $while-in
+ (i32.store8
+ (local.tee $2
+ (i32.add
+ (local.get $2)
+ (i32.const -1)
)
)
- (local.set $3
- (call $___udivdi3
+ (i32.or
+ (call $___uremdi3
(local.get $0)
(local.get $1)
(i32.const 10)
)
+ (i32.const 48)
)
- (local.set $4
- (global.get $tempRet0)
+ )
+ (local.set $0
+ (call $___udivdi3
+ (local.get $0)
+ (local.get $1)
+ (i32.const 10)
)
- (if (result i32)
- (i32.or
- (i32.and
- (i32.eq
- (local.get $1)
- (i32.const 9)
- )
- (i32.gt_u
- (local.get $0)
- (i32.const -1)
- )
- )
- (i32.gt_u
- (local.get $1)
- (i32.const 9)
- )
- )
- (block
- (local.set $0
- (local.get $3)
- )
- (local.set $1
- (local.get $4)
- )
- (br $while-in)
+ )
+ (local.set $3
+ (global.get $tempRet0)
+ )
+ (if
+ (i32.gt_u
+ (local.get $1)
+ (i32.const 9)
+ )
+ (block
+ (local.set $1
+ (local.get $3)
)
- (local.get $3)
+ (br $while-in)
)
)
)
diff --git a/test/emcc_hello_world.fromasm.imprecise b/test/emcc_hello_world.fromasm.imprecise
index 4c5d7afd2..ce1db8ea2 100644
--- a/test/emcc_hello_world.fromasm.imprecise
+++ b/test/emcc_hello_world.fromasm.imprecise
@@ -7014,78 +7014,48 @@
)
(func $_fmt_u (; has Stack IR ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(local $3 i32)
- (local $4 i32)
(if
- (i32.or
- (i32.and
- (i32.eqz
- (local.get $1)
- )
- (i32.gt_u
- (local.get $0)
- (i32.const -1)
- )
- )
- (i32.gt_u
- (local.get $1)
- (i32.const 0)
- )
+ (i32.gt_u
+ (local.get $1)
+ (i32.const 0)
)
- (local.set $0
- (loop $while-in (result i32)
- (i32.store8
- (local.tee $2
- (i32.add
- (local.get $2)
- (i32.const -1)
- )
- )
- (i32.or
- (call $___uremdi3
- (local.get $0)
- (local.get $1)
- (i32.const 10)
- )
- (i32.const 48)
+ (loop $while-in
+ (i32.store8
+ (local.tee $2
+ (i32.add
+ (local.get $2)
+ (i32.const -1)
)
)
- (local.set $3
- (call $___udivdi3
+ (i32.or
+ (call $___uremdi3
(local.get $0)
(local.get $1)
(i32.const 10)
)
+ (i32.const 48)
)
- (local.set $4
- (global.get $tempRet0)
+ )
+ (local.set $0
+ (call $___udivdi3
+ (local.get $0)
+ (local.get $1)
+ (i32.const 10)
)
- (if (result i32)
- (i32.or
- (i32.and
- (i32.eq
- (local.get $1)
- (i32.const 9)
- )
- (i32.gt_u
- (local.get $0)
- (i32.const -1)
- )
- )
- (i32.gt_u
- (local.get $1)
- (i32.const 9)
- )
- )
- (block
- (local.set $0
- (local.get $3)
- )
- (local.set $1
- (local.get $4)
- )
- (br $while-in)
+ )
+ (local.set $3
+ (global.get $tempRet0)
+ )
+ (if
+ (i32.gt_u
+ (local.get $1)
+ (i32.const 9)
+ )
+ (block
+ (local.set $1
+ (local.get $3)
)
- (local.get $3)
+ (br $while-in)
)
)
)
diff --git a/test/passes/inlining-optimizing_optimize-level=3.txt b/test/passes/inlining-optimizing_optimize-level=3.txt
index f951319de..bcb7db0bd 100644
--- a/test/passes/inlining-optimizing_optimize-level=3.txt
+++ b/test/passes/inlining-optimizing_optimize-level=3.txt
@@ -7348,88 +7348,56 @@
)
(func $_fmt_u (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(local $3 i32)
- (local $4 i32)
(if
- (block (result i32)
- (if
- (i32.or
- (i32.and
- (i32.eqz
- (local.get $1)
- )
- (i32.gt_u
- (local.get $0)
- (i32.const -1)
- )
+ (i32.gt_u
+ (local.get $1)
+ (i32.const 0)
+ )
+ (loop $while-in
+ (i32.store8
+ (local.tee $2
+ (i32.add
+ (local.get $2)
+ (i32.const -1)
)
- (i32.gt_u
+ )
+ (i32.or
+ (call $___uremdi3
+ (local.get $0)
(local.get $1)
+ (i32.const 10)
(i32.const 0)
)
+ (i32.const 48)
)
- (local.set $0
- (loop $while-in (result i32)
- (i32.store8
- (local.tee $2
- (i32.add
- (local.get $2)
- (i32.const -1)
- )
- )
- (i32.or
- (call $___uremdi3
- (local.get $0)
- (local.get $1)
- (i32.const 10)
- (i32.const 0)
- )
- (i32.const 48)
- )
- )
- (local.set $3
- (call $___udivdi3
- (local.get $0)
- (local.get $1)
- (i32.const 10)
- (i32.const 0)
- )
- )
- (local.set $4
- (global.get $tempRet0)
- )
- (if (result i32)
- (i32.or
- (i32.and
- (i32.eq
- (local.get $1)
- (i32.const 9)
- )
- (i32.gt_u
- (local.get $0)
- (i32.const -1)
- )
- )
- (i32.gt_u
- (local.get $1)
- (i32.const 9)
- )
- )
- (block
- (local.set $0
- (local.get $3)
- )
- (local.set $1
- (local.get $4)
- )
- (br $while-in)
- )
- (local.get $3)
- )
+ )
+ (local.set $0
+ (call $___udivdi3
+ (local.get $0)
+ (local.get $1)
+ (i32.const 10)
+ (i32.const 0)
+ )
+ )
+ (local.set $3
+ (global.get $tempRet0)
+ )
+ (if
+ (i32.gt_u
+ (local.get $1)
+ (i32.const 9)
+ )
+ (block
+ (local.set $1
+ (local.get $3)
)
+ (br $while-in)
)
)
- (local.get $0)
)
+ )
+ (if
+ (local.get $0)
(loop $while-in1
(i32.store8
(local.tee $2
diff --git a/test/passes/optimize-instructions_all-features.txt b/test/passes/optimize-instructions_all-features.txt
index e04bc4eb4..8da31f107 100644
--- a/test/passes/optimize-instructions_all-features.txt
+++ b/test/passes/optimize-instructions_all-features.txt
@@ -3,14 +3,14 @@
(type $i32_=>_i32 (func (param i32) (result i32)))
(type $none_=>_i32 (func (result i32)))
(type $none_=>_none (func))
+ (type $i32_i64_=>_none (func (param i32 i64)))
(type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
(type $i32_=>_none (func (param i32)))
- (type $i32_i64_=>_none (func (param i32 i64)))
(type $none_=>_i64 (func (result i64)))
- (type $i32_i64_f32_=>_none (func (param i32 i64 f32)))
(type $i64_=>_i64 (func (param i64) (result i64)))
- (type $i32_i32_f64_f64_=>_none (func (param i32 i32 f64 f64)))
+ (type $i32_i64_f32_=>_none (func (param i32 i64 f32)))
(type $i32_i64_f32_f64_=>_none (func (param i32 i64 f32 f64)))
+ (type $i32_i32_f64_f64_=>_none (func (param i32 i32 f64 f64)))
(type $i32_i64_f64_i32_=>_none (func (param i32 i64 f64 i32)))
(type $none_=>_f64 (func (result f64)))
(type $none_=>_externref (func (result externref)))
@@ -2521,9 +2521,9 @@
)
)
)
- (func $mul-power-2 (param $x i32) (result i32)
+ (func $mul-32-power-2 (param $x i32) (result i32)
(drop
- (call $mul-power-2
+ (call $mul-32-power-2
(i32.shl
(local.get $x)
(i32.const 2)
@@ -2531,7 +2531,7 @@
)
)
(drop
- (call $mul-power-2
+ (call $mul-32-power-2
(i32.mul
(local.get $x)
(i32.const 5)
@@ -2539,19 +2539,19 @@
)
)
(drop
- (call $mul-power-2
+ (call $mul-32-power-2
(local.get $x)
)
)
(drop
- (call $mul-power-2
+ (call $mul-32-power-2
(i32.const 0)
)
)
(drop
- (call $mul-power-2
+ (call $mul-32-power-2
(i32.mul
- (call $mul-power-2
+ (call $mul-32-power-2
(i32.const 123)
)
(i32.const 0)
@@ -2559,15 +2559,15 @@
)
)
(drop
- (call $mul-power-2
- (i32.mul
+ (call $mul-32-power-2
+ (i32.sub
+ (i32.const 0)
(local.get $x)
- (i32.const -1)
)
)
)
(drop
- (call $mul-power-2
+ (call $mul-32-power-2
(i32.shl
(local.get $x)
(i32.const 31)
@@ -2576,9 +2576,122 @@
)
(unreachable)
)
- (func $urem-power-2 (param $x i32) (result i32)
+ (func $mul-64-power-2 (param $x i64) (result i64)
+ (drop
+ (call $mul-64-power-2
+ (i64.shl
+ (local.get $x)
+ (i64.const 2)
+ )
+ )
+ )
+ (drop
+ (call $mul-64-power-2
+ (i64.mul
+ (local.get $x)
+ (i64.const 5)
+ )
+ )
+ )
+ (drop
+ (call $mul-64-power-2
+ (local.get $x)
+ )
+ )
+ (drop
+ (call $mul-64-power-2
+ (i64.const 0)
+ )
+ )
+ (drop
+ (call $mul-64-power-2
+ (i64.mul
+ (call $mul-64-power-2
+ (i64.const 123)
+ )
+ (i64.const 0)
+ )
+ )
+ )
+ (drop
+ (call $mul-64-power-2
+ (i64.sub
+ (i64.const 0)
+ (local.get $x)
+ )
+ )
+ )
+ (drop
+ (call $mul-64-power-2
+ (i64.shl
+ (local.get $x)
+ (i64.const 63)
+ )
+ )
+ )
+ (unreachable)
+ )
+ (func $div-32-power-2 (param $x i32) (result i32)
(drop
- (call $urem-power-2
+ (call $div-32-power-2
+ (i32.shr_u
+ (local.get $x)
+ (i32.const 2)
+ )
+ )
+ )
+ (drop
+ (call $div-32-power-2
+ (i32.div_u
+ (local.get $x)
+ (i32.const 5)
+ )
+ )
+ )
+ (drop
+ (call $div-32-power-2
+ (local.get $x)
+ )
+ )
+ (drop
+ (call $div-32-power-2
+ (i32.div_u
+ (local.get $x)
+ (i32.const 0)
+ )
+ )
+ )
+ (drop
+ (call $div-32-power-2
+ (i32.div_u
+ (call $div-32-power-2
+ (i32.const 123)
+ )
+ (i32.const 0)
+ )
+ )
+ )
+ (drop
+ (call $div-32-power-2
+ (i32.eq
+ (local.get $x)
+ (i32.const -1)
+ )
+ )
+ )
+ (drop
+ (call $div-32-power-2
+ (i32.shr_u
+ (local.get $x)
+ (i32.const 31)
+ )
+ )
+ )
+ (unreachable)
+ )
+ (func $urem-32-power-2 (param $x i32) (result i32)
+ (drop
+ (call $urem-32-power-2
(i32.and
(local.get $x)
(i32.const 3)
@@ -2586,7 +2699,7 @@
)
)
(drop
- (call $urem-power-2
+ (call $urem-32-power-2
(i32.rem_u
(local.get $x)
(i32.const 5)
@@ -2594,12 +2707,12 @@
)
)
(drop
- (call $urem-power-2
+ (call $urem-32-power-2
(i32.const 0)
)
)
(drop
- (call $urem-power-2
+ (call $urem-32-power-2
(i32.rem_u
(local.get $x)
(i32.const 0)
@@ -2607,7 +2720,7 @@
)
)
(drop
- (call $urem-power-2
+ (call $urem-32-power-2
(i32.rem_u
(local.get $x)
(i32.const -1)
@@ -2615,15 +2728,28 @@
)
)
(drop
- (call $urem-power-2
+ (call $urem-32-power-2
(i32.and
(local.get $x)
(i32.const 2147483647)
)
)
)
+ (drop
+ (call $urem-32-power-2
+ (i32.const 0)
+ )
+ )
(unreachable)
)
+ (func $srem-by-1 (param $x i32) (param $y i64)
+ (drop
+ (i32.const 0)
+ )
+ (drop
+ (i64.const 0)
+ )
+ )
(func $orZero (param $0 i32) (result i32)
(local.get $0)
)
@@ -2739,15 +2865,15 @@
)
)
(drop
- (i32.mul
+ (i32.sub
+ (i32.const 0)
(local.get $x32)
- (i32.const -1)
)
)
(drop
- (i64.mul
+ (i64.sub
+ (i64.const 0)
(local.get $x64)
- (i64.const -1)
)
)
(drop
@@ -3254,6 +3380,97 @@
(i32.const 2)
)
)
+ (func $rhs-is-neg-one (param $x i32) (param $y i64) (param $fx f32) (param $fy f64)
+ (drop
+ (i32.sub
+ (local.get $x)
+ (i32.const -1)
+ )
+ )
+ (drop
+ (i64.sub
+ (local.get $y)
+ (i64.const -1)
+ )
+ )
+ (drop
+ (i32.const 0)
+ )
+ (drop
+ (i32.const 0)
+ )
+ (drop
+ (i32.gt_s
+ (local.get $x)
+ (i32.const -1)
+ )
+ )
+ (drop
+ (i64.gt_s
+ (local.get $y)
+ (i64.const -1)
+ )
+ )
+ (drop
+ (i64.extend_i32_s
+ (i32.const 0)
+ )
+ )
+ (drop
+ (i32.const 1)
+ )
+ (drop
+ (i32.const 1)
+ )
+ (drop
+ (i32.le_s
+ (local.get $x)
+ (i32.const -1)
+ )
+ )
+ (drop
+ (i64.le_s
+ (local.get $y)
+ (i64.const -1)
+ )
+ )
+ (drop
+ (i32.sub
+ (i32.const 0)
+ (local.get $x)
+ )
+ )
+ (drop
+ (i64.sub
+ (i64.const 0)
+ (local.get $y)
+ )
+ )
+ (drop
+ (f32.mul
+ (local.get $fx)
+ (f32.const -1)
+ )
+ )
+ (drop
+ (f64.mul
+ (local.get $fy)
+ (f64.const -1)
+ )
+ )
+ (drop
+ (i32.eq
+ (local.get $x)
+ (i32.const -1)
+ )
+ )
+ (drop
+ (i64.div_u
+ (local.get $y)
+ (i64.const -1)
+ )
+ )
+ )
(func $pre-combine-or (param $x i32) (param $y i32)
(drop
(i32.ge_s
diff --git a/test/passes/optimize-instructions_all-features.wast b/test/passes/optimize-instructions_all-features.wast
index 8de7d4819..a0fff2936 100644
--- a/test/passes/optimize-instructions_all-features.wast
+++ b/test/passes/optimize-instructions_all-features.wast
@@ -2856,9 +2856,9 @@
)
)
)
- (func $mul-power-2 (param $x i32) (result i32)
+ (func $mul-32-power-2 (param $x i32) (result i32)
(drop
- (call $mul-power-2
+ (call $mul-32-power-2
(i32.mul
(local.get $x)
(i32.const 4)
@@ -2866,7 +2866,7 @@
)
)
(drop
- (call $mul-power-2
+ (call $mul-32-power-2
(i32.mul
(local.get $x)
(i32.const 5)
@@ -2874,7 +2874,7 @@
)
)
(drop
- (call $mul-power-2
+ (call $mul-32-power-2
(i32.mul
(local.get $x)
(i32.const 1)
@@ -2882,7 +2882,7 @@
)
)
(drop
- (call $mul-power-2
+ (call $mul-32-power-2
(i32.mul
(local.get $x)
(i32.const 0)
@@ -2890,15 +2890,15 @@
)
)
(drop
- (call $mul-power-2
+ (call $mul-32-power-2
(i32.mul
- (call $mul-power-2 (i32.const 123)) ;; side effects
+ (call $mul-32-power-2 (i32.const 123)) ;; side effects
(i32.const 0)
)
)
)
(drop
- (call $mul-power-2
+ (call $mul-32-power-2
(i32.mul
(local.get $x)
(i32.const 0xffffffff)
@@ -2906,7 +2906,7 @@
)
)
(drop
- (call $mul-power-2
+ (call $mul-32-power-2
(i32.mul
(local.get $x)
(i32.const 0x80000000)
@@ -2915,9 +2915,127 @@
)
(unreachable)
)
- (func $urem-power-2 (param $x i32) (result i32)
+ (func $mul-64-power-2 (param $x i64) (result i64)
(drop
- (call $urem-power-2
+ (call $mul-64-power-2
+ (i64.mul
+ (local.get $x)
+ (i64.const 4)
+ )
+ )
+ )
+ (drop
+ (call $mul-64-power-2
+ (i64.mul
+ (local.get $x)
+ (i64.const 5)
+ )
+ )
+ )
+ (drop
+ (call $mul-64-power-2
+ (i64.mul
+ (local.get $x)
+ (i64.const 1)
+ )
+ )
+ )
+ (drop
+ (call $mul-64-power-2
+ (i64.mul
+ (local.get $x)
+ (i64.const 0)
+ )
+ )
+ )
+ (drop
+ (call $mul-64-power-2
+ (i64.mul
+ (call $mul-64-power-2 (i64.const 123)) ;; side effects
+ (i64.const 0)
+ )
+ )
+ )
+ (drop
+ (call $mul-64-power-2
+ (i64.mul
+ (local.get $x)
+ (i64.const 0xffffffffffffffff)
+ )
+ )
+ )
+ (drop
+ (call $mul-64-power-2
+ (i64.mul
+ (local.get $x)
+ (i64.const 0x8000000000000000)
+ )
+ )
+ )
+ (unreachable)
+ )
+ (func $div-32-power-2 (param $x i32) (result i32)
+ (drop
+ (call $div-32-power-2
+ (i32.div_u
+ (local.get $x)
+ (i32.const 4)
+ )
+ )
+ )
+ (drop
+ (call $div-32-power-2
+ (i32.div_u
+ (local.get $x)
+ (i32.const 5)
+ )
+ )
+ )
+ (drop
+ (call $div-32-power-2
+ (i32.div_u
+ (local.get $x)
+ (i32.const 1)
+ )
+ )
+ )
+ (drop
+ (call $div-32-power-2
+ (i32.div_u
+ (local.get $x)
+ (i32.const 0)
+ )
+ )
+ )
+ (drop
+ (call $div-32-power-2
+ (i32.div_u
+ (call $div-32-power-2 (i32.const 123)) ;; side effects
+ (i32.const 0)
+ )
+ )
+ )
+ (drop
+ (call $div-32-power-2
+ (i32.div_u
+ (local.get $x)
+ (i32.const 0xffffffff)
+ )
+ )
+ )
+ (drop
+ (call $div-32-power-2
+ (i32.div_u
+ (local.get $x)
+ (i32.const 0x80000000)
+ )
+ )
+ )
+ (unreachable)
+ )
+ (func $urem-32-power-2 (param $x i32) (result i32)
+ (drop
+ (call $urem-32-power-2
(i32.rem_u
(local.get $x)
(i32.const 4)
@@ -2925,7 +3043,7 @@
)
)
(drop
- (call $urem-power-2
+ (call $urem-32-power-2
(i32.rem_u
(local.get $x)
(i32.const 5)
@@ -2933,7 +3051,7 @@
)
)
(drop
- (call $urem-power-2
+ (call $urem-32-power-2
(i32.rem_u
(local.get $x)
(i32.const 1)
@@ -2941,7 +3059,7 @@
)
)
(drop
- (call $urem-power-2
+ (call $urem-32-power-2
(i32.rem_u
(local.get $x)
(i32.const 0)
@@ -2949,7 +3067,7 @@
)
)
(drop
- (call $urem-power-2
+ (call $urem-32-power-2
(i32.rem_u
(local.get $x)
(i32.const 0xffffffff)
@@ -2957,15 +3075,35 @@
)
)
(drop
- (call $urem-power-2
+ (call $urem-32-power-2
(i32.rem_u
(local.get $x)
(i32.const 0x80000000)
)
)
)
+ ;; (unsigned)x % 1
+ (drop
+ (call $urem-32-power-2
+ (i32.rem_u
+ (local.get $x)
+ (i32.const 1)
+ )
+ )
+ )
(unreachable)
)
+ (func $srem-by-1 (param $x i32) (param $y i64)
+ ;; (signed)x % 1
+ (drop (i32.rem_s
+ (local.get $x)
+ (i32.const 1)
+ ))
+ (drop (i64.rem_s
+ (local.get $y)
+ (i64.const 1)
+ ))
+ )
(func $orZero (param $0 i32) (result i32)
(i32.or
(local.get $0)
@@ -3703,6 +3841,81 @@
(i32.const 2)
)
)
+ (func $rhs-is-neg-one (param $x i32) (param $y i64) (param $fx f32) (param $fy f64)
+ (drop (i32.sub
+ (local.get $x)
+ (i32.const -1)
+ ))
+ (drop (i64.sub
+ (local.get $y)
+ (i64.const -1)
+ ))
+ (drop (i32.gt_u
+ (local.get $x)
+ (i32.const -1)
+ ))
+ (drop (i64.gt_u
+ (local.get $y)
+ (i64.const -1)
+ ))
+ (drop (i32.gt_s
+ (local.get $x)
+ (i32.const -1)
+ ))
+ (drop (i64.gt_s
+ (local.get $y)
+ (i64.const -1)
+ ))
+ (drop (i64.extend_i32_s
+ (i64.gt_u
+ (i64.const 0)
+ (i64.const -1)
+ )
+ ))
+ ;; (unsigned)x <= -1 ==> 1
+ (drop (i32.le_u
+ (local.get $x)
+ (i32.const -1)
+ ))
+ (drop (i64.le_u
+ (local.get $y)
+ (i64.const -1)
+ ))
+ (drop (i32.le_s
+ (local.get $x)
+ (i32.const -1)
+ ))
+ (drop (i64.le_s
+ (local.get $y)
+ (i64.const -1)
+ ))
+ ;; x * -1
+ (drop (i32.mul
+ (local.get $x)
+ (i32.const -1)
+ ))
+ (drop (i64.mul
+ (local.get $y)
+ (i64.const -1)
+ ))
+ (drop (f32.mul ;; skip
+ (local.get $fx)
+ (f32.const -1)
+ ))
+ (drop (f64.mul ;; skip
+ (local.get $fy)
+ (f64.const -1)
+ ))
+ ;; (unsigned)x / -1
+ (drop (i32.div_u
+ (local.get $x)
+ (i32.const -1)
+ ))
+ (drop (i64.div_u
+ (local.get $y)
+ (i64.const -1)
+ ))
+ )
(func $pre-combine-or (param $x i32) (param $y i32)
(drop (i32.or
(i32.gt_s
diff --git a/test/wasm2js/i64-ctz.2asm.js.opt b/test/wasm2js/i64-ctz.2asm.js.opt
index 6e1a54fae..b651dae29 100644
--- a/test/wasm2js/i64-ctz.2asm.js.opt
+++ b/test/wasm2js/i64-ctz.2asm.js.opt
@@ -40,7 +40,7 @@ function asmFunc(global, env, buffer) {
if ($0 | $1) {
$3 = $1 + -1 | 0;
$2 = $0 + -1 | 0;
- if ($2 >>> 0 < 4294967295) {
+ if (($2 | 0) != -1) {
$3 = $3 + 1 | 0
}
$2 = Math_clz32($0 ^ $2) + 32 | 0;
diff --git a/test/wasm2js/unary-ops.2asm.js.opt b/test/wasm2js/unary-ops.2asm.js.opt
index 180f89dd0..425e223ff 100644
--- a/test/wasm2js/unary-ops.2asm.js.opt
+++ b/test/wasm2js/unary-ops.2asm.js.opt
@@ -81,7 +81,7 @@ function asmFunc(global, env, buffer) {
if ($0 | $1_1) {
$3 = $1_1 + -1 | 0;
$2 = $0 + -1 | 0;
- if ($2 >>> 0 < 4294967295) {
+ if (($2 | 0) != -1) {
$3 = $3 + 1 | 0
}
$2 = Math_clz32($0 ^ $2) + 32 | 0;