Skip to content

Simplify and fix heap type counting #5110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 12 additions & 15 deletions src/ir/module-utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,15 @@ struct CodeScanner
if (auto* call = curr->dynCast<CallIndirect>()) {
counts.note(call->heapType);
} else if (auto* call = curr->dynCast<CallRef>()) {
if (call->isReturn && call->target->type.isFunction()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The isReturn change makes us count in the way that is correct in the spec but we haven't yet moved to, I think? But the idea is that there's no harm to doing that for now, and eventually this code will become right in binaryen as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We emit a type annotation for non-return call_ref as well since #5079, so this is necessary for correctness.

counts.note(call->target->type);
}
counts.note(call->target->type);
} else if (curr->is<RefNull>()) {
counts.note(curr->type);
} else if (auto* make = curr->dynCast<StructNew>()) {
handleMake(make);
} else if (auto* make = curr->dynCast<ArrayNew>()) {
handleMake(make);
} else if (auto* make = curr->dynCast<ArrayInit>()) {
handleMake(make);
} else if (curr->is<StructNew>()) {
counts.note(curr->type);
} else if (curr->is<ArrayNew>()) {
counts.note(curr->type);
} else if (curr->is<ArrayInit>()) {
counts.note(curr->type);
} else if (auto* cast = curr->dynCast<RefCast>()) {
counts.note(cast->intendedType);
} else if (auto* cast = curr->dynCast<RefTest>()) {
Expand All @@ -77,6 +75,11 @@ struct CodeScanner
counts.note(get->ref->type);
} else if (auto* set = curr->dynCast<StructSet>()) {
counts.note(set->ref->type);
} else if (auto* get = curr->dynCast<ArrayGet>()) {
counts.note(get->ref->type);
} else if (auto* set = curr->dynCast<ArraySet>()) {
counts.note(set->ref->type);

} else if (Properties::isControlFlowStructure(curr)) {
if (curr->type.isTuple()) {
// TODO: Allow control flow to have input types as well
Expand All @@ -86,12 +89,6 @@ struct CodeScanner
}
}
}

template<typename T> void handleMake(T* curr) {
if (curr->type != Type::unreachable) {
counts.note(curr->type.getHeapType());
}
}
};

Counts getHeapTypeCounts(Module& wasm) {
Expand Down
6 changes: 3 additions & 3 deletions test/heap-types.wast.from-wast
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
(type $none_=>_none (func))
(type $struct.C (struct (field $named-mut (mut f32))))
(type $matrix (array (mut (ref null $vector))))
(type $grandchild (struct (field i32) (field i64)))
(type $bytes (array (mut i8)))
(type $grandchild (struct (field i32) (field i64)))
(type $anyref_=>_none (func (param anyref)))
(type $nested-child-struct (struct (field (mut (ref $child)))))
(type $words (array (mut i32)))
(type $nested-child-array (array (mut (ref $child))))
(type $child (struct (field i32)))
(type $ref|$struct.A|_=>_ref|$struct.B| (func (param (ref $struct.A)) (result (ref $struct.B))))
(type $ref|$vector|_=>_ref|$matrix| (func (param (ref $vector)) (result (ref $matrix))))
(type $words (array (mut i32)))
(type $nested-child-array (array (mut (ref $child))))
(type $ref|$vector|_ref?|$vector|_=>_none (func (param (ref $vector) (ref null $vector))))
(type $none_=>_ref|$vector| (func (result (ref $vector))))
(type $none_=>_ref|$bytes| (func (result (ref $bytes))))
Expand Down
6 changes: 3 additions & 3 deletions test/heap-types.wast.fromBinary
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
(type $struct.B (struct (field i8) (field (mut i16)) (field (ref $struct.A)) (field (mut (ref $struct.A)))))
(type $none_=>_none (func))
(type $matrix (array (mut (ref null $vector))))
(type $bytes (array (mut i8)))
(type $struct.C (struct (field $named-mut (mut f32))))
(type $grandchild (struct (field i32) (field i64)))
(type $bytes (array (mut i8)))
(type $anyref_=>_none (func (param anyref)))
(type $nested-child-struct (struct (field (mut (ref $child)))))
(type $words (array (mut i32)))
(type $nested-child-array (array (mut (ref $child))))
(type $child (struct (field i32)))
(type $ref|$struct.A|_=>_ref|$struct.B| (func (param (ref $struct.A)) (result (ref $struct.B))))
(type $ref|$vector|_=>_ref|$matrix| (func (param (ref $vector)) (result (ref $matrix))))
(type $words (array (mut i32)))
(type $nested-child-array (array (mut (ref $child))))
(type $ref|$vector|_ref?|$vector|_=>_none (func (param (ref $vector) (ref null $vector))))
(type $none_=>_ref|$vector| (func (result (ref $vector))))
(type $none_=>_ref|$bytes| (func (result (ref $bytes))))
Expand Down
6 changes: 3 additions & 3 deletions test/heap-types.wast.fromBinary.noDebugInfo
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
(type ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|} (struct (field i8) (field (mut i16)) (field (ref ${i32_f32_f64})) (field (mut (ref ${i32_f32_f64})))))
(type $none_=>_none (func))
(type $[mut:ref?|[mut:f64]|] (array (mut (ref null $[mut:f64]))))
(type $[mut:i8] (array (mut i8)))
(type ${mut:f32} (struct (field (mut f32))))
(type ${i32_i64} (struct (field i32) (field i64)))
(type $[mut:i8] (array (mut i8)))
(type $anyref_=>_none (func (param anyref)))
(type ${mut:ref|{i32}|} (struct (field (mut (ref ${i32})))))
(type $[mut:i32] (array (mut i32)))
(type $[mut:ref|{i32}|] (array (mut (ref ${i32}))))
(type ${i32} (struct (field i32)))
(type $ref|{i32_f32_f64}|_=>_ref|{i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|}| (func (param (ref ${i32_f32_f64})) (result (ref ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|}))))
(type $ref|[mut:f64]|_=>_ref|[mut:ref?|[mut:f64]|]| (func (param (ref $[mut:f64])) (result (ref $[mut:ref?|[mut:f64]|]))))
(type $[mut:i32] (array (mut i32)))
(type $[mut:ref|{i32}|] (array (mut (ref ${i32}))))
(type $ref|[mut:f64]|_ref?|[mut:f64]|_=>_none (func (param (ref $[mut:f64]) (ref null $[mut:f64]))))
(type $none_=>_ref|[mut:f64]| (func (result (ref $[mut:f64]))))
(type $none_=>_ref|[mut:i8]| (func (result (ref $[mut:i8]))))
Expand Down
3 changes: 2 additions & 1 deletion test/lit/passes/cfp.wast
Original file line number Diff line number Diff line change
Expand Up @@ -2028,10 +2028,11 @@
;; Test a global type other than i32. Arrays of structs are a realistic case
;; as they are used to implement itables.

;; CHECK: (type $itable (array_subtype (ref $vtable) data))

;; CHECK: (type $vtable (struct_subtype (field funcref) data))
(type $vtable (struct funcref))

;; CHECK: (type $itable (array_subtype (ref $vtable) data))
(type $itable (array (ref $vtable)))

;; CHECK: (type $object (struct_subtype (field $itable (ref $itable)) data))
Expand Down
4 changes: 2 additions & 2 deletions test/lit/passes/gufa-refs.wast
Original file line number Diff line number Diff line change
Expand Up @@ -4203,11 +4203,11 @@
(module
;; CHECK: (type $i1 (func_subtype (param i32) func))
(type $i1 (func (param i32)))
;; CHECK: (type $none_=>_i32 (func_subtype (result i32) func))

;; CHECK: (type $i2 (func_subtype (param i32) func))
(type $i2 (func (param i32)))

;; CHECK: (type $none_=>_i32 (func_subtype (result i32) func))

;; CHECK: (type $none_=>_none (func_subtype func))

;; CHECK: (import "a" "b" (func $import (result i32)))
Expand Down
20 changes: 10 additions & 10 deletions test/lit/passes/instrument-memory-gc.wast
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,16 @@
(field f32)
(field $named f64)
))
;; CHECK: (type $array (array (mut f64)))
;; NOMNL: (type $array (array_subtype (mut f64) data))
(type $array (array (mut f64)))

;; CHECK: (type $i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32) (result i32)))

;; CHECK: (type $ref|$struct|_=>_none (func (param (ref $struct))))

;; CHECK: (type $ref|$array|_=>_none (func (param (ref $array))))

;; CHECK: (type $array (array (mut f64)))
;; NOMNL: (type $i32_i32_i32_i32_=>_i32 (func_subtype (param i32 i32 i32 i32) (result i32) func))

;; NOMNL: (type $ref|$struct|_=>_none (func_subtype (param (ref $struct)) func))

;; NOMNL: (type $ref|$array|_=>_none (func_subtype (param (ref $array)) func))

;; NOMNL: (type $array (array_subtype (mut f64) data))
(type $array (array (mut f64)))

;; CHECK: (import "env" "load_ptr" (func $load_ptr (param i32 i32 i32 i32) (result i32)))

;; CHECK: (import "env" "load_val_i32" (func $load_val_i32 (param i32 i32) (result i32)))
Expand Down Expand Up @@ -132,6 +126,12 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; NOMNL: (type $i32_i32_i32_i32_=>_i32 (func_subtype (param i32 i32 i32 i32) (result i32) func))

;; NOMNL: (type $ref|$struct|_=>_none (func_subtype (param (ref $struct)) func))

;; NOMNL: (type $ref|$array|_=>_none (func_subtype (param (ref $array)) func))

;; NOMNL: (import "env" "load_ptr" (func $load_ptr (param i32 i32 i32 i32) (result i32)))

;; NOMNL: (import "env" "load_val_i32" (func $load_val_i32 (param i32 i32) (result i32)))
Expand Down
3 changes: 2 additions & 1 deletion test/lit/passes/merge-blocks.wast
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
(module
(type $anyref_=>_none (func (param anyref)))

;; CHECK: (type $array (array (mut i32)))

;; CHECK: (type $struct (struct (field (mut i32))))
(type $struct (struct (field (mut i32))))

;; CHECK: (type $array (array (mut i32)))
(type $array (array (mut i32)))

;; CHECK: (func $br_on_to_drop
Expand Down
6 changes: 2 additions & 4 deletions test/lit/passes/optimize-instructions-gc.wast
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,12 @@
;; NOMNL: (type $A (struct_subtype (field i32) data))
(type $A (struct (field i32)))

;; CHECK: (type $B (struct (field i32) (field i32) (field f32)))

;; CHECK: (type $array (array (mut i8)))
;; NOMNL: (type $B (struct_subtype (field i32) (field i32) (field f32) $A))

;; NOMNL: (type $array (array_subtype (mut i8) data))
(type $array (array (mut i8)))

;; CHECK: (type $B (struct (field i32) (field i32) (field f32)))
;; NOMNL: (type $B (struct_subtype (field i32) (field i32) (field f32) $A))
(type $B (struct_subtype (field i32) (field i32) (field f32) $A))

;; CHECK: (type $B-child (struct (field i32) (field i32) (field f32) (field i64)))
Expand Down
6 changes: 4 additions & 2 deletions test/lit/passes/precompute-gc.wast
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@

;; two incompatible struct types
(type $A (struct (field (mut f32))))
;; CHECK: (type $func-return-i32 (func (result i32)))

;; CHECK: (type $B (struct (field (mut f64))))
;; NOMNL: (type $func-return-i32 (func_subtype (result i32) func))

;; NOMNL: (type $B (struct_subtype (field (mut f64)) data))
(type $B (struct (field (mut f64))))

;; CHECK: (type $func-return-i32 (func (result i32)))
;; NOMNL: (type $func-return-i32 (func_subtype (result i32) func))
(type $func-return-i32 (func (result i32)))

;; CHECK: (import "fuzzing-support" "log-i32" (func $log (param i32)))
Expand Down
12 changes: 8 additions & 4 deletions test/lit/passes/signature-refining.wast
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@
(module
;; As above, but the call is via call_ref.

;; CHECK: (type $sig (func_subtype (param (ref $struct)) func))

;; CHECK: (type $struct (struct_subtype data))
(type $struct (struct_subtype data))

;; CHECK: (type $sig (func_subtype (param (ref $struct)) func))
(type $sig (func_subtype (param anyref) func))

;; CHECK: (type $none_=>_none (func_subtype func))
Expand Down Expand Up @@ -71,10 +72,11 @@
;; call uses a nullable $struct, the other a non-nullable dataref, so the LUB
;; is a nullable dataref.

;; CHECK: (type $sig (func_subtype (param dataref) func))

;; CHECK: (type $struct (struct_subtype data))
(type $struct (struct_subtype data))

;; CHECK: (type $sig (func_subtype (param dataref) func))
(type $sig (func_subtype (param anyref) func))

;; CHECK: (type $none_=>_none (func_subtype func))
Expand Down Expand Up @@ -266,10 +268,11 @@
;; An unreachable value does not prevent optimization: we will update the
;; param to be $struct.

;; CHECK: (type $sig (func_subtype (param (ref $struct)) func))

;; CHECK: (type $struct (struct_subtype data))
(type $struct (struct_subtype data))

;; CHECK: (type $sig (func_subtype (param (ref $struct)) func))
(type $sig (func_subtype (param anyref) func))

;; CHECK: (type $none_=>_none (func_subtype func))
Expand Down Expand Up @@ -356,9 +359,10 @@
;; CHECK: (type $struct (struct_subtype data))
(type $struct (struct_subtype data))

;; CHECK: (type $sig-2 (func_subtype (param eqref (ref $struct)) func))

;; CHECK: (type $sig-1 (func_subtype (param dataref anyref) func))
(type $sig-1 (func_subtype (param anyref) (param anyref) func))
;; CHECK: (type $sig-2 (func_subtype (param eqref (ref $struct)) func))
(type $sig-2 (func_subtype (param anyref) (param anyref) func))

;; CHECK: (type $none_=>_none (func_subtype func))
Expand Down
2 changes: 1 addition & 1 deletion test/passes/Oz_fuzz-exec_all-features.txt
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@
[fuzz-exec] calling static-br_on_cast_fail
[LoggingExternalInterface logging -2]
(module
(type $void_func (func))
(type $bytes (array (mut i8)))
(type $void_func (func))
(type $struct (struct (field (mut i32))))
(type $i32_=>_none (func (param i32)))
(type $extendedstruct (struct (field (mut i32)) (field f64)))
Expand Down