diff options
author | Alon Zakai <azakai@google.com> | 2024-02-27 13:39:53 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-27 13:39:53 -0800 |
commit | d5157e0fda52e09f7daccce17cd517129b9bf67a (patch) | |
tree | 41bd04f4478b11cc856d523a1349c5c3eb7b2fde /test | |
parent | f86813722ce81257f475c43024327210bd28935e (diff) | |
download | binaryen-d5157e0fda52e09f7daccce17cd517129b9bf67a.tar.gz binaryen-d5157e0fda52e09f7daccce17cd517129b9bf67a.tar.bz2 binaryen-d5157e0fda52e09f7daccce17cd517129b9bf67a.zip |
SubtypingDiscoverer: Differentiate non-flow subtyping constraints (#6344)
When we do a local.set of a value into a local then we have both a subtyping constraint - for
the value to be valid to put in that local - and also a flow of a value, which can then reach
more places. Such flow then interacts with casts in Unsubtyping, since it needs to know
what can flow where in order to know how casts force us to keep subtyping relations.
That regressed in the not-actually-NFC #6323 in which I added the innocuous lines
to add subtyping constraints in ref.eq. It seems fine to require that the arms of a
RefEq must be of type eqref, but Unsubtyping then assuming those arms flowed into
a location of type eqref... which means casts might force us to not optimize some
things.
To fix this, differentiate the rare case of non-flowing subtyping constraints, which is
basically only RefEq. There are perhaps a few more cases (like i31 operations) but they
do not matter in practice for Unsubtyping anyhow; I suggest we land this first to undo
the regression and then at our leisure investigate the other instructions.
Diffstat (limited to 'test')
-rw-r--r-- | test/lit/passes/unsubtyping-casts.wast | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/test/lit/passes/unsubtyping-casts.wast b/test/lit/passes/unsubtyping-casts.wast index c1993e8b4..8f0f66ef2 100644 --- a/test/lit/passes/unsubtyping-casts.wast +++ b/test/lit/passes/unsubtyping-casts.wast @@ -372,6 +372,109 @@ ) ) +;; As above, but now with some ref.eq added. Those should not inhibit +;; optimizations: as before, $bot no longer needs to subtype from $mid (but +;; $mid must subtype from $top). ref.eq does add a requirement on subtyping +;; (that the type be a subtype of eq), but ref.eq does not actually flow the +;; inputs it receives anywhere, so that doesn't stop us from removing subtyping +;; from user types. +(module + (rec + ;; CHECK: (rec + ;; CHECK-NEXT: (type $top (sub (struct ))) + (type $top (sub (struct))) + ;; CHECK: (type $mid (sub $top (struct ))) + (type $mid (sub $top (struct))) + ;; CHECK: (type $bot (sub (struct ))) + (type $bot (sub $mid (struct))) + ) + + ;; CHECK: (type $3 (func (param anyref (ref $top) (ref $mid) (ref $bot)))) + + ;; CHECK: (func $cast (type $3) (param $any anyref) (param $top (ref $top)) (param $mid (ref $mid)) (param $bot (ref $bot)) + ;; CHECK-NEXT: (local $l anyref) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (local.get $top) + ;; CHECK-NEXT: (local.get $mid) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (local.get $top) + ;; CHECK-NEXT: (local.get $bot) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (local.get $mid) + ;; CHECK-NEXT: (local.get $bot) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.cast (ref $bot) + ;; CHECK-NEXT: (local.get $any) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.cast (ref $top) + ;; CHECK-NEXT: (local.get $any) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.cast (ref $mid) + ;; CHECK-NEXT: (local.get $any) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $l + ;; CHECK-NEXT: (struct.new_default $mid) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $cast (param $any anyref) (param $top (ref $top)) (param $mid (ref $mid)) (param $bot (ref $bot)) + (local $l anyref) + (drop + (ref.eq + (local.get $top) + (local.get $mid) + ) + ) + (drop + (ref.eq + (local.get $top) + (local.get $bot) + ) + ) + (drop + (ref.eq + (local.get $mid) + (local.get $bot) + ) + ) + (drop + ;; Cast any -> $bot + (ref.cast (ref $bot) + (local.get $any) + ) + ) + (drop + ;; Cast any -> $top + (ref.cast (ref $top) + (local.get $any) + ) + ) + (drop + ;; Cast any -> $mid + (ref.cast (ref $mid) + (local.get $any) + ) + ) + + (local.set $l + (struct.new $mid) + ) + ) +) + (module (rec ;; CHECK: (rec |