diff options
-rw-r--r-- | src/ir/possible-contents.cpp | 17 | ||||
-rw-r--r-- | test/lit/passes/gufa-refs.wast | 59 |
2 files changed, 73 insertions, 3 deletions
diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index 8ed2118fe..b2a0b417a 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -618,6 +618,7 @@ struct InfoCollector addRoot(curr); } void visitTableGet(TableGet* curr) { + // TODO: be more precise addRoot(curr); } void visitTableSet(TableSet* curr) {} @@ -992,6 +993,7 @@ struct InfoCollector if (curr->type == Type::unreachable) { return; } + // See ArrayCopy, above. Builder builder(*getModule()); auto* set = builder.makeArraySet(curr->ref, curr->index, curr->value); visitArraySet(set); @@ -1000,9 +1002,18 @@ struct InfoCollector if (curr->type == Type::unreachable) { return; } - // TODO: Modeling the write to the array can be similar to the above, but - // how should the read from the segment be modeled? - WASM_UNREACHABLE("unimplemented"); + // See ArrayCopy, above. Here an additional complexity is that we need to + // model the read from the segment. As in TableGet, for now we just assume + // any value is possible there (a root in the graph), which we set up + // manually here as a fake unknown value, using a fake local.get that we + // root. + // TODO: be more precise about what is in the table + auto valueType = curr->ref->type.getHeapType().getArray().element.type; + Builder builder(*getModule()); + auto* get = builder.makeLocalGet(-1, valueType); + addRoot(get); + auto* set = builder.makeArraySet(curr->ref, curr->index, get); + visitArraySet(set); } void visitStringNew(StringNew* curr) { if (curr->type == Type::unreachable) { diff --git a/test/lit/passes/gufa-refs.wast b/test/lit/passes/gufa-refs.wast index 8bcf5c6a5..fe3eb70fc 100644 --- a/test/lit/passes/gufa-refs.wast +++ b/test/lit/passes/gufa-refs.wast @@ -5466,3 +5466,62 @@ ) ) ) + +;; Verify we do not error or misoptimize with array.init_elem. +(module + ;; CHECK: (type $vector (array (mut funcref))) + (type $vector (array (mut funcref))) + + (elem func) + + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (elem $0 func) + + ;; CHECK: (elem declare func $test) + + ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK-NEXT: (local $ref (ref $vector)) + ;; CHECK-NEXT: (local.set $ref + ;; CHECK-NEXT: (array.new $vector + ;; CHECK-NEXT: (ref.func $test) + ;; CHECK-NEXT: (i32.const 100) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (array.init_elem $vector $0 + ;; CHECK-NEXT: (local.get $ref) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (array.get $vector + ;; CHECK-NEXT: (local.get $ref) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $test + (local $ref (ref $vector)) + (local.set $ref + (array.new $vector + (ref.func $test) + (i32.const 100) + ) + ) + (array.init_elem $vector 0 + (local.get $ref) + (i32.const 1) + (i32.const 1) + (i32.const 1) + ) + ;; We wrote a specific ref.func earlier, but also we did an init_elem whose + ;; values we consider unknown, so we will not optimize this get. + (drop + (array.get $vector + (local.get $ref) + (i32.const 1) + ) + ) + ) +) |