diff --git a/src/ir/abstract.h b/src/ir/abstract.h index e23ffad17ec..3071e6dd690 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 3e3863e954b..cbd8c932359 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -19,6 +19,7 @@ // #include +#include #include #include @@ -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 @@ struct OptimizeInstructions // 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()->value = Literal(int32_t(shifts)); + template Expression* optimizePowerOf2Mul(Binary* binary, T c) { + static_assert(std::is_same::value || + std::is_same::value, + "type mismatch"); + auto shifts = CountTrailingZeroes(c); + binary->op = std::is_same::value ? ShlInt32 : ShlInt64; + binary->right->cast()->value = Literal(static_cast(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()->value = Literal(int32_t(c - 1)); + template Expression* optimizePowerOf2UDiv(Binary* binary, T c) { + static_assert(std::is_same::value || + std::is_same::value, + "type mismatch"); + auto shifts = CountTrailingZeroes(c); + binary->op = std::is_same::value ? ShrUInt32 : ShrUInt64; + binary->right->cast()->value = Literal(static_cast(shifts)); + return binary; + } + + template Expression* optimizePowerOf2URem(Binary* binary, T c) { + static_assert(std::is_same::value || + std::is_same::value, + "type mismatch"); + binary->op = std::is_same::value ? AndInt32 : AndInt64; + binary->right->cast()->value = Literal(c - 1); return binary; } @@ -1327,8 +1363,9 @@ struct OptimizeInstructions auto type = binary->right->type; auto* right = binary->right->cast(); 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 @@ struct OptimizeInstructions 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 @@ struct OptimizeInstructions // 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 7a4223cd853..1da65a09f15 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 774740dc126..b66b70c560f 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 fecd5a564e0..d3b16ddc26d 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 4c5d7afd213..ce1db8ea212 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 f951319de58..bcb7db0bdd1 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 e04bc4eb42c..8da31f1077a 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 8de7d481998..a0fff2936f0 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 6e1a54fae58..b651dae2908 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 180f89dd0d1..425e223ffe9 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;