Skip to content

Commit 57ab4d7

Browse files
committedMar 11, 2025
Fix optimization of casts to exact null types
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 2bddedc commit 57ab4d7

File tree

2 files changed

+34
-17
lines changed

2 files changed

+34
-17
lines changed
 

‎src/passes/OptimizeInstructions.cpp

+15-6
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

+19-11
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)