diff --git a/src/passes/GlobalTypeOptimization.cpp b/src/passes/GlobalTypeOptimization.cpp index 8133c025ddd..d19cfc3cf27 100644 --- a/src/passes/GlobalTypeOptimization.cpp +++ b/src/passes/GlobalTypeOptimization.cpp @@ -660,6 +660,28 @@ struct GlobalTypeOptimization : public Pass { curr->index = newIndex; } + void visitStructRMW(StructRMW* curr) { + if (curr->ref->type == Type::unreachable) { + return; + } + + auto newIndex = getNewIndex(curr->ref->type.getHeapType(), curr->index); + // We must not remove a field that is read from. + assert(newIndex != RemovedField); + curr->index = newIndex; + } + + void visitStructCmpxchg(StructCmpxchg* curr) { + if (curr->ref->type == Type::unreachable) { + return; + } + + auto newIndex = getNewIndex(curr->ref->type.getHeapType(), curr->index); + // We must not remove a field that is read from. + assert(newIndex != RemovedField); + curr->index = newIndex; + } + void visitFunction(Function* curr) { if (needEHFixups) { EHUtils::handleBlockNestedPops(curr, *getModule()); diff --git a/test/lit/passes/gto-removals-rmw.wast b/test/lit/passes/gto-removals-rmw.wast index 7d759a6727f..ac650ba41cf 100644 --- a/test/lit/passes/gto-removals-rmw.wast +++ b/test/lit/passes/gto-removals-rmw.wast @@ -74,3 +74,47 @@ ) ) ) + +;; When a field is removed, indexes in RMW and Cmpxchg should be updated. +(module + ;; GTO should remove the first field because it is never read. The second + ;; field will then be shifted from index 1 to 0. + ;; CHECK: (rec + ;; CHECK-NEXT: (type $struct (shared (struct (field (mut i32))))) + (type $struct (shared (struct (field (mut i64)) (field (mut i32))))) + + ;; CHECK: (type $1 (func (param (ref $struct)))) + + ;; CHECK: (func $use-field (type $1) (param $ref (ref $struct)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.atomic.rmw.and $struct 0 + ;; CHECK-NEXT: (local.get $ref) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.atomic.rmw.cmpxchg $struct 0 + ;; CHECK-NEXT: (local.get $ref) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $use-field (param $ref (ref $struct)) + ;; Use field 1 with an atomic RMW. + (drop + (struct.atomic.rmw.and $struct 1 + (local.get $ref) + (i32.const 1) + ) + ) + ;; Use field 1 with an atomic Cmpxchg. + (drop + (struct.atomic.rmw.cmpxchg $struct 1 + (local.get $ref) + (i32.const 0) + (i32.const 1) + ) + ) + ) +)