diff options
author | Alon Zakai <azakai@google.com> | 2020-12-16 17:26:09 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-16 17:26:09 -0800 |
commit | 4423bcce31d9162c8f8e4262deda5e9278e0e55c (patch) | |
tree | 971e0d74d77b92ab51d905d2c9ea4080b1efe94e /src/ir/branch-utils.h | |
parent | 83114c51d5aedcb540d578790dbf3173d1775d5c (diff) | |
download | binaryen-4423bcce31d9162c8f8e4262deda5e9278e0e55c.tar.gz binaryen-4423bcce31d9162c8f8e4262deda5e9278e0e55c.tar.bz2 binaryen-4423bcce31d9162c8f8e4262deda5e9278e0e55c.zip |
More refactoring of branch utility code to remove boilerplate. (#3448)
This is almost NFC, but it may emit slightly different IR in cases that
don't matter much. Specifically,
(block (result i32) ;; can also be unreachable
(unreachable)
(i32.const 1)
)
That can be finalized to have type unreachable or i32, as both are
valid. After this PR we should consistently do the same thing in all
places. (Either option would be ok - we prefer to keep the type if
there is one.)
In practice, DCE will remove all the dead code anyhow, leaving no
difference to matter. However, the IR is different without DCE, and
that may be noticeable in an unoptimized build - but it should have
no effect on behavior, just on the binary.
Diffstat (limited to 'src/ir/branch-utils.h')
-rw-r--r-- | src/ir/branch-utils.h | 51 |
1 files changed, 30 insertions, 21 deletions
diff --git a/src/ir/branch-utils.h b/src/ir/branch-utils.h index e6a3486ca..6dfe216a2 100644 --- a/src/ir/branch-utils.h +++ b/src/ir/branch-utils.h @@ -68,6 +68,25 @@ template<typename T> void operateOnScopeNameUses(Expression* expr, T func) { #include "wasm-delegations-fields.h" } +// Similar to operateOnScopeNameUses, but also passes in the type that is sent +// if the branch is taken. The type is none if there is no value. +template<typename T> +void operateOnScopeNameUsesAndSentTypes(Expression* expr, T func) { + operateOnScopeNameUses(expr, [&](Name& name) { + // There isn't a delegate mechanism for getting a sent value, so do a direct + // if-else chain. This will need to be updated with new br variants. + if (auto* br = expr->dynCast<Break>()) { + func(name, br->value ? br->value->type : Type::none); + } else if (auto* sw = expr->dynCast<Switch>()) { + func(name, sw->value ? sw->value->type : Type::none); + } else if (auto* br = expr->dynCast<BrOnExn>()) { + func(name, br->sent); + } else { + WASM_UNREACHABLE("bad br type"); + } + }); +} + // Perform a generic operation on definitions of scope names in an expression. // The provided function receives a Name& which it can modify if it needs to. template<typename T> void operateOnScopeNameDefs(Expression* expr, T func) { @@ -164,36 +183,26 @@ struct BranchSeeker Name target; Index found = 0; - Type valueType; + // None indicates no value is sent. + Type valueType = Type::none; BranchSeeker(Name target) : target(target) {} - void noteFound(Expression* value) { - noteFound(value ? value->type : Type::none); - } - - void noteFound(Type type) { + void noteFound(Type newType) { found++; - if (found == 1) { - valueType = Type::unreachable; - } - if (type != Type::unreachable) { - valueType = type; + if (newType != Type::none) { + if (found == 1) { + valueType = newType; + } else { + valueType = Type::getLeastUpperBound(valueType, newType); + } } } void visitExpression(Expression* curr) { - operateOnScopeNameUses(curr, [&](Name& name) { + operateOnScopeNameUsesAndSentTypes(curr, [&](Name& name, Type type) { if (name == target) { - if (auto* br = curr->dynCast<Break>()) { - noteFound(br->value); - } else if (auto* sw = curr->dynCast<Switch>()) { - noteFound(sw->value); - } else if (auto* br = curr->dynCast<BrOnExn>()) { - noteFound(br->sent); - } else { - WASM_UNREACHABLE("bad br type"); - } + noteFound(type); } }); } |