From d3dd900aa285be37b7581128a1386c123e937476 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Mon, 5 Jan 2026 18:48:38 -0800 Subject: [PATCH 1/2] Remove assertion about repeat types in TypeSSA TypeSSA previously asserted that it never saw repeated type shapes when collecting the type shapes of the various types in the module. This is usually true, but it turns out that DAE can produce repeated type shapes that violated this assertion. Since it would be complicated to fix DAE to stop producing duplicate type shapes and the duplicate type shapes it produces are actually benign, simply remove the assertion in TypeSSA. --- src/passes/TypeSSA.cpp | 3 +- test/lit/passes/dae-typessa-repeat-types.wast | 81 +++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 test/lit/passes/dae-typessa-repeat-types.wast diff --git a/src/passes/TypeSSA.cpp b/src/passes/TypeSSA.cpp index dd8f694c659..ad0e9b500ea 100644 --- a/src/passes/TypeSSA.cpp +++ b/src/passes/TypeSSA.cpp @@ -73,8 +73,7 @@ std::vector ensureTypesAreInNewRecGroup(std::vector&& types, UniqueRecGroups unique(wasm.features); for (auto group : existing) { std::vector types(group.begin(), group.end()); - [[maybe_unused]] auto uniqueTypes = unique.insert(std::move(types)); - assert(uniqueTypes.size() == group.size() && "unexpected collision"); + unique.insertOrGet(std::move(types)); } auto num = types.size(); diff --git a/test/lit/passes/dae-typessa-repeat-types.wast b/test/lit/passes/dae-typessa-repeat-types.wast new file mode 100644 index 00000000000..d03e7e1a1f1 --- /dev/null +++ b/test/lit/passes/dae-typessa-repeat-types.wast @@ -0,0 +1,81 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. +;; RUN: wasm-opt %s -all --disable-custom-descriptors --dae --type-ssa -S -o - | filecheck %s + +(module + ;; CHECK: (type $struct (struct)) + (type $struct (struct)) + + ;; CHECK: (type $1 (func (result i32 (ref (exact $struct))))) + + ;; CHECK: (type $array (sub (array (mut i32)))) + (type $array (sub (array (mut i32)))) + + ;; Trigger TypeSSA + ;; CHECK: (type $3 (func)) + + ;; CHECK: (type $array_1 (sub $array (array (mut i32)))) + + ;; CHECK: (type $5 (func (result i32 (ref $struct)))) + + ;; CHECK: (global $array (ref $array) (array.new $array_1 + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: )) + (global $array (ref $array) + (array.new $array + (i32.const 0) + (i32.const 0) + ) + ) + + ;; CHECK: (func $caller (type $3) + ;; CHECK-NEXT: (call $callee) + ;; CHECK-NEXT: ) + (func $caller + ;; Give DAE a constant null parameter to optimize. + (tuple.drop 2 + (call $callee + (ref.null none) + ) + ) + ) + + ;; CHECK: (func $callee (type $3) + ;; CHECK-NEXT: (local $0 anyref) + ;; CHECK-NEXT: (tuple.drop 2 + ;; CHECK-NEXT: (block (type $1) (result i32 (ref (exact $struct))) + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block (type $1) (result i32 (ref (exact $struct))) + ;; CHECK-NEXT: (tuple.make 2 + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (struct.new_default $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $callee (param (ref null any)) (result i32 (ref $struct)) + ;; When applying the constant null, DAE will create a block with + ;; (result i32 (ref (exact $struct))) + (block (result i32 (ref $struct)) + (tuple.make 2 + (i32.const 0) + (struct.new_default $struct) + ) + ) + ) + + ;; CHECK: (func $other (type $5) (result i32 (ref $struct)) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $other (result i32 (ref $struct)) + ;; This will keep the (result i32 (ref $struct)) signature, which will + ;; conflict with the (result i32 (ref (exact $struct))) of the block above + ;; after binary writing. This will not be observable, though, since DAE only + ;; optimizes non-referenced functions. TypeSSA should not crash or fail an + ;; assertion due to the repeated type shape. + (unreachable) + ) +) From 77de3dc084b1cb2cb940f0c1504cc697255e71c6 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Tue, 6 Jan 2026 14:00:54 -0800 Subject: [PATCH 2/2] add comment --- src/passes/TypeSSA.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/passes/TypeSSA.cpp b/src/passes/TypeSSA.cpp index ad0e9b500ea..095d6cec2bf 100644 --- a/src/passes/TypeSSA.cpp +++ b/src/passes/TypeSSA.cpp @@ -73,6 +73,9 @@ std::vector ensureTypesAreInNewRecGroup(std::vector&& types, UniqueRecGroups unique(wasm.features); for (auto group : existing) { std::vector types(group.begin(), group.end()); + // N.B. we use `insertOrGet` rather than `insert` because some passes (DAE, + // BlockMerging) can create multiple types with the same shape, so we can't + // assume all the rec groups are already unique. unique.insertOrGet(std::move(types)); }