From f4471b85bd2943f07cf1462f760e82c89ca4f1b6 Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Fri, 18 Sep 2026 16:06:42 +0000 Subject: [PATCH] Fix type updating for struct.wait --- src/ir/struct-utils.h | 13 +++++++ src/passes/GlobalTypeOptimization.cpp | 12 ++++++- src/passes/TypeRefining.cpp | 13 ++++++- test/lit/passes/gto-removals.wast | 20 +++++++++-- test/lit/passes/type-refining-gufa-rmw.wast | 40 ++++++++++++++++++--- 5 files changed, 89 insertions(+), 9 deletions(-) diff --git a/src/ir/struct-utils.h b/src/ir/struct-utils.h index c90fbb85348..b4c69986fde 100644 --- a/src/ir/struct-utils.h +++ b/src/ir/struct-utils.h @@ -248,6 +248,19 @@ struct StructScanner : public WalkerPass> { functionSetGetInfos[this->getFunction()][ht][index]); } + void visitStructWait(StructWait* curr) { + auto type = curr->ref->type; + if (type == Type::unreachable || type.isNull()) { + return; + } + + auto ht = std::make_pair(type.getHeapType(), type.getExactness()); + auto index = curr->index; + self().noteRead(type.getHeapType(), + index, + functionSetGetInfos[this->getFunction()][ht][index]); + } + void visitStructRMW(StructRMW* curr) { auto type = curr->ref->type; if (type == Type::unreachable || type.isNull()) { diff --git a/src/passes/GlobalTypeOptimization.cpp b/src/passes/GlobalTypeOptimization.cpp index b0bb31edbd9..68e56b20298 100644 --- a/src/passes/GlobalTypeOptimization.cpp +++ b/src/passes/GlobalTypeOptimization.cpp @@ -839,7 +839,17 @@ struct GlobalTypeOptimization : public Pass { curr->index = newIndex; } - // TODO: visitStructWait + void visitStructWait(StructWait* curr) { + if (curr->ref->type == Type::unreachable) { + return; + } + + auto newIndex = + parent.getNewIndex(curr->ref->type.getHeapType(), curr->index); + // We must not remove a field that is read from. + assert(newIndex != RemovedField); + curr->index = newIndex; + } }; PassRunner runner(getPassRunner()); diff --git a/src/passes/TypeRefining.cpp b/src/passes/TypeRefining.cpp index 1d4fad7d85d..1afda6dbc4f 100644 --- a/src/passes/TypeRefining.cpp +++ b/src/passes/TypeRefining.cpp @@ -568,7 +568,18 @@ struct TypeRefining : public Pass { curr->replacement = fixType(curr->replacement, fieldType); } - // TODO: visitStructWait + void visitStructWait(StructWait* curr) { + if (curr->ref->type == Type::unreachable) { + return; + } + auto type = curr->ref->type.getHeapType(); + if (type.isBottom()) { + return; + } + + auto fieldType = type.getStruct().fields[curr->index].type; + curr->expected = fixType(curr->expected, fieldType); + } bool refinalize = false; diff --git a/test/lit/passes/gto-removals.wast b/test/lit/passes/gto-removals.wast index f0000775bfc..98b0ef505ec 100644 --- a/test/lit/passes/gto-removals.wast +++ b/test/lit/passes/gto-removals.wast @@ -99,8 +99,8 @@ ;; A read *does* keep a field from being removed. ;; CHECK: (rec - ;; CHECK-NEXT: (type $struct (sub (struct (field funcref)))) - (type $struct (sub (struct (field (mut funcref))))) + ;; CHECK-NEXT: (type $struct (sub (struct (field funcref) (field i32)))) + (type $struct (sub (struct (field (mut funcref)) (field (mut i32))))) ;; CHECK: (type $1 (func (param (ref $struct)))) @@ -110,6 +110,14 @@ ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.wait $struct 1 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (waitqueue.new) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (i64.const -1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $func (param $x (ref $struct)) (drop @@ -117,6 +125,14 @@ (local.get $x) ) ) + (drop + (struct.wait $struct 1 + (local.get $x) + (waitqueue.new) + (i32.const 1) + (i64.const -1) + ) + ) ) ) diff --git a/test/lit/passes/type-refining-gufa-rmw.wast b/test/lit/passes/type-refining-gufa-rmw.wast index 760dd5cd75f..16e990b47d8 100644 --- a/test/lit/passes/type-refining-gufa-rmw.wast +++ b/test/lit/passes/type-refining-gufa-rmw.wast @@ -417,10 +417,10 @@ ) (module - ;; NRML: (type $struct (sub (struct (field (mut (ref null $struct)))))) + ;; NRML: (type $struct (sub (shared (struct (field (mut (ref null $struct))))))) ;; GUFA: (rec - ;; GUFA-NEXT: (type $struct (sub (struct (field (mut nullref))))) - (type $struct (sub (struct (field (mut (ref null $struct)))))) + ;; GUFA-NEXT: (type $struct (sub (shared (struct (field (mut (ref null (shared none)))))))) + (type $struct (sub (shared (struct (field (mut (ref null $struct))))))) ;; NRML: (type $1 (func (param (ref null $struct)))) @@ -435,6 +435,14 @@ ;; NRML-NEXT: (local.get $struct) ;; NRML-NEXT: ) ;; NRML-NEXT: ) + ;; NRML-NEXT: (drop + ;; NRML-NEXT: (struct.wait $struct 0 + ;; NRML-NEXT: (local.get $struct) + ;; NRML-NEXT: (unreachable) + ;; NRML-NEXT: (local.get $struct) + ;; NRML-NEXT: (i64.const -1) + ;; NRML-NEXT: ) + ;; NRML-NEXT: ) ;; NRML-NEXT: ) ;; GUFA: (type $1 (func (param (ref null $struct)))) @@ -446,12 +454,25 @@ ;; GUFA-NEXT: (struct.atomic.rmw.cmpxchg acqrel acqrel $struct 0 ;; GUFA-NEXT: (local.get $struct) ;; GUFA-NEXT: (unreachable) - ;; GUFA-NEXT: (block (result nullref) + ;; GUFA-NEXT: (block (result (ref null (shared none))) ;; GUFA-NEXT: (drop ;; GUFA-NEXT: (local.get $struct) ;; GUFA-NEXT: ) - ;; GUFA-NEXT: (ref.null none) + ;; GUFA-NEXT: (ref.null (shared none)) + ;; GUFA-NEXT: ) + ;; GUFA-NEXT: ) + ;; GUFA-NEXT: ) + ;; GUFA-NEXT: (drop + ;; GUFA-NEXT: (struct.wait $struct 0 + ;; GUFA-NEXT: (local.get $struct) + ;; GUFA-NEXT: (unreachable) + ;; GUFA-NEXT: (block (result (ref null (shared none))) + ;; GUFA-NEXT: (drop + ;; GUFA-NEXT: (local.get $struct) + ;; GUFA-NEXT: ) + ;; GUFA-NEXT: (ref.null (shared none)) ;; GUFA-NEXT: ) + ;; GUFA-NEXT: (i64.const -1) ;; GUFA-NEXT: ) ;; GUFA-NEXT: ) ;; GUFA-NEXT: ) @@ -471,6 +492,15 @@ (local.get $struct) ) ) + ;; Likewise with struct.wait. + (drop + (struct.wait $struct 0 + (local.get $struct) + (unreachable) + (local.get $struct) + (i64.const -1) + ) + ) ) )