Skip to content

Commit 3fd5c4f

Browse files
authored
OptimizeCasts: Also handle local.tee (#6507)
Converts the following: (some.operation (ref.cast .. (local.tee $ref ..)) (local.get $ref) ) into: (some.operation (local.tee $temp (ref.cast .. (local.tee $ref ..)) ) (local.get $temp) )
1 parent 1eedf1e commit 3fd5c4f

File tree

2 files changed

+63
-27
lines changed

2 files changed

+63
-27
lines changed

src/passes/OptimizeCasts.cpp

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -93,21 +93,10 @@
9393
// RefAs with ExternInternalize and ExternExternalize are not considered casts
9494
// when obtaining fallthroughs, and so are ignored.
9595
//
96-
// TODO: 1. Look past individual basic blocks? This may be worth considering
97-
// given the pattern of a cast appearing in an if condition that is
98-
// then used in an if arm, for example, where simple dominance shows
99-
// the cast can be reused.
100-
// TODO: 2. Look at LocalSet as well and not just Get. That would add some
101-
// overlap with the other passes mentioned above (SimplifyLocals and
102-
// RedundantSetElimination also track sets and can switch a get to use
103-
// a better set's index when that refines the type). But once we do the
104-
// first two TODOs above then we'd be adding some novel things here,
105-
// as we could optimize "backwards" as well (TODO 1) and past basic
106-
// blocks (TODO 2, though RedundantSetElimination does that as well).
107-
// However, we should consider whether improving those other passes
108-
// might make more sense (as it would help more than casts, if we could
109-
// make them operate "backwards" and/or past basic blocks).
110-
//
96+
// TODO: Look past individual basic blocks? This may be worth considering
97+
// given the pattern of a cast appearing in an if condition that is
98+
// then used in an if arm, for example, where simple dominance shows
99+
// the cast can be reused.
111100

112101
#include "ir/effects.h"
113102
#include "ir/linear-execution.h"
@@ -453,20 +442,30 @@ struct BestCastFinder : public LinearExecutionWalker<BestCastFinder> {
453442
void visitRefCast(RefCast* curr) { handleRefinement(curr); }
454443

455444
void handleRefinement(Expression* curr) {
456-
auto* fallthrough = Properties::getFallthrough(curr, options, *getModule());
445+
auto* teeFallthrough = Properties::getFallthrough(
446+
curr, options, *getModule(), Properties::FallthroughBehavior::NoTeeBrIf);
447+
if (auto* tee = teeFallthrough->dynCast<LocalSet>()) {
448+
updateBestCast(curr, tee->index);
449+
}
450+
auto* fallthrough =
451+
Properties::getFallthrough(teeFallthrough, options, *getModule());
457452
if (auto* get = fallthrough->dynCast<LocalGet>()) {
458-
auto*& bestCast = mostCastedGets[get->index];
459-
if (!bestCast) {
460-
// This is the first.
461-
bestCast = curr;
462-
return;
463-
}
453+
updateBestCast(curr, get->index);
454+
}
455+
}
464456

465-
// See if we are better than the current best.
466-
if (curr->type != bestCast->type &&
467-
Type::isSubType(curr->type, bestCast->type)) {
468-
bestCast = curr;
469-
}
457+
void updateBestCast(Expression* curr, Index index) {
458+
auto*& bestCast = mostCastedGets[index];
459+
if (!bestCast) {
460+
// This is the first.
461+
bestCast = curr;
462+
return;
463+
}
464+
465+
// See if we are better than the current best.
466+
if (curr->type != bestCast->type &&
467+
Type::isSubType(curr->type, bestCast->type)) {
468+
bestCast = curr;
470469
}
471470
}
472471
};

test/lit/passes/optimize-casts.wast

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,6 +1352,43 @@
13521352
)
13531353
)
13541354

1355+
;; CHECK: (func $local-tee (type $2) (param $x (ref struct))
1356+
;; CHECK-NEXT: (local $y (ref struct))
1357+
;; CHECK-NEXT: (local $2 (ref $A))
1358+
;; CHECK-NEXT: (drop
1359+
;; CHECK-NEXT: (local.tee $2
1360+
;; CHECK-NEXT: (ref.cast (ref $A)
1361+
;; CHECK-NEXT: (local.tee $y
1362+
;; CHECK-NEXT: (local.get $x)
1363+
;; CHECK-NEXT: )
1364+
;; CHECK-NEXT: )
1365+
;; CHECK-NEXT: )
1366+
;; CHECK-NEXT: )
1367+
;; CHECK-NEXT: (drop
1368+
;; CHECK-NEXT: (local.get $2)
1369+
;; CHECK-NEXT: )
1370+
;; CHECK-NEXT: (drop
1371+
;; CHECK-NEXT: (local.get $2)
1372+
;; CHECK-NEXT: )
1373+
;; CHECK-NEXT: )
1374+
(func $local-tee (param $x (ref struct))
1375+
(local $y (ref struct))
1376+
;; We should use the cast value after it has been computed, in both gets.
1377+
(drop
1378+
(ref.cast (ref $A)
1379+
(local.tee $y
1380+
(local.get $x)
1381+
)
1382+
)
1383+
)
1384+
(drop
1385+
(local.get $x)
1386+
)
1387+
(drop
1388+
(local.get $y)
1389+
)
1390+
)
1391+
13551392
;; CHECK: (func $get (type $11) (result (ref struct))
13561393
;; CHECK-NEXT: (unreachable)
13571394
;; CHECK-NEXT: )

0 commit comments

Comments
 (0)