diff options
author | Alon Zakai <azakai@google.com> | 2021-07-19 14:38:24 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-19 14:38:24 -0700 |
commit | fb9de9d391a7272548dcc41cd8229076189d7398 (patch) | |
tree | a1d5c3610ca8c3ec9b82e3f451e857b6470f75ac | |
parent | f98eb3463cdfb1ad6a97dc0c4ba6d6d99f77e706 (diff) | |
download | binaryen-fb9de9d391a7272548dcc41cd8229076189d7398.tar.gz binaryen-fb9de9d391a7272548dcc41cd8229076189d7398.tar.bz2 binaryen-fb9de9d391a7272548dcc41cd8229076189d7398.zip |
RemoveUnusedBrs: Do not create a select with a multivalue result (#4005)
The spec disallows that.
Fixes #3990
-rw-r--r-- | src/passes/RemoveUnusedBrs.cpp | 16 | ||||
-rw-r--r-- | test/lit/passes/remove-unused-brs.wast | 47 |
2 files changed, 60 insertions, 3 deletions
diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp index 5631c9d5f..157cfc1f3 100644 --- a/src/passes/RemoveUnusedBrs.cpp +++ b/src/passes/RemoveUnusedBrs.cpp @@ -97,6 +97,12 @@ static bool tooCostlyToRunUnconditionally(const PassOptions& passOptions, return total >= TOO_MUCH; } +static bool canEmitSelectWithArms(Expression* ifTrue, Expression* ifFalse) { + // A select only allows a single value in its arms in the spec: + // https://webassembly.github.io/spec/core/valid/instructions.html#xref-syntax-instructions-syntax-instr-parametric-mathsf-select-t-ast + return ifTrue->type.isSingle() && ifFalse->type.isSingle(); +} + struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { bool isFunctionParallel() override { return true; } @@ -1023,7 +1029,8 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { EffectAnalyzer(passOptions, features, curr) .hasSideEffects(); list[0] = old; - if (canReorder && !hasSideEffects) { + if (canReorder && !hasSideEffects && + canEmitSelectWithArms(br->value, curr)) { ExpressionManipulator::nop(list[0]); replaceCurrent( builder.makeSelect(br->condition, br->value, curr)); @@ -1044,8 +1051,11 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { // Convert an if into a select, if possible and beneficial to do so. Select* selectify(If* iff) { - if (!iff->ifFalse || !iff->ifTrue->type.isSingle() || - !iff->ifFalse->type.isSingle()) { + // Only an if-else can be turned into a select. + if (!iff->ifFalse) { + return nullptr; + } + if (!canEmitSelectWithArms(iff->ifTrue, iff->ifFalse)) { return nullptr; } if (iff->condition->type == Type::unreachable) { diff --git a/test/lit/passes/remove-unused-brs.wast b/test/lit/passes/remove-unused-brs.wast index 089d82391..9ed319cb8 100644 --- a/test/lit/passes/remove-unused-brs.wast +++ b/test/lit/passes/remove-unused-brs.wast @@ -288,4 +288,51 @@ (call $get-i32) ) ) + + ;; CHECK: (func $restructure-select-no-multivalue + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block $block (result i32 i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (br_if $block + ;; CHECK-NEXT: (tuple.make + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (call $restructure-br_if + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (tuple.make + ;; CHECK-NEXT: (i32.const 4) + ;; CHECK-NEXT: (i32.const 5) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $restructure-select-no-multivalue + (drop + (block $block (result i32 i32) + (drop + (br_if $block + (tuple.make + (i32.const 1) + ;; Add a side effect to prevent us turning $block into a + ;; restructured if - instead, we will try a restructured select. + ;; But, selects cannot return multiple values in the spec, so we + ;; can do nothing here. + (call $restructure-br_if + (i32.const 2) + ) + ) + (i32.const 3) + ) + ) + (tuple.make + (i32.const 4) + (i32.const 5) + ) + ) + ) + ) ) |