summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/OptimizeInstructions.cpp8
-rw-r--r--test/lit/passes/optimize-instructions-gc.wast35
2 files changed, 40 insertions, 3 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index 70df652b8..6251348af 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -2169,8 +2169,12 @@ struct OptimizeInstructions
{builder.makeDrop(curr->ref), builder.makeConst(int32_t(1))}));
break;
case GCTypeUtils::Unreachable:
- replaceCurrent(builder.makeSequence(builder.makeDrop(curr->ref),
- builder.makeUnreachable()));
+ // Make sure to emit a block with the same type as us, to avoid other
+ // code in this pass needing to handle unexpected unreachable code
+ // (which is only properly propagated at the end of this pass when we
+ // refinalize).
+ replaceCurrent(builder.makeBlock(
+ {builder.makeDrop(curr->ref), builder.makeUnreachable()}, Type::i32));
break;
case GCTypeUtils::Failure:
replaceCurrent(builder.makeSequence(builder.makeDrop(curr->ref),
diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast
index e6c251ad2..e973ca086 100644
--- a/test/lit/passes/optimize-instructions-gc.wast
+++ b/test/lit/passes/optimize-instructions-gc.wast
@@ -2392,7 +2392,7 @@
;; CHECK: (func $non-null-bottom-ref-test-notee (type $none_=>_i32) (result i32)
;; CHECK-NEXT: (local $0 funcref)
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (loop
+ ;; CHECK-NEXT: (loop (result (ref nofunc))
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -2422,4 +2422,37 @@
(ref.func $non-null-bottom-cast)
)
)
+
+ ;; CHECK: (func $ref.test-then-optimizeAddedConstants (type $none_=>_i32) (result i32)
+ ;; CHECK-NEXT: (i32.add
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $ref.test-then-optimizeAddedConstants (result i32)
+ ;; The cast will become unreachable, and then the test as well. We should
+ ;; not error in the subsequent optimizeAddedConstants function that will be
+ ;; called on the adds. The risk here is that that code does not expect an
+ ;; unreachable to appear inside a non-unreachable add, which can happen as
+ ;; we delay updating types til the end of the pass. To avoid that, the
+ ;; ref.test should not change its type, but only replace itself with a block
+ ;; containing an unreachable (but declared as the old type; leaving
+ ;; optimizing it further for other passes).
+ (i32.add
+ (i32.const 1)
+ (i32.add
+ (i32.const 2)
+ (ref.test func
+ (ref.cast func
+ (ref.null nofunc)
+ )
+ )
+ )
+ )
+ )
)