diff options
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 8 | ||||
-rw-r--r-- | test/lit/passes/optimize-instructions-gc.wast | 35 |
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) + ) + ) + ) + ) + ) ) |