Skip to content

Commit 31b4558

Browse files
authored
[WasmGC] OptimizeInstructions: Reorder externalize/internalize operations with ref.as_non_null (#7004)
(any.convert_extern/extern.convert_any (ref.as_non_null ..)) => (ref.as_non_null (any.convert_extern/extern.convert_any ..)) This then allows the RefAsNonNull to be combined with parents in some cases (whereas the reverse allows nothing).
1 parent 34906bf commit 31b4558

File tree

2 files changed

+55
-7
lines changed

2 files changed

+55
-7
lines changed

src/passes/OptimizeInstructions.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2248,8 +2248,27 @@ struct OptimizeInstructions
22482248
}
22492249

22502250
if (curr->op == ExternConvertAny || curr->op == AnyConvertExtern) {
2251-
// We can't optimize these. Even removing a non-null cast is not valid as
2252-
// they allow nulls to filter through, unlike other RefAs*.
2251+
// These pass nulls through, and we can reorder them with null traps:
2252+
//
2253+
// (any.convert_extern/extern.convert_any (ref.as_non_null.. ))
2254+
// =>
2255+
// (ref.as_non_null (any.convert_extern/extern.convert_any ..))
2256+
//
2257+
// By moving the RefAsNonNull outside, it may reach a position where it
2258+
// can be optimized (e.g. if the parent traps anyhow). And,
2259+
// ExternConvertAny/AnyConvertExtern cannot be folded with anything, so
2260+
// there is no harm to moving them inside.
2261+
if (auto* refAsChild = curr->value->dynCast<RefAs>()) {
2262+
if (refAsChild->op == RefAsNonNull) {
2263+
// Reorder and fix up the types.
2264+
curr->value = refAsChild->value;
2265+
curr->finalize();
2266+
refAsChild->value = curr;
2267+
refAsChild->finalize();
2268+
replaceCurrent(refAsChild);
2269+
}
2270+
}
2271+
// TODO: optimize away ExternConvertAny of AnyConvertExtern, etc.
22532272
return;
22542273
}
22552274

test/lit/passes/optimize-instructions-gc-extern.wast

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@
33
;; RUN: | filecheck %s
44

55
(module
6+
;; CHECK: (type $array (array (mut i8)))
7+
(type $array (array (mut i8)))
8+
69
;; CHECK: (func $extern.convert_any (type $0) (param $x anyref) (param $y externref)
710
;; CHECK-NEXT: (drop
811
;; CHECK-NEXT: (extern.convert_any
912
;; CHECK-NEXT: (local.get $x)
1013
;; CHECK-NEXT: )
1114
;; CHECK-NEXT: )
1215
;; CHECK-NEXT: (drop
13-
;; CHECK-NEXT: (extern.convert_any
14-
;; CHECK-NEXT: (ref.as_non_null
16+
;; CHECK-NEXT: (ref.as_non_null
17+
;; CHECK-NEXT: (extern.convert_any
1518
;; CHECK-NEXT: (local.get $x)
1619
;; CHECK-NEXT: )
1720
;; CHECK-NEXT: )
@@ -22,27 +25,30 @@
2225
;; CHECK-NEXT: )
2326
;; CHECK-NEXT: )
2427
;; CHECK-NEXT: (drop
25-
;; CHECK-NEXT: (any.convert_extern
26-
;; CHECK-NEXT: (ref.as_non_null
28+
;; CHECK-NEXT: (ref.as_non_null
29+
;; CHECK-NEXT: (any.convert_extern
2730
;; CHECK-NEXT: (local.get $y)
2831
;; CHECK-NEXT: )
2932
;; CHECK-NEXT: )
3033
;; CHECK-NEXT: )
3134
;; CHECK-NEXT: )
32-
(func $extern.convert_any (export "ext") (param $x (ref null any)) (param $y (ref null extern))
35+
(func $extern.convert_any (param $x (ref null any)) (param $y (ref null extern))
3336
;; We should not change anything here, and also not hit an internal error.
3437
(drop
3538
(extern.convert_any
3639
(local.get $x)
3740
)
3841
)
42+
;; We can reorder the externalize with the ref.as_non_null, which sometimes
43+
;; helps later optimizations, see below.
3944
(drop
4045
(extern.convert_any
4146
(ref.as_non_null
4247
(local.get $x)
4348
)
4449
)
4550
)
51+
;; As the above two cases, but for internalize.
4652
(drop
4753
(any.convert_extern
4854
(local.get $y)
@@ -56,4 +62,27 @@
5662
)
5763
)
5864
)
65+
66+
;; CHECK: (func $convert.optimize.parent (type $1) (param $ext externref)
67+
;; CHECK-NEXT: (drop
68+
;; CHECK-NEXT: (ref.cast (ref $array)
69+
;; CHECK-NEXT: (any.convert_extern
70+
;; CHECK-NEXT: (local.get $ext)
71+
;; CHECK-NEXT: )
72+
;; CHECK-NEXT: )
73+
;; CHECK-NEXT: )
74+
;; CHECK-NEXT: )
75+
(func $convert.optimize.parent (param $ext externref)
76+
;; The ref.cast can fold in the ref.as_non_null, after it is moved
77+
;; outside of the any.convert_extern.
78+
(drop
79+
(ref.cast (ref null $array)
80+
(any.convert_extern
81+
(ref.as_non_null
82+
(local.get $ext)
83+
)
84+
)
85+
)
86+
)
87+
)
5988
)

0 commit comments

Comments
 (0)