diff options
-rw-r--r-- | src/ir/abstract.h | 7 | ||||
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 35 | ||||
-rw-r--r-- | test/passes/optimize-instructions_all-features.txt | 133 | ||||
-rw-r--r-- | test/passes/optimize-instructions_all-features.wast | 120 |
4 files changed, 273 insertions, 22 deletions
diff --git a/src/ir/abstract.h b/src/ir/abstract.h index 1cd51b9ba..2bb764aeb 100644 --- a/src/ir/abstract.h +++ b/src/ir/abstract.h @@ -59,6 +59,13 @@ enum Op { GeU }; +inline bool hasAnyShift(BinaryOp op) { + return op == ShlInt32 || op == ShrSInt32 || op == ShrUInt32 || + op == RotLInt32 || op == RotRInt32 || op == ShlInt64 || + op == ShrSInt64 || op == ShrUInt64 || op == RotLInt64 || + op == RotRInt64; +} + // Provide a wasm type and an abstract op and get the concrete one. For example, // you can provide i32 and Add and receive the specific opcode for a 32-bit // addition, AddInt32. If the op does not exist, it returns Invalid. diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index c54960079..59a38eeaa 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -350,6 +350,41 @@ struct OptimizeInstructions return inner; } } + { + // x <<>> (C & (31 | 63)) ==> x <<>> C' + // x <<>> (y & (31 | 63)) ==> x <<>> y + // where '<<>>': + // '<<', '>>', '>>>'. 'rotl' or 'rotr' + BinaryOp op; + Const* c; + Expression *x, *y; + + // x <<>> C + if (matches(curr, binary(&op, any(&x), ival(&c))) && + Abstract::hasAnyShift(op)) { + // truncate RHS constant to effective size as: + // i32(x) <<>> const(C & 31)) + // i64(x) <<>> const(C & 63)) + c->value = c->value.and_( + Literal::makeFromInt32(c->type.getByteSize() * 8 - 1, c->type)); + // x <<>> 0 ==> x + if (c->value.isZero()) { + return x; + } + } + if (matches( + curr, + binary(&op, any(&x), binary(Abstract::And, any(&y), ival(&c)))) && + Abstract::hasAnyShift(op)) { + // i32(x) <<>> (y & 31) ==> x <<>> y + // i64(x) <<>> (y & 63) ==> x <<>> y + if ((c->type == Type::i32 && (c->value.geti32() & 31) == 31) || + (c->type == Type::i64 && (c->value.geti64() & 63LL) == 63LL)) { + curr->cast<Binary>()->right = y; + return curr; + } + } + } } if (auto* select = curr->dynCast<Select>()) { diff --git a/test/passes/optimize-instructions_all-features.txt b/test/passes/optimize-instructions_all-features.txt index e12afcca4..d4ff1ead6 100644 --- a/test/passes/optimize-instructions_all-features.txt +++ b/test/passes/optimize-instructions_all-features.txt @@ -8,12 +8,12 @@ (type $i32_=>_none (func (param i32))) (type $none_=>_i64 (func (result i64))) (type $i64_=>_i64 (func (param i64) (result i64))) + (type $i32_i32_i64_i64_=>_none (func (param i32 i32 i64 i64))) (type $i32_i64_f32_=>_none (func (param i32 i64 f32))) (type $i32_i64_f32_f64_=>_none (func (param i32 i64 f32 f64))) (type $none_=>_anyref (func (result anyref))) (type $i32_i32_i32_=>_none (func (param i32 i32 i32))) (type $i32_i32_i32_f64_=>_none (func (param i32 i32 i32 f64))) - (type $i32_i32_i64_i64_=>_none (func (param i32 i32 i64 i64))) (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 $f32_f64_=>_none (func (param f32 f64))) @@ -992,7 +992,7 @@ (drop (i32.shr_u (i32.const 128) - (i32.const 35) + (i32.const 3) ) ) (drop @@ -1016,16 +1016,13 @@ (drop (i32.shr_u (i32.const 128) - (i32.const 35) + (i32.const 3) ) ) (drop (i32.shr_s (i32.shl - (i32.shr_s - (i32.const -1) - (i32.const 32) - ) + (i32.const -1) (i32.const 24) ) (i32.const 24) @@ -1336,7 +1333,7 @@ (local.get $0) (i32.const 11) ) - (i32.const 200) + (i32.const 8) ) ) ) @@ -2270,19 +2267,13 @@ ) (func $neg-shifts-and-255 (result i32) (i32.and - (i32.shr_u - (i32.const -99) - (i32.const -32) - ) + (i32.const -99) (i32.const 255) ) ) (func $neg-shifts-and-255-b (result i32) (i32.and - (i32.shl - (i32.const -2349025) - (i32.const -32) - ) + (i32.const -2349025) (i32.const 255) ) ) @@ -2290,9 +2281,9 @@ (i32.shr_u (i32.shr_u (local.get $x) - (i32.const 65535) + (i32.const 31) ) - (i32.const 32767) + (i32.const 31) ) ) (func $shifts-square-no-overflow-small (param $x i32) (result i32) @@ -2305,9 +2296,9 @@ (i64.shr_u (i64.shr_u (local.get $x) - (i64.const 65535) + (i64.const 63) ) - (i64.const 64767) + (i64.const 63) ) ) (func $shifts-square-no-overflow-small-64 (param $x i64) (result i64) @@ -2329,9 +2320,9 @@ (i32.shr_u (i32.shl (i32.const 23) - (i32.const -61) + (i32.const 3) ) - (i32.const 168) + (i32.const 8) ) ) (func $actually-no-shifts (result i32) @@ -4439,6 +4430,104 @@ ) ) ) + (func $optimize-shifts (param $x i32) (param $y i32) (param $z i64) (param $w i64) + (drop + (local.get $x) + ) + (drop + (local.get $x) + ) + (drop + (local.get $x) + ) + (drop + (local.get $x) + ) + (drop + (local.get $x) + ) + (drop + (local.get $z) + ) + (drop + (local.get $z) + ) + (drop + (local.get $z) + ) + (drop + (local.get $z) + ) + (drop + (local.get $z) + ) + (drop + (i32.shl + (local.get $x) + (local.get $y) + ) + ) + (drop + (i32.shl + (local.get $x) + (local.get $y) + ) + ) + (drop + (i32.shr_s + (local.get $x) + (local.get $y) + ) + ) + (drop + (i32.shr_u + (local.get $x) + (local.get $y) + ) + ) + (drop + (i64.shl + (local.get $z) + (local.get $w) + ) + ) + (drop + (i64.shl + (local.get $z) + (local.get $w) + ) + ) + (drop + (i64.shr_s + (local.get $z) + (local.get $w) + ) + ) + (drop + (i64.shr_u + (local.get $z) + (local.get $w) + ) + ) + (drop + (i32.shl + (local.get $x) + (i32.and + (local.get $y) + (i32.const 32) + ) + ) + ) + (drop + (i64.shr_u + (local.get $z) + (i64.and + (local.get $w) + (i64.const 31) + ) + ) + ) + ) (func $optimize-bulk-memory-copy (param $dst i32) (param $src i32) (param $sz i32) (memory.copy (local.get $dst) diff --git a/test/passes/optimize-instructions_all-features.wast b/test/passes/optimize-instructions_all-features.wast index 05e0e37c3..505f89ea2 100644 --- a/test/passes/optimize-instructions_all-features.wast +++ b/test/passes/optimize-instructions_all-features.wast @@ -4924,6 +4924,126 @@ ) ) ) + (func $optimize-shifts (param $x i32) (param $y i32) (param $z i64) (param $w i64) + ;; i32 + (drop (i32.shl + (local.get $x) + (i32.const 32) + )) + (drop (i32.shr_s + (local.get $x) + (i32.const 32) + )) + (drop (i32.shr_u + (local.get $x) + (i32.const 64) + )) + (drop (i32.rotl + (local.get $x) + (i32.const 64) + )) + (drop (i32.rotr + (local.get $x) + (i32.const 64) + )) + ;; i64 + (drop (i64.shl + (local.get $z) + (i64.const 64) + )) + (drop (i64.shr_s + (local.get $z) + (i64.const 64) + )) + (drop (i64.shr_u + (local.get $z) + (i64.const 128) + )) + (drop (i64.rotl + (local.get $z) + (i64.const 128) + )) + (drop (i64.rotr + (local.get $z) + (i64.const 128) + )) + + ;; i32 + (drop (i32.shl + (local.get $x) + (i32.and + (local.get $y) + (i32.const 31) + ) + )) + (drop (i32.shl + (local.get $x) + (i32.and + (local.get $y) + (i32.const 63) + ) + )) + (drop (i32.shr_s + (local.get $x) + (i32.and + (local.get $y) + (i32.const 31) + ) + )) + (drop (i32.shr_u + (local.get $x) + (i32.and + (local.get $y) + (i32.const 31) + ) + )) + ;; i64 + (drop (i64.shl + (local.get $z) + (i64.and + (local.get $w) + (i64.const 63) + ) + )) + (drop (i64.shl + (local.get $z) + (i64.and + (local.get $w) + (i64.const 127) + ) + )) + (drop (i64.shr_s + (local.get $z) + (i64.and + (local.get $w) + (i64.const 63) + ) + )) + (drop (i64.shr_u + (local.get $z) + (i64.and + (local.get $w) + (i64.const 63) + ) + )) + + ;; skip + (drop (i32.shl + (local.get $x) + (i32.and + (local.get $y) + (i32.const 32) + ) + )) + ;; skip + (drop (i64.shr_u + (local.get $z) + (i64.and + (local.get $w) + (i64.const 31) + ) + )) + ) (func $optimize-bulk-memory-copy (param $dst i32) (param $src i32) (param $sz i32) (memory.copy ;; skip (local.get $dst) |