summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ir/ordering.h14
-rw-r--r--src/wasm/wasm.cpp2
-rw-r--r--test/lit/passes/gto-removals.wast33
3 files changed, 46 insertions, 3 deletions
diff --git a/src/ir/ordering.h b/src/ir/ordering.h
index ed2c00ee2..bc8d69055 100644
--- a/src/ir/ordering.h
+++ b/src/ir/ordering.h
@@ -34,6 +34,11 @@ namespace wasm {
//
// (temp = first, second, temp)
//
+// The first expression is assumed to not be unreachable (otherwise, there is no
+// value to get the result of). If the second is unreachable, this returns
+// something with type unreachable (that avoids returning something with a
+// concrete type, which might replace something with unreachable type - we want
+// to keep the type the same, in most cases).
inline Expression* getResultOfFirst(Expression* first,
Expression* second,
Function* func,
@@ -43,6 +48,15 @@ inline Expression* getResultOfFirst(Expression* first,
Builder builder(*wasm);
+ if (second->type == Type::unreachable) {
+ // No value is actually consumed here. Emit something with unreachable type.
+ // (Note that if we continued to the canReorder code after us, and emitted
+ // second followed by first, then the block would have a concrete type due
+ // to the last element having such a type - which would not have unreachable
+ // type.)
+ return builder.makeSequence(builder.makeDrop(first), second);
+ }
+
if (EffectAnalyzer::canReorder(passOptions, *wasm, first, second)) {
return builder.makeSequence(second, first);
}
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index a445d74bf..af40896ce 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -182,7 +182,7 @@ void Block::finalize() {
return;
}
// The default type is what is at the end. Next we need to see if breaks and/
- // or unreachabitily change that.
+ // or unreachability change that.
type = list.back()->type;
if (!name.is()) {
// Nothing branches here, so this is easy.
diff --git a/test/lit/passes/gto-removals.wast b/test/lit/passes/gto-removals.wast
index f75eb7483..5dd6ab4d1 100644
--- a/test/lit/passes/gto-removals.wast
+++ b/test/lit/passes/gto-removals.wast
@@ -815,11 +815,13 @@
;; CHECK-NEXT: (block $block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
- ;; CHECK-NEXT: (block (result (ref null ${mut:i8}))
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null ${mut:i8})
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br $block)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (ref.null ${mut:i8})
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -836,6 +838,33 @@
)
)
+ ;; CHECK: (func $unreachable-set-2b (type $none_=>_none)
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.as_non_null
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null ${mut:i8})
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $unreachable-set-2b
+ ;; As above, but with an unreachable instead of a br. We add a nop here so
+ ;; that we are inside of a block, and then validation would fail if we do
+ ;; not keep the type of the replacement for the struct.set identical to the
+ ;; struct.set. That is, the type must remain unreachable.
+ (nop)
+ (struct.set ${mut:i8} 0
+ (ref.null ${mut:i8})
+ (unreachable)
+ )
+ )
+
;; CHECK: (func $unreachable-set-3 (type $none_=>_none)
;; CHECK-NEXT: (local $0 (ref ${mut:i8}))
;; CHECK-NEXT: (drop