summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ir/properties.h6
-rw-r--r--src/passes/OptimizeInstructions.cpp7
-rw-r--r--src/passes/RemoveUnusedBrs.cpp10
-rw-r--r--test/lit/passes/optimize-instructions-multivalue.wast74
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)
+ )
+ )
+)