summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Graey <maxgraey@gmail.com>2021-07-22 21:16:45 +0300
committerGitHub <noreply@github.com>2021-07-22 11:16:45 -0700
commitf01fd8cad1cb1a6a80ef12bcfc19502bd51ddf46 (patch)
tree01d39d03bf29d7750ed7493715050338f82d4881
parentb9b8d74a4c646c4df7ddad5be195cff976cf6704 (diff)
downloadbinaryen-f01fd8cad1cb1a6a80ef12bcfc19502bd51ddf46.tar.gz
binaryen-f01fd8cad1cb1a6a80ef12bcfc19502bd51ddf46.tar.bz2
binaryen-f01fd8cad1cb1a6a80ef12bcfc19502bd51ddf46.zip
[Optimize Instructions] Simplify zero/sign extentions (special case) (#4009)
For signed or unsigned extension to 64-bits after lowering from partially filled 64-bit arguments: ```rust i64.extend_i32_u(i32.wrap_i64(x)) => x // where maxBits(x) <= 32 i64.extend_i32_s(i32.wrap_i64(x)) => x // where maxBits(x) <= 31 ```
-rw-r--r--src/passes/OptimizeInstructions.cpp34
-rw-r--r--test/lit/passes/optimize-instructions.wast53
2 files changed, 76 insertions, 11 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index 31ed9348a..2e6a2d48d 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -841,19 +841,35 @@ struct OptimizeInstructions
}
}
{
- Unary* inner;
+ // i64.extend_i32_s(i32.wrap_i64(x)) => x
+ // where maxBits(x) <= 31
+ //
+ // i64.extend_i32_u(i32.wrap_i64(x)) => x
+ // where maxBits(x) <= 32
Expression* x;
- if (getModule()->features.hasSignExt()) {
- // i64.extend_i32_s(i32.wrap_i64(x)) => i64.extend32_s(x)
- if (matches(curr,
- unary(ExtendSInt32, unary(&inner, WrapInt64, any(&x))))) {
- inner->op = ExtendS32Int64;
- inner->type = Type::i64;
- inner->value = x;
- return replaceCurrent(inner);
+ UnaryOp unaryOp;
+ if (matches(curr, unary(&unaryOp, unary(WrapInt64, any(&x))))) {
+ if (unaryOp == ExtendSInt32 || unaryOp == ExtendUInt32) {
+ auto maxBits = Bits::getMaxBits(x, this);
+ if ((unaryOp == ExtendSInt32 && maxBits <= 31) ||
+ (unaryOp == ExtendUInt32 && maxBits <= 32)) {
+ return replaceCurrent(x);
+ }
}
}
}
+ if (getModule()->features.hasSignExt()) {
+ // i64.extend_i32_s(i32.wrap_i64(x)) => i64.extend32_s(x)
+ Unary* inner;
+ Expression* x;
+ if (matches(curr,
+ unary(ExtendSInt32, unary(&inner, WrapInt64, any(&x))))) {
+ inner->op = ExtendS32Int64;
+ inner->type = Type::i64;
+ inner->value = x;
+ return replaceCurrent(inner);
+ }
+ }
}
if (Abstract::hasAnyReinterpret(curr->op)) {
diff --git a/test/lit/passes/optimize-instructions.wast b/test/lit/passes/optimize-instructions.wast
index 07f246b49..352e70e26 100644
--- a/test/lit/passes/optimize-instructions.wast
+++ b/test/lit/passes/optimize-instructions.wast
@@ -11252,7 +11252,7 @@
;; i32.wrap_i64(i64.extend_i32_s(x)) ==> x
;; i32.wrap_i64(i64.extend_i32_u(x)) ==> x
- ;; CHECK: (func $sign-and-zero-extention-elimination (param $x i32)
+ ;; CHECK: (func $sign-and-zero-extention-elimination-1 (param $x i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
@@ -11260,10 +11260,59 @@
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- (func $sign-and-zero-extention-elimination (param $x i32)
+ (func $sign-and-zero-extention-elimination-1 (param $x i32)
(drop (i32.wrap_i64 (i64.extend_i32_s (local.get $x))))
(drop (i32.wrap_i64 (i64.extend_i32_u (local.get $x))))
)
+ ;; i64.extend_i32_u(i32.wrap_i64(x)) => x, where maxBits(x) <= 32
+ ;; i64.extend_i32_s(i32.wrap_i64(x)) => x, where maxBits(x) <= 31
+
+ ;; CHECK: (func $sign-and-zero-extention-elimination-2 (param $x i64)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.and
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i64.const 4294967295)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.and
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i64.const 2147483647)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.extend_i32_u
+ ;; CHECK-NEXT: (i32.wrap_i64
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.extend_i32_s
+ ;; CHECK-NEXT: (i32.wrap_i64
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.extend_i32_s
+ ;; CHECK-NEXT: (i32.wrap_i64
+ ;; CHECK-NEXT: (i64.and
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i64.const 4294967295)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $sign-and-zero-extention-elimination-2 (param $x i64)
+ (drop (i64.extend_i32_u (i32.wrap_i64 (i64.and (local.get $x) (i64.const 0x00000000FFFFFFFF)))))
+ (drop (i64.extend_i32_s (i32.wrap_i64 (i64.and (local.get $x) (i64.const 0x000000007FFFFFFF)))))
+
+ (drop (i64.extend_i32_u (i32.wrap_i64 (local.get $x)))) ;; skip
+ (drop (i64.extend_i32_s (i32.wrap_i64 (local.get $x)))) ;; skip
+ (drop (i64.extend_i32_s (i32.wrap_i64 (i64.and (local.get $x) (i64.const 0x00000000FFFFFFFF))))) ;; skip
+ )
;; CHECK: (func $optimize-shifts (param $x i32) (param $y i32) (param $z i64) (param $w i64)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $x)