summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ir/abstract.h7
-rw-r--r--src/passes/OptimizeInstructions.cpp35
-rw-r--r--test/passes/optimize-instructions_all-features.txt133
-rw-r--r--test/passes/optimize-instructions_all-features.wast120
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)