From bba4ec0903e11b80b6118267747d4318588e51ee Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Sun, 7 Jun 2026 11:33:14 -0700 Subject: [PATCH] Fix crash in optimizeSelect with non-concrete arm types Avoid creating a scratch local of non-concrete type (like unreachable) when we cannot reorder. We generally do not optimize unreachable selects in the first place, but it is still possible that we observe unreachable arms when optimizing because other optimizations might have made the arms unreachable. TAG=agy --- src/passes/OptimizeInstructions.cpp | 6 ++++ .../passes/optimize-instructions-gc-tnh.wast | 35 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 5985ae278b1..df6985bd7bf 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -3415,6 +3415,12 @@ struct OptimizeInstructions if (canReorder(ifTrue, c)) { return builder.makeSequence(builder.makeDrop(c), ifTrue); } + // We generally skip optimizing unreachable selects, but an + // optimization on the children might have made them newly + // unreachable. We cannot create a scratch local in that case. + if (!ifTrue->type.isConcrete()) { + return nullptr; + } auto scratch = builder.addVar(getFunction(), ifTrue->type); return builder.makeBlock( {builder.makeLocalSet(scratch, ifTrue), diff --git a/test/lit/passes/optimize-instructions-gc-tnh.wast b/test/lit/passes/optimize-instructions-gc-tnh.wast index 45674df82a2..8eb66fcf5c5 100644 --- a/test/lit/passes/optimize-instructions-gc-tnh.wast +++ b/test/lit/passes/optimize-instructions-gc-tnh.wast @@ -1056,4 +1056,39 @@ (func $get-null (result (ref null none)) (unreachable) ) + + ;; TNH: (func $select-uninhabitable-arms (type $void) + ;; TNH-NEXT: (drop + ;; TNH-NEXT: (select + ;; TNH-NEXT: (unreachable) + ;; TNH-NEXT: (unreachable) + ;; TNH-NEXT: (call $get-i32) + ;; TNH-NEXT: ) + ;; TNH-NEXT: ) + ;; TNH-NEXT: ) + ;; NO_TNH: (func $select-uninhabitable-arms (type $void) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (select + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: (call $get-i32) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $select-uninhabitable-arms + (drop + ;; This select is not unreachable, so we will optimize it. + (select (result (ref nofunc)) + ;; But the arms will be optimized to unreachable first. We should not + ;; crash on trying to create an unreachable scratch local here. + (ref.as_non_null + (ref.null nofunc) + ) + (ref.as_non_null + (ref.null nofunc) + ) + (call $get-i32) + ) + ) + ) )