diff options
author | Alon Zakai <alonzakai@gmail.com> | 2018-04-11 18:46:48 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-11 18:46:48 -0700 |
commit | a9d59bd033e98d6399a7efab81a57aafcf241be3 (patch) | |
tree | ea52e4acc7439caf5fd49b0ab27018792146d807 | |
parent | 61388bbd1fe6ef472e656298483efa2d81cd9ed3 (diff) | |
download | binaryen-a9d59bd033e98d6399a7efab81a57aafcf241be3.tar.gz binaryen-a9d59bd033e98d6399a7efab81a57aafcf241be3.tar.bz2 binaryen-a9d59bd033e98d6399a7efab81a57aafcf241be3.zip |
More math opts (#1507)
`xor` of 0, `and` and `or` of -1
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 23 | ||||
-rw-r--r-- | test/passes/optimize-instructions.txt | 27 | ||||
-rw-r--r-- | test/passes/optimize-instructions.wast | 42 |
3 files changed, 89 insertions, 3 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 3e7c15720..293adcbde 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -1120,7 +1120,8 @@ private: if (binary->op == Abstract::getBinary(type, Abstract::Shl) || binary->op == Abstract::getBinary(type, Abstract::ShrU) || binary->op == Abstract::getBinary(type, Abstract::ShrS) || - binary->op == Abstract::getBinary(type, Abstract::Or)) { + binary->op == Abstract::getBinary(type, Abstract::Or) || + binary->op == Abstract::getBinary(type, Abstract::Xor)) { return binary->left; } else if ((binary->op == Abstract::getBinary(type, Abstract::Mul) || binary->op == Abstract::getBinary(type, Abstract::And)) && @@ -1128,9 +1129,23 @@ private: return binary->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 (binary->op == Abstract::getBinary(type, Abstract::And)) { + return binary->left; + } else if (binary->op == Abstract::getBinary(type, Abstract::Or) && + !EffectAnalyzer(getPassOptions(), binary->left).hasSideEffects()) { + return binary->right; + } + } // wasm binary encoding uses signed LEBs, which slightly favor negative - // numbers: -64 is more efficient than +64 etc. we therefore prefer - // x - -64 over x + 64 + // numbers: -64 is more efficient than +64 etc., as well as other powers + // of two 7 bits etc. higher. we therefore prefer x - -64 over x + 64. + // in theory we could just prefer negative numbers over positive, but + // that can have bad effects on gzip compression (as it would mean more + // 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(); @@ -1149,6 +1164,7 @@ private: } else { binary->op = Abstract::getBinary(type, Abstract::Add); } + return binary; } } } @@ -1240,6 +1256,7 @@ private: // given a binary expression with equal children and no side effects in either, // we can fold various things + // TODO: trinaries, things like (x & (y & x)) ? Expression* optimizeBinaryWithEqualEffectlessChildren(Binary* binary) { // TODO add: perhaps worth doing 2*x if x is quite large? switch (binary->op) { diff --git a/test/passes/optimize-instructions.txt b/test/passes/optimize-instructions.txt index b1b4ce2d2..bc7221d3f 100644 --- a/test/passes/optimize-instructions.txt +++ b/test/passes/optimize-instructions.txt @@ -2850,6 +2850,33 @@ (i32.const 1) ) ) + (func $all_ones (; 68 ;) (type $0) (param $x i32) (param $y i64) + (drop + (get_local $x) + ) + (drop + (i32.const -1) + ) + (drop + (i32.or + (tee_local $x + (i32.const 1337) + ) + (i32.const -1) + ) + ) + (drop + (get_local $y) + ) + (drop + (i64.const -1) + ) + ) + (func $xor (; 69 ;) (type $0) (param $x i32) (param $y i64) + (drop + (get_local $x) + ) + ) ) (module (type $0 (func)) diff --git a/test/passes/optimize-instructions.wast b/test/passes/optimize-instructions.wast index 85709c7ca..f3a6b1329 100644 --- a/test/passes/optimize-instructions.wast +++ b/test/passes/optimize-instructions.wast @@ -3385,6 +3385,48 @@ ) ) ) + (func $all_ones (param $x i32) (param $y i64) + (drop + (i32.and + (get_local $x) + (i32.const -1) + ) + ) + (drop + (i32.or + (get_local $x) + (i32.const -1) + ) + ) + (drop + (i32.or + (tee_local $x + (i32.const 1337) + ) + (i32.const -1) + ) + ) + (drop + (i64.and + (get_local $y) + (i64.const -1) + ) + ) + (drop + (i64.or + (get_local $y) + (i64.const -1) + ) + ) + ) + (func $xor (param $x i32) (param $y i64) + (drop + (i32.xor + (get_local $x) + (i32.const 0) + ) + ) + ) ) (module (import "env" "memory" (memory $0 (shared 256 256))) |