diff options
author | Alon Zakai <azakai@google.com> | 2023-04-07 09:48:57 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-07 09:48:57 -0700 |
commit | 9328b6c1906e2fb91253f65c6983547407c0a77c (patch) | |
tree | d5b8dd68c1e1bff5c4c8f0e9b21c0d3fe1f0eb76 | |
parent | e5be9ac2e2f22545ae02db43e9f94dd7d3dbceef (diff) | |
download | binaryen-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.h | 22 | ||||
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 7 | ||||
-rw-r--r-- | test/lit/passes/optimize-instructions-gc.wast | 61 |
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) + ) + ) ) |