Skip to content

Commit 8b47ebf

Browse files
authored
Fix optimization of casts to exact null types (#7365)
The logic for optimizing ref.casts that are known to succeed did not account for possible casts to exact null types, leading to it producing invalid IR. Fix it and add a test.
1 parent b29abbe commit 8b47ebf

File tree

2 files changed

+34
-17
lines changed

2 files changed

+34
-17
lines changed

src/passes/OptimizeInstructions.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2277,10 +2277,14 @@ struct OptimizeInstructions
22772277
// emit a null check.
22782278
bool needsNullCheck = ref->type.getNullability() == Nullable &&
22792279
curr->type.getNullability() == NonNullable;
2280+
// Same with exactness.
2281+
bool needsExactCast = ref->type.getExactness() == Inexact &&
2282+
curr->type.getExactness() == Exact;
22802283
// If the best value to propagate is the argument to the cast, we can
22812284
// simply remove the cast (or downgrade it to a null check if
2282-
// necessary).
2283-
if (ref == curr->ref) {
2285+
// necessary). This does not work if we need a cast to prove
2286+
// exactness.
2287+
if (ref == curr->ref && !needsExactCast) {
22842288
if (needsNullCheck) {
22852289
replaceCurrent(builder.makeRefAs(RefAsNonNull, curr->ref));
22862290
} else {
@@ -2289,17 +2293,22 @@ struct OptimizeInstructions
22892293
return;
22902294
}
22912295
// Otherwise we can't just remove the cast and replace it with `ref`
2292-
// because the intermediate expressions might have had side effects.
2293-
// We can replace the cast with a drop followed by a direct return of
2294-
// the value, though.
2296+
// because the intermediate expressions might have had side effects or
2297+
// we need to check exactness. We can replace the cast with a drop
2298+
// followed by a direct return of the value, though.
22952299
if (ref->type.isNull()) {
2300+
// TODO: Remove this once we type ref.null as exact.
2301+
if (needsExactCast) {
2302+
return;
2303+
}
2304+
22962305
// We can materialize the resulting null value directly.
22972306
//
22982307
// The type must be nullable for us to do that, which it normally
22992308
// would be, aside from the interesting corner case of
23002309
// uninhabitable types:
23012310
//
2302-
// (ref.cast func
2311+
// (ref.cast (ref func)
23032312
// (block (result (ref nofunc))
23042313
// (unreachable)
23052314
// )

test/lit/passes/optimize-instructions-exact.wast

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,27 @@
66
;; RUN: wasm-opt %s -all --optimize-instructions -S -o - | filecheck %s
77

88
(module
9-
;; CHECK: (func $cast-to-exact-none (type $0) (param $0 anyref)
10-
;; CHECK-NEXT: (drop
11-
;; CHECK-NEXT: (ref.cast (exact nullref)
12-
;; CHECK-NEXT: (local.get $0)
13-
;; CHECK-NEXT: )
9+
;; CHECK: (func $cast-any-to-exact-none (type $0) (param $0 anyref) (result (exact nullref))
10+
;; CHECK-NEXT: (ref.cast (exact nullref)
11+
;; CHECK-NEXT: (local.get $0)
1412
;; CHECK-NEXT: )
1513
;; CHECK-NEXT: )
16-
(func $cast-to-exact-none (param anyref)
17-
(drop
18-
;; This will not be changed, but should not trigger an assertion.
19-
(ref.cast (exact nullref)
20-
(local.get 0)
21-
)
14+
(func $cast-any-to-exact-none (param anyref) (result (exact nullref))
15+
;; This will not be changed, but should not trigger an assertion.
16+
(ref.cast (exact nullref)
17+
(local.get 0)
18+
)
19+
)
20+
;; CHECK: (func $cast-null-to-exact-none (type $1) (result (exact nullref))
21+
;; CHECK-NEXT: (local $0 nullref)
22+
;; CHECK-NEXT: (ref.cast (exact nullref)
23+
;; CHECK-NEXT: (local.get $0)
24+
;; CHECK-NEXT: )
25+
;; CHECK-NEXT: )
26+
(func $cast-null-to-exact-none (result (exact nullref))
27+
(local nullref)
28+
(ref.cast (exact nullref)
29+
(local.get 0)
2230
)
2331
)
2432
)

0 commit comments

Comments
 (0)