diff options
author | Max Graey <maxgraey@gmail.com> | 2020-10-30 08:08:48 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-29 23:08:48 -0700 |
commit | 5fc27e20479edfef0674c89e9bb7888ee25cb054 (patch) | |
tree | a748191c55e48d91bbc3d01ed64e6d3de0762c66 | |
parent | 25e47f2c3e7ca8151377075432b34c95073acaca (diff) | |
download | binaryen-5fc27e20479edfef0674c89e9bb7888ee25cb054.tar.gz binaryen-5fc27e20479edfef0674c89e9bb7888ee25cb054.tar.bz2 binaryen-5fc27e20479edfef0674c89e9bb7888ee25cb054.zip |
Fold subtraction of sums or differences from constants (#3295)
`C1 - (x + C2)` -> `(C1 - C2) - x`
`C1 - (x - C2)` -> `(C1 + C2) - x`
`C1 - (C2 - x)` -> `x + (C1 - C2)`
-rw-r--r-- | src/literal.h | 12 | ||||
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 33 | ||||
-rw-r--r-- | test/passes/optimize-instructions_all-features.txt | 44 | ||||
-rw-r--r-- | test/passes/optimize-instructions_all-features.wast | 55 |
4 files changed, 144 insertions, 0 deletions
diff --git a/src/literal.h b/src/literal.h index d94d1a6d0..625b3eb43 100644 --- a/src/literal.h +++ b/src/literal.h @@ -114,6 +114,18 @@ public: WASM_UNREACHABLE("unexpected type"); } } + bool isNegative() const { + switch (type.getBasic()) { + case Type::i32: + case Type::f32: + return i32 < 0; + case Type::i64: + case Type::f64: + return i64 < 0; + default: + WASM_UNREACHABLE("unexpected type"); + } + } bool isSignedMin() const { switch (type.getBasic()) { case Type::i32: diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 57ef42913..20cdeee19 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -1734,6 +1734,39 @@ private: return curr->left; } { + // C1 - (x + C2) ==> (C1 - C2) - x + Const *c1, *c2; + Expression* x; + if (matches(curr, + binary(Sub, ival(&c1), binary(Add, any(&x), ival(&c2))))) { + left->value = c1->value.sub(c2->value); + curr->right = x; + return curr; + } + // C1 - (x - C2) ==> (C1 + C2) - x + if (matches(curr, + binary(Sub, ival(&c1), binary(Sub, any(&x), ival(&c2))))) { + left->value = c1->value.add(c2->value); + curr->right = x; + return curr; + } + // C1 - (C2 - x) ==> x + (C1 - C2) + if (matches(curr, + binary(Sub, ival(&c1), binary(Sub, ival(&c2), any(&x))))) { + left->value = c1->value.sub(c2->value); + if (left->value.isNegative()) { + // -C1 - (C2 - x) ==> x - (C1 - C2) + left->value = left->value.neg(); + curr->op = Abstract::getBinary(type, Sub); + } else { + curr->op = Abstract::getBinary(type, Add); + } + curr->right = x; + std::swap(curr->left, curr->right); + return curr; + } + } + { // fval(C) / -x ==> -C / x Expression* right; if (matches(curr, binary(DivS, fval(), unary(Neg, any(&right))))) { diff --git a/test/passes/optimize-instructions_all-features.txt b/test/passes/optimize-instructions_all-features.txt index 96346ed22..522bd6fe8 100644 --- a/test/passes/optimize-instructions_all-features.txt +++ b/test/passes/optimize-instructions_all-features.txt @@ -4391,6 +4391,50 @@ ) ) ) + (func $lhs-is-const (param $x i32) (param $y i64) + (drop + (i32.sub + (i32.const 1) + (local.get $x) + ) + ) + (drop + (i64.sub + (i64.const 1) + (local.get $y) + ) + ) + (drop + (i32.sub + (i32.const -2) + (local.get $x) + ) + ) + (drop + (i64.sub + (i64.const -2) + (local.get $y) + ) + ) + (drop + (i32.sub + (local.get $x) + (i32.const 1) + ) + ) + (drop + (i64.sub + (local.get $y) + (i64.const 1) + ) + ) + (drop + (i32.sub + (local.get $x) + (i32.const -2147483648) + ) + ) + ) (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 cdb3c56f2..9b172e4bd 100644 --- a/test/passes/optimize-instructions_all-features.wast +++ b/test/passes/optimize-instructions_all-features.wast @@ -4842,6 +4842,61 @@ (local.get $x) )) ) + (func $lhs-is-const (param $x i32) (param $y i64) + ;; 0 - (x - 1) + (drop (i32.sub + (i32.const 0) + (i32.sub + (local.get $x) + (i32.const 1) + ) + )) + (drop (i64.sub + (i64.const 0) + (i64.sub + (local.get $y) + (i64.const 1) + ) + )) + ;; -1 - (x + 1) + (drop (i32.sub + (i32.const -1) + (i32.add + (local.get $x) + (i32.const 1) + ) + )) + (drop (i64.sub + (i64.const -1) + (i64.add + (local.get $y) + (i64.const 1) + ) + )) + ;; 1 - (2 - x) + (drop (i32.sub + (i32.const 1) + (i32.sub + (i32.const 2) + (local.get $x) + ) + )) + (drop (i64.sub + (i64.const 1) + (i64.sub + (i64.const 2) + (local.get $y) + ) + )) + ;; 0 - (0x80000000 - x) + (drop (i32.sub + (i32.const 0) + (i32.sub + (i32.const 0x80000000) + (local.get $x) + ) + )) + ) (func $pre-combine-or (param $x i32) (param $y i32) (drop (i32.or (i32.gt_s |