Skip to content

Commit e185ff9

Browse files
authored
Avoid invalid exact casts in RemoveUnusedBrs (#7522)
RemoveUnusedBrs can introduce new casts when optimizing out br_on_cast and br_on_cast_fail instructions. This happens when the pass finds a more precise type for the fallthrough value reaching the casting branch, allowing it to improve the cast target type. When the branch is subsequently optimized out, this precise type information is recovered with an inserted cast. Update the pass to avoid creating invalid casts to exact types when custom descriptors is not enabled.
1 parent ffa65f0 commit e185ff9

File tree

2 files changed

+101
-32
lines changed

2 files changed

+101
-32
lines changed

src/passes/RemoveUnusedBrs.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,12 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
906906
// further optimizations after this, and those optimizations might even
907907
// benefit from this improvement.
908908
auto glb = Type::getGreatestLowerBound(curr->castType, refType);
909+
if (!getModule()->features.hasCustomDescriptors() && glb.isExact() &&
910+
!curr->castType.isExact()) {
911+
// When custom descriptors is not enabled, nontrivial exact casts are
912+
// not allowed.
913+
glb = glb.with(Inexact);
914+
}
909915
if (curr->op == BrOnCastFail) {
910916
// BrOnCastFail sends the input type, with adjusted nullability. The
911917
// input heap type makes sense for the branch target, and we will not
Lines changed: 95 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,105 @@
11
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
22

3-
;; RUN: wasm-opt %s -all --remove-unused-brs -S -o - | filecheck %s
4-
53
;; Check that we optimize the cast correctly when the fallthrough has exact
6-
;; type. In particular, we should not insert a ref.as_non_null, which would
7-
;; trap.
4+
;; type, whether or not custom descriptors is enabled.
5+
6+
;; RUN: wasm-opt %s -all --remove-unused-brs -S -o - | filecheck %s
7+
;; RUN: wasm-opt %s -all --disable-custom-descriptors --remove-unused-brs -S -o - | filecheck %s --check-prefix=NO_CD
88

99
(module
10-
;; CHECK: (type $struct (struct))
11-
(type $struct (struct))
12-
;; CHECK: (func $br_on_cast_fail (type $1) (param $0 (ref null (exact $struct)))
13-
;; CHECK-NEXT: (local $1 (ref null $struct))
14-
;; CHECK-NEXT: (drop
15-
;; CHECK-NEXT: (block $block
16-
;; CHECK-NEXT: (drop
17-
;; CHECK-NEXT: (ref.cast (ref null (exact $struct))
18-
;; CHECK-NEXT: (local.tee $1
19-
;; CHECK-NEXT: (local.get $0)
20-
;; CHECK-NEXT: )
21-
;; CHECK-NEXT: )
22-
;; CHECK-NEXT: )
23-
;; CHECK-NEXT: (return)
24-
;; CHECK-NEXT: )
25-
;; CHECK-NEXT: )
26-
;; CHECK-NEXT: )
27-
(func $br_on_cast_fail (param (ref null (exact $struct)))
28-
(local $1 (ref null $struct))
29-
(drop
30-
(block $block (result (ref $struct))
10+
;; CHECK: (type $foo (struct))
11+
;; NO_CD: (type $foo (struct))
12+
(type $foo (struct))
13+
14+
;; CHECK: (func $br_on_cast (type $1) (param $0 (ref (exact $foo)))
15+
;; CHECK-NEXT: (local $inexact (ref $foo))
16+
;; CHECK-NEXT: (drop
17+
;; CHECK-NEXT: (block $block (result (ref (exact $foo)))
18+
;; CHECK-NEXT: (drop
19+
;; CHECK-NEXT: (br $block
20+
;; CHECK-NEXT: (ref.cast (ref (exact $foo))
21+
;; CHECK-NEXT: (local.tee $inexact
22+
;; CHECK-NEXT: (local.get $0)
23+
;; CHECK-NEXT: )
24+
;; CHECK-NEXT: )
25+
;; CHECK-NEXT: )
26+
;; CHECK-NEXT: )
27+
;; CHECK-NEXT: (local.get $0)
28+
;; CHECK-NEXT: )
29+
;; CHECK-NEXT: )
30+
;; CHECK-NEXT: )
31+
;; NO_CD: (func $br_on_cast (type $1) (param $0 (ref (exact $foo)))
32+
;; NO_CD-NEXT: (local $inexact (ref $foo))
33+
;; NO_CD-NEXT: (drop
34+
;; NO_CD-NEXT: (block $block (result (ref $foo))
35+
;; NO_CD-NEXT: (drop
36+
;; NO_CD-NEXT: (br $block
37+
;; NO_CD-NEXT: (local.tee $inexact
38+
;; NO_CD-NEXT: (local.get $0)
39+
;; NO_CD-NEXT: )
40+
;; NO_CD-NEXT: )
41+
;; NO_CD-NEXT: )
42+
;; NO_CD-NEXT: (local.get $0)
43+
;; NO_CD-NEXT: )
44+
;; NO_CD-NEXT: )
45+
;; NO_CD-NEXT: )
46+
(func $br_on_cast (param (ref (exact $foo)))
47+
(local $inexact (ref $foo))
48+
(drop
49+
(block (result (ref $foo))
50+
(drop
51+
(br_on_cast 0 anyref (ref $foo)
52+
(local.tee $inexact
53+
(local.get 0)
54+
)
55+
)
56+
)
57+
(local.get 0)
58+
)
59+
)
60+
)
61+
62+
;; CHECK: (func $br_on_cast_fail (type $1) (param $0 (ref (exact $foo)))
63+
;; CHECK-NEXT: (local $inexact (ref $foo))
64+
;; CHECK-NEXT: (drop
65+
;; CHECK-NEXT: (block $block (result (ref (exact $foo)))
66+
;; CHECK-NEXT: (drop
67+
;; CHECK-NEXT: (ref.cast (ref (exact $foo))
68+
;; CHECK-NEXT: (local.tee $inexact
69+
;; CHECK-NEXT: (local.get $0)
70+
;; CHECK-NEXT: )
71+
;; CHECK-NEXT: )
72+
;; CHECK-NEXT: )
73+
;; CHECK-NEXT: (local.get $0)
74+
;; CHECK-NEXT: )
75+
;; CHECK-NEXT: )
76+
;; CHECK-NEXT: )
77+
;; NO_CD: (func $br_on_cast_fail (type $1) (param $0 (ref (exact $foo)))
78+
;; NO_CD-NEXT: (local $inexact (ref $foo))
79+
;; NO_CD-NEXT: (drop
80+
;; NO_CD-NEXT: (block $block (result (ref (exact $foo)))
81+
;; NO_CD-NEXT: (drop
82+
;; NO_CD-NEXT: (local.tee $inexact
83+
;; NO_CD-NEXT: (local.get $0)
84+
;; NO_CD-NEXT: )
85+
;; NO_CD-NEXT: )
86+
;; NO_CD-NEXT: (local.get $0)
87+
;; NO_CD-NEXT: )
88+
;; NO_CD-NEXT: )
89+
;; NO_CD-NEXT: )
90+
(func $br_on_cast_fail (param (ref (exact $foo)))
91+
(local $inexact (ref $foo))
3192
(drop
32-
(br_on_cast_fail $block (ref null $struct) (ref null $struct)
33-
(local.tee $1
34-
(local.get 0)
93+
(block (result (ref $foo))
94+
(drop
95+
(br_on_cast_fail 0 anyref (ref $foo)
96+
(local.tee $inexact
97+
(local.get 0)
98+
)
99+
)
100+
)
101+
(local.get 0)
35102
)
36-
)
37103
)
38-
(return)
39-
)
40104
)
41-
)
42105
)

0 commit comments

Comments
 (0)