summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ir/possible-contents.cpp17
-rw-r--r--test/lit/passes/gufa-refs.wast59
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)
+ )
+ )
+ )
+)