diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index 549ec7169ef..381d4e49441 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -1776,6 +1776,7 @@ void TNHOracle::scan(Function* func, void visitStructCmpxchg(StructCmpxchg* curr) { notePossibleTrap(curr->ref); } + // TODO: visitStructWait void visitArrayGet(ArrayGet* curr) { notePossibleTrap(curr->ref); } void visitArraySet(ArraySet* curr) { notePossibleTrap(curr->ref); } void visitArrayLoad(ArrayLoad* curr) { notePossibleTrap(curr->ref); } diff --git a/src/ir/struct-utils.h b/src/ir/struct-utils.h index 471a580a9d4..c90fbb85348 100644 --- a/src/ir/struct-utils.h +++ b/src/ir/struct-utils.h @@ -287,6 +287,8 @@ struct StructScanner : public WalkerPass> { noteExpressionOrCopy(curr->replacement, type, index, info); } + // TODO: visitStructWait + void visitRefCast(RefCast* curr) { if (curr->desc) { // We may try to read a descriptor from anything arriving in |curr->ref|, diff --git a/src/passes/GlobalTypeOptimization.cpp b/src/passes/GlobalTypeOptimization.cpp index 8cfa4960cc9..b0bb31edbd9 100644 --- a/src/passes/GlobalTypeOptimization.cpp +++ b/src/passes/GlobalTypeOptimization.cpp @@ -838,6 +838,8 @@ struct GlobalTypeOptimization : public Pass { assert(newIndex != RemovedField); curr->index = newIndex; } + + // TODO: visitStructWait }; PassRunner runner(getPassRunner()); diff --git a/src/passes/TypeRefining.cpp b/src/passes/TypeRefining.cpp index 720233cf9ae..1d4fad7d85d 100644 --- a/src/passes/TypeRefining.cpp +++ b/src/passes/TypeRefining.cpp @@ -551,7 +551,12 @@ struct TypeRefining : public Pass { } void visitStructCmpxchg(StructCmpxchg* curr) { - if (curr->type == Type::unreachable) { + if (curr->ref->type == Type::unreachable) { + // Ignore unreachable code. Note that we check curr->ref, not curr, + // as curr may be unreachable because of another operand than the ref + // and the replacement value (the expected value may be the + // unreachable one). In that case, the replacement must still validate + // as if it were written, so we must fix it up below. return; } auto type = curr->ref->type.getHeapType(); @@ -563,6 +568,8 @@ struct TypeRefining : public Pass { curr->replacement = fixType(curr->replacement, fieldType); } + // TODO: visitStructWait + bool refinalize = false; // Fix up a given value so it fits into the type the location it is diff --git a/test/lit/passes/type-refining-gufa-rmw.wast b/test/lit/passes/type-refining-gufa-rmw.wast index 24aec709a98..760dd5cd75f 100644 --- a/test/lit/passes/type-refining-gufa-rmw.wast +++ b/test/lit/passes/type-refining-gufa-rmw.wast @@ -415,3 +415,62 @@ ) ) ) + +(module + ;; NRML: (type $struct (sub (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)))))) + + ;; NRML: (type $1 (func (param (ref null $struct)))) + + ;; NRML: (func $test (type $1) (param $struct (ref null $struct)) + ;; NRML-NEXT: (drop + ;; NRML-NEXT: (struct.new_default $struct) + ;; NRML-NEXT: ) + ;; NRML-NEXT: (drop + ;; NRML-NEXT: (struct.atomic.rmw.cmpxchg acqrel acqrel $struct 0 + ;; NRML-NEXT: (local.get $struct) + ;; NRML-NEXT: (unreachable) + ;; NRML-NEXT: (local.get $struct) + ;; NRML-NEXT: ) + ;; NRML-NEXT: ) + ;; NRML-NEXT: ) + ;; GUFA: (type $1 (func (param (ref null $struct)))) + + ;; GUFA: (func $test (type $1) (param $struct (ref null $struct)) + ;; GUFA-NEXT: (drop + ;; GUFA-NEXT: (struct.new_default $struct) + ;; GUFA-NEXT: ) + ;; GUFA-NEXT: (drop + ;; 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: (drop + ;; GUFA-NEXT: (local.get $struct) + ;; GUFA-NEXT: ) + ;; GUFA-NEXT: (ref.null none) + ;; GUFA-NEXT: ) + ;; GUFA-NEXT: ) + ;; GUFA-NEXT: ) + ;; GUFA-NEXT: ) + (func $test (param $struct (ref null $struct)) + ;; Use the type, writing only nulls. + (drop + (struct.new_default $struct) + ) + ;; An unreachable cmpxchg, but where the ref and value are not unreachable. + ;; The value must still validate as if it were written, so we will fix it up + ;; with a null, as the field is refined to a null (in GUFA mode, which + ;; does that refining). + (drop + (struct.atomic.rmw.cmpxchg acqrel acqrel $struct 0 + (local.get $struct) + (unreachable) + (local.get $struct) + ) + ) + ) +) +