summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2023-04-07 09:48:57 -0700
committerGitHub <noreply@github.com>2023-04-07 09:48:57 -0700
commit9328b6c1906e2fb91253f65c6983547407c0a77c (patch)
treed5b8dd68c1e1bff5c4c8f0e9b21c0d3fe1f0eb76
parente5be9ac2e2f22545ae02db43e9f94dd7d3dbceef (diff)
downloadbinaryen-9328b6c1906e2fb91253f65c6983547407c0a77c.tar.gz
binaryen-9328b6c1906e2fb91253f65c6983547407c0a77c.tar.bz2
binaryen-9328b6c1906e2fb91253f65c6983547407c0a77c.zip
[Wasm GC] Fix an assertion in array.set processing in OptimizeInstructions (#5641)
-rw-r--r--src/ir/gc-type-utils.h22
-rw-r--r--src/passes/OptimizeInstructions.cpp7
-rw-r--r--test/lit/passes/optimize-instructions-gc.wast61
3 files changed, 83 insertions, 7 deletions
diff --git a/src/ir/gc-type-utils.h b/src/ir/gc-type-utils.h
index 1fecca22e..53cc6feb2 100644
--- a/src/ir/gc-type-utils.h
+++ b/src/ir/gc-type-utils.h
@@ -105,6 +105,28 @@ inline EvaluationResult evaluateCastCheck(Type refType, Type castType) {
return Unknown;
}
+// Given a reference and a field index, return the field for it, if one exists.
+// One may not exist if the reference is unreachable, or a bottom type.
+//
+// The index is optional as it does not matter for an array.
+//
+// TODO: use in more places
+inline std::optional<Field> getField(HeapType type, Index index = 0) {
+ if (type.isStruct()) {
+ return type.getStruct().fields[index];
+ } else if (type.isArray()) {
+ return type.getArray().element;
+ }
+ return {};
+}
+
+inline std::optional<Field> getField(Type type, Index index = 0) {
+ if (type.isRef()) {
+ return getField(type.getHeapType(), index);
+ }
+ return {};
+}
+
} // namespace wasm::GCTypeUtils
#endif // wasm_ir_gc_type_utils_h
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index e71519012..e6b19a6de 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -1941,9 +1941,10 @@ struct OptimizeInstructions
return;
}
- if (curr->ref->type != Type::unreachable && curr->value->type.isInteger()) {
- auto element = curr->ref->type.getHeapType().getArray().element;
- optimizeStoredValue(curr->value, element.getByteSize());
+ if (curr->value->type.isInteger()) {
+ if (auto field = GCTypeUtils::getField(curr->ref->type)) {
+ optimizeStoredValue(curr->value, field->getByteSize());
+ }
}
}
diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast
index adcf654d6..5711d9bc2 100644
--- a/test/lit/passes/optimize-instructions-gc.wast
+++ b/test/lit/passes/optimize-instructions-gc.wast
@@ -28,17 +28,17 @@
(type $B (struct_subtype (field i32) (field i32) (field f32) $A))
+ ;; CHECK: (type $void (func))
+
;; CHECK: (type $B-child (struct_subtype (field i32) (field i32) (field f32) (field i64) $B))
+ ;; NOMNL: (type $void (func))
+
;; NOMNL: (type $B-child (struct_subtype (field i32) (field i32) (field f32) (field i64) $B))
(type $B-child (struct_subtype (field i32) (field i32) (field f32) (field i64) $B))
(type $empty (struct))
- ;; CHECK: (type $void (func))
-
;; CHECK: (type $C (struct_subtype (field i32) (field i32) (field f64) $A))
- ;; NOMNL: (type $void (func))
-
;; NOMNL: (type $C (struct_subtype (field i32) (field i32) (field f64) $A))
(type $C (struct_subtype (field i32) (field i32) (field f64) $A))
@@ -3200,4 +3200,57 @@
(i32.const 100)
)
)
+
+ ;; CHECK: (func $set.array.null (type $void)
+ ;; CHECK-NEXT: (local $temp (ref none))
+ ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.tee $temp
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $set.array.null (type $void)
+ ;; NOMNL-NEXT: (local $temp (ref none))
+ ;; NOMNL-NEXT: (block ;; (replaces something unreachable we can't emit)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (local.tee $temp
+ ;; NOMNL-NEXT: (unreachable)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (i32.const 2)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (i32.const 3)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (unreachable)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $set.array.null
+ (local $temp (ref none))
+
+ ;; The cast of none will be inferred to be an unreachable. That does not
+ ;; propagate through the tee during this pass, however, as it only
+ ;; happens during the refinalize at the very end. We must be careful not to
+ ;; hit an internal error while processing the array.set, as its reference's
+ ;; fallthrough value has null type and not array type.
+ (array.set $array
+ (local.tee $temp
+ (ref.as_non_null
+ (ref.null none)
+ )
+ )
+ (i32.const 2)
+ (i32.const 3)
+ )
+ )
)