diff options
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 7 | ||||
-rw-r--r-- | test/lit/passes/optimize-instructions-gc-tnh.wast | 45 |
2 files changed, 51 insertions, 1 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index c9e1ced19..f5a0c6756 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -1632,7 +1632,12 @@ struct OptimizeInstructions } if (auto* select = ref->dynCast<Select>()) { - if (select->ifTrue->type.isNull()) { + // We must check for unreachability explicitly here because a full + // refinalize only happens at the end. That is, the select may stil be + // reachable after we turned one child into an unreachable, and we are + // calling getResultOfFirst which will error on unreachability. + if (select->ifTrue->type.isNull() && + select->ifFalse->type != Type::unreachable) { ref = builder.makeSequence( builder.makeDrop(select->ifTrue), getResultOfFirst(select->ifFalse, diff --git a/test/lit/passes/optimize-instructions-gc-tnh.wast b/test/lit/passes/optimize-instructions-gc-tnh.wast index f708951f8..5815f8e1f 100644 --- a/test/lit/passes/optimize-instructions-gc-tnh.wast +++ b/test/lit/passes/optimize-instructions-gc-tnh.wast @@ -772,6 +772,51 @@ ) ) + ;; TNH: (func $select.unreachable.child (type $none_=>_ref|$struct|) (result (ref $struct)) + ;; TNH-NEXT: (select + ;; TNH-NEXT: (ref.as_non_null + ;; TNH-NEXT: (ref.null none) + ;; TNH-NEXT: ) + ;; TNH-NEXT: (unreachable) + ;; TNH-NEXT: (i32.const 1) + ;; TNH-NEXT: ) + ;; TNH-NEXT: ) + ;; NO_TNH: (func $select.unreachable.child (type $none_=>_ref|$struct|) (result (ref $struct)) + ;; NO_TNH-NEXT: (select + ;; NO_TNH-NEXT: (ref.as_non_null + ;; NO_TNH-NEXT: (ref.null none) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (block + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.as_non_null + ;; NO_TNH-NEXT: (ref.null none) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (i32.const 1) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $select.unreachable.child (result (ref $struct)) + ;; We will turn the false arm of the select into an unreachable first, and + ;; then process the select. While doing so we must not error, as the select + ;; itself will still have a reachable type (a full refinalize only + ;; happens at the very end of the function). + (ref.cast $struct + (select (result (ref $struct)) + (ref.as_non_null + (ref.null none) + ) + (ref.cast $struct + (ref.as_non_null + (ref.null none) + ) + ) + (i32.const 1) + ) + ) + ) + ;; Helper functions. ;; TNH: (func $get-i32 (type $none_=>_i32) (result i32) |