diff options
author | Alon Zakai <alonzakai@gmail.com> | 2018-08-27 11:41:48 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-27 11:41:48 -0700 |
commit | 65112ceec0cb92ec853f3391263d51a12b15bad0 (patch) | |
tree | d8b54a465365a2fb4c15c5c859ad5e80447c8a7b | |
parent | f215193ec12a45fdd893ea8a8cec1353aa3b529e (diff) | |
download | binaryen-65112ceec0cb92ec853f3391263d51a12b15bad0.tar.gz binaryen-65112ceec0cb92ec853f3391263d51a12b15bad0.tar.bz2 binaryen-65112ceec0cb92ec853f3391263d51a12b15bad0.zip |
Improve getFallthrough (#1643)
That method looks through tee_locals and other operations that receive a value and let it flow through them, like a block's final value, etc. It just handled a few such operations, with this PR all of them should be handled.
Also refactor it out of the OptimizeInstructions pass as I think it may be useful for propagating returned constants.
-rw-r--r-- | src/ir/properties.h | 36 | ||||
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 20 | ||||
-rw-r--r-- | test/passes/optimize-instructions.txt | 91 | ||||
-rw-r--r-- | test/passes/optimize-instructions.wast | 47 |
4 files changed, 176 insertions, 18 deletions
diff --git a/src/ir/properties.h b/src/ir/properties.h index 7cbbe73f0..6848e9481 100644 --- a/src/ir/properties.h +++ b/src/ir/properties.h @@ -146,6 +146,42 @@ inline Index getZeroExtBits(Expression* curr) { return Bits::getMaskedBits(curr->cast<Binary>()->right->cast<Const>()->value.geti32()); } +// Returns a falling-through value, that is, it looks through a tee_local +// and other operations that receive a value and let it flow through them. +inline Expression* getFallthrough(Expression* curr) { + // If the current node is unreachable, there is no value + // falling through. + if (curr->type == unreachable) { + return curr; + } + if (auto* set = curr->dynCast<SetLocal>()) { + if (set->isTee()) { + return getFallthrough(set->value); + } + } else if (auto* block = curr->dynCast<Block>()) { + // if no name, we can't be broken to, and then can look at the fallthrough + if (!block->name.is() && block->list.size() > 0) { + return getFallthrough(block->list.back()); + } + } else if (auto* loop = curr->dynCast<Loop>()) { + return getFallthrough(loop->body); + } else if (auto* iff = curr->dynCast<If>()) { + if (iff->ifFalse) { + // Perhaps just one of the two actually returns. + if (iff->ifTrue->type == unreachable) { + return getFallthrough(iff->ifFalse); + } else if (iff->ifFalse->type == unreachable) { + return getFallthrough(iff->ifTrue); + } + } + } else if (auto* br = curr->dynCast<Break>()) { + if (br->condition && br->value) { + return getFallthrough(br->value); + } + } + return curr; +} + } // Properties } // wasm diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 55042d96f..73f78611b 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -258,22 +258,6 @@ Index getMaxBits(Expression* curr, LocalInfoProvider* localInfoProvider) { } } -// looks through fallthrough operations, like tee_local, block fallthrough, etc. -// too and block fallthroughs, etc. -Expression* getFallthrough(Expression* curr) { - if (auto* set = curr->dynCast<SetLocal>()) { - if (set->isTee()) { - return getFallthrough(set->value); - } - } else if (auto* block = curr->dynCast<Block>()) { - // if no name, we can't be broken to, and then can look at the fallthrough - if (!block->name.is() && block->list.size() > 0) { - return getFallthrough(block->list.back()); - } - } - return curr; -} - // Useful information about locals struct LocalInfo { static const Index kUnknown = Index(-1); @@ -316,7 +300,7 @@ struct LocalScanner : PostWalker<LocalScanner> { auto type = getFunction()->getLocalType(curr->index); if (type != i32 && type != i64) return; // an integer var, worth processing - auto* value = getFallthrough(curr->value); + auto* value = Properties::getFallthrough(curr->value); auto& info = localInfo[curr->index]; info.maxBits = std::max(info.maxBits, getMaxBits(value, this)); auto signExtBits = LocalInfo::kUnknown; @@ -421,7 +405,7 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions, Index extraShifts; auto bits = Properties::getAlmostSignExtBits(binary, extraShifts); if (extraShifts == 0) { - if (auto* load = getFallthrough(ext)->dynCast<Load>()) { + if (auto* load = Properties::getFallthrough(ext)->dynCast<Load>()) { // pattern match a load of 8 bits and a sign extend using a shl of 24 then shr_s of 24 as well, etc. if (LoadUtils::canBeSigned(load) && ((load->bytes == 1 && bits == 8) || (load->bytes == 2 && bits == 16))) { diff --git a/test/passes/optimize-instructions.txt b/test/passes/optimize-instructions.txt index 0b156f803..5a0a45e3d 100644 --- a/test/passes/optimize-instructions.txt +++ b/test/passes/optimize-instructions.txt @@ -11,6 +11,7 @@ (type $9 (func (param i32 i64 f32 f64))) (type $10 (func (param i32 i64 f32))) (type $11 (func (param i32 i64 f64 i32))) + (type $12 (func (result f64))) (memory $0 0) (export "load-off-2" (func $load-off-2)) (func $f (; 0 ;) (type $0) (param $i1 i32) (param $i2 i64) @@ -2906,6 +2907,96 @@ ) ) ) + (func $getFallthrough (; 71 ;) (type $1) + (local $x0 i32) + (local $x1 i32) + (local $x2 i32) + (local $x3 i32) + (local $x4 i32) + (local $x5 i32) + (local $x6 i32) + (local $x7 i32) + (set_local $x0 + (i32.const 1) + ) + (drop + (get_local $x0) + ) + (set_local $x1 + (tee_local $x2 + (i32.const 1) + ) + ) + (drop + (get_local $x1) + ) + (set_local $x3 + (loop $loop-in (result i32) + (i32.const 1) + ) + ) + (drop + (get_local $x3) + ) + (set_local $x4 + (if (result i32) + (i32.const 1) + (i32.const 2) + (i32.const 3) + ) + ) + (drop + (i32.and + (get_local $x4) + (i32.const 7) + ) + ) + (set_local $x5 + (if (result i32) + (i32.const 1) + (unreachable) + (i32.const 3) + ) + ) + (drop + (get_local $x5) + ) + (set_local $x6 + (if (result i32) + (i32.const 1) + (i32.const 3) + (unreachable) + ) + ) + (drop + (get_local $x6) + ) + (drop + (block $out (result i32) + (set_local $x7 + (br_if $out + (i32.const 1) + (i32.const 1) + ) + ) + (drop + (get_local $x7) + ) + (unreachable) + ) + ) + ) + (func $tee-with-unreachable-value (; 72 ;) (type $12) (result f64) + (local $var$0 i32) + (block $label$1 (result f64) + (tee_local $var$0 + (br_if $label$1 + (f64.const 1) + (unreachable) + ) + ) + ) + ) ) (module (type $0 (func)) diff --git a/test/passes/optimize-instructions.wast b/test/passes/optimize-instructions.wast index b65432715..aa979c62a 100644 --- a/test/passes/optimize-instructions.wast +++ b/test/passes/optimize-instructions.wast @@ -3479,6 +3479,53 @@ ) ) ) + (func $getFallthrough ;; unit tests for Properties::getFallthrough + (local $x0 i32) + (local $x1 i32) + (local $x2 i32) + (local $x3 i32) + (local $x4 i32) + (local $x5 i32) + (local $x6 i32) + (local $x7 i32) + ;; the trivial case + (set_local $x0 (i32.const 1)) + (drop (i32.and (get_local $x0) (i32.const 7))) + ;; tees + (set_local $x1 (tee_local $x2 (i32.const 1))) + (drop (i32.and (get_local $x1) (i32.const 7))) + ;; loop + (set_local $x3 (loop (result i32) (i32.const 1))) + (drop (i32.and (get_local $x3) (i32.const 7))) + ;; if - two sides, can't + (set_local $x4 (if (result i32) (i32.const 1) (i32.const 2) (i32.const 3))) + (drop (i32.and (get_local $x4) (i32.const 7))) + ;; if - one side, can + (set_local $x5 (if (result i32) (i32.const 1) (unreachable) (i32.const 3))) + (drop (i32.and (get_local $x5) (i32.const 7))) + ;; if - one side, can + (set_local $x6 (if (result i32) (i32.const 1) (i32.const 3) (unreachable))) + (drop (i32.and (get_local $x6) (i32.const 7))) + ;; br_if with value + (drop + (block $out (result i32) + (set_local $x7 (br_if $out (i32.const 1) (i32.const 1))) + (drop (i32.and (get_local $x7) (i32.const 7))) + (unreachable) + ) + ) + ) + (func $tee-with-unreachable-value (result f64) + (local $var$0 i32) + (block $label$1 (result f64) + (tee_local $var$0 + (br_if $label$1 ;; the f64 does not actually flow through this, it's unreachable (and the type is wrong - but unchecked) + (f64.const 1) + (unreachable) + ) + ) + ) + ) ) (module (import "env" "memory" (memory $0 (shared 256 256))) |