diff options
-rw-r--r-- | src/ir/properties.h | 6 | ||||
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 7 | ||||
-rw-r--r-- | src/passes/RemoveUnusedBrs.cpp | 10 | ||||
-rw-r--r-- | test/lit/passes/optimize-instructions-multivalue.wast | 74 |
4 files changed, 88 insertions, 9 deletions
diff --git a/src/ir/properties.h b/src/ir/properties.h index 63dd6c72c..8e5297092 100644 --- a/src/ir/properties.h +++ b/src/ir/properties.h @@ -328,6 +328,12 @@ inline bool isResultFallthrough(Expression* curr) { curr->is<Break>(); } +inline 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(); +} + } // namespace Properties } // namespace wasm diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 9f095b333..31ed9348a 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -3037,7 +3037,12 @@ private: curr->ifTrue) .hasSideEffects(); - if (validTypes && validEffects) { + // In addition, check for specific limitations of select. + bool validChildren = + !std::is_same<T, Select>::value || + Properties::canEmitSelectWithArms(ifTrueChild, ifFalseChild); + + if (validTypes && validEffects && validChildren) { // Replace ifTrue with its child. curr->ifTrue = ifTrueChild; // Relace ifFalse with its child, and reuse that node outside. diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp index 157cfc1f3..d0950b485 100644 --- a/src/passes/RemoveUnusedBrs.cpp +++ b/src/passes/RemoveUnusedBrs.cpp @@ -97,12 +97,6 @@ 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; } @@ -1030,7 +1024,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { .hasSideEffects(); list[0] = old; if (canReorder && !hasSideEffects && - canEmitSelectWithArms(br->value, curr)) { + Properties::canEmitSelectWithArms(br->value, curr)) { ExpressionManipulator::nop(list[0]); replaceCurrent( builder.makeSelect(br->condition, br->value, curr)); @@ -1055,7 +1049,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { if (!iff->ifFalse) { return nullptr; } - if (!canEmitSelectWithArms(iff->ifTrue, iff->ifFalse)) { + if (!Properties::canEmitSelectWithArms(iff->ifTrue, iff->ifFalse)) { return nullptr; } if (iff->condition->type == Type::unreachable) { diff --git a/test/lit/passes/optimize-instructions-multivalue.wast b/test/lit/passes/optimize-instructions-multivalue.wast new file mode 100644 index 000000000..310505360 --- /dev/null +++ b/test/lit/passes/optimize-instructions-multivalue.wast @@ -0,0 +1,74 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --optimize-instructions --enable-multivalue -S -o - | filecheck %s + +(module + ;; CHECK: (func $if-identical-arms-tuple (param $x i32) (result i32) + ;; CHECK-NEXT: (tuple.extract 0 + ;; CHECK-NEXT: (if (result i32 i32) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (tuple.make + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (tuple.make + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-identical-arms-tuple (param $x i32) (result i32) + (if (result i32) + (local.get $x) + ;; The tuple.extract can be hoisted out. + (tuple.extract 0 + (tuple.make + (i32.const 0) + (i32.const 1) + ) + ) + (tuple.extract 0 + (tuple.make + (i32.const 2) + (i32.const 3) + ) + ) + ) + ) + ;; CHECK: (func $select-identical-arms-tuple (param $x i32) (result i32) + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (tuple.extract 0 + ;; CHECK-NEXT: (tuple.make + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (tuple.extract 0 + ;; CHECK-NEXT: (tuple.make + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $select-identical-arms-tuple (param $x i32) (result i32) + (select + ;; The tuple.extract cannot be hoisted out, as the spec disallows a + ;; select with multiple values in its arms. + (tuple.extract 0 + (tuple.make + (i32.const 0) + (i32.const 1) + ) + ) + (tuple.extract 0 + (tuple.make + (i32.const 2) + (i32.const 3) + ) + ) + (local.get $x) + ) + ) +) |