Skip to content

Commit 0f19a05

Browse files
authored
OptimizeInstructions: Do not remove an inner cast when there are descriptor effects in the way (#9067)
1 parent 2048605 commit 0f19a05

2 files changed

Lines changed: 99 additions & 3 deletions

File tree

src/passes/OptimizeInstructions.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2550,13 +2550,41 @@ struct OptimizeInstructions
25502550
// traps are allowed, then we cannot remove the potentially-trapping
25512551
// child, though.
25522552
bool notWeaker = Type::isSubType(curr->type, child->type);
2553-
bool safe = !child->desc || getPassOptions().trapsNeverHappen;
2554-
if (notWeaker && safe) {
2553+
auto& options = getPassOptions();
2554+
auto canTrap = !options.trapsNeverHappen;
2555+
bool safe = !child->desc || !canTrap;
2556+
bool canOptimize = notWeaker && safe;
2557+
if (canOptimize && curr->desc && canTrap) {
2558+
// There is another child here, which might trap, and we need to
2559+
// consider that in this situation:
2560+
//
2561+
// (outer.cast
2562+
// (inner.cast (inner.ref))
2563+
// (descriptor with effects)
2564+
// )
2565+
//
2566+
// =>
2567+
//
2568+
// (outer.cast
2569+
// (inner.ref) ;; inner cast was removed
2570+
// (descriptor with effects)
2571+
// )
2572+
//
2573+
// It is safe to remove the inner cast, as if it trapped, the outer one
2574+
// would still trap. But if there is a descriptor, then we are moving
2575+
// the trap across the descriptor, and shouldn't cross effects there.
2576+
EffectAnalyzer descEffects(options, *getModule(), curr->desc);
2577+
ShallowEffectAnalyzer movingEffects(options, *getModule(), curr->ref);
2578+
if (movingEffects.orderedBefore(descEffects)) {
2579+
canOptimize = false;
2580+
}
2581+
}
2582+
if (canOptimize) {
25552583
if (child->desc) {
25562584
// Reorder the child's reference past its dropped descriptor if
25572585
// necessary.
25582586
auto* block =
2559-
ChildLocalizer(child, getFunction(), *getModule(), getPassOptions())
2587+
ChildLocalizer(child, getFunction(), *getModule(), options)
25602588
.getChildrenReplacement();
25612589
block->list.push_back(child->ref);
25622590
block->type = child->ref->type;

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

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,4 +1459,72 @@
14591459
)
14601460
)
14611461
)
1462+
1463+
;; CHECK: (func $ref.cast_desc_eq-ref.cast (type $22) (param $x anyref)
1464+
;; CHECK-NEXT: (drop
1465+
;; CHECK-NEXT: (ref.cast_desc_eq (ref $struct)
1466+
;; CHECK-NEXT: (ref.cast (ref $struct)
1467+
;; CHECK-NEXT: (local.get $x)
1468+
;; CHECK-NEXT: )
1469+
;; CHECK-NEXT: (block (result (ref null $desc))
1470+
;; CHECK-NEXT: (return)
1471+
;; CHECK-NEXT: )
1472+
;; CHECK-NEXT: )
1473+
;; CHECK-NEXT: )
1474+
;; CHECK-NEXT: (drop
1475+
;; CHECK-NEXT: (ref.cast_desc_eq (ref (exact $struct))
1476+
;; CHECK-NEXT: (local.get $x)
1477+
;; CHECK-NEXT: (struct.new_default $desc)
1478+
;; CHECK-NEXT: )
1479+
;; CHECK-NEXT: )
1480+
;; CHECK-NEXT: )
1481+
;; NTRAP: (func $ref.cast_desc_eq-ref.cast (type $22) (param $x anyref)
1482+
;; NTRAP-NEXT: (local $1 (ref $struct))
1483+
;; NTRAP-NEXT: (local $2 (ref null $desc))
1484+
;; NTRAP-NEXT: (drop
1485+
;; NTRAP-NEXT: (block (result (ref $struct))
1486+
;; NTRAP-NEXT: (local.set $1
1487+
;; NTRAP-NEXT: (ref.cast (ref $struct)
1488+
;; NTRAP-NEXT: (local.get $x)
1489+
;; NTRAP-NEXT: )
1490+
;; NTRAP-NEXT: )
1491+
;; NTRAP-NEXT: (local.set $2
1492+
;; NTRAP-NEXT: (block (result (ref null $desc))
1493+
;; NTRAP-NEXT: (return)
1494+
;; NTRAP-NEXT: )
1495+
;; NTRAP-NEXT: )
1496+
;; NTRAP-NEXT: (local.get $1)
1497+
;; NTRAP-NEXT: )
1498+
;; NTRAP-NEXT: )
1499+
;; NTRAP-NEXT: (drop
1500+
;; NTRAP-NEXT: (ref.cast_desc_eq (ref (exact $struct))
1501+
;; NTRAP-NEXT: (local.get $x)
1502+
;; NTRAP-NEXT: (struct.new_default $desc)
1503+
;; NTRAP-NEXT: )
1504+
;; NTRAP-NEXT: )
1505+
;; NTRAP-NEXT: )
1506+
(func $ref.cast_desc_eq-ref.cast (param $x anyref)
1507+
;; As above with ref.as_non_null, removing the inner ref.cast would allow
1508+
;; reaching the return before the cast check, so we do not optimize. (In
1509+
;; NTRAP mode we end up removing the outer cast, separately.)
1510+
(drop
1511+
(ref.cast_desc_eq (ref $struct)
1512+
(ref.cast (ref $struct)
1513+
(local.get $x)
1514+
)
1515+
(block (result (ref null $desc))
1516+
(return)
1517+
)
1518+
)
1519+
)
1520+
;; Without dangerous effects we can remove the inner cast.
1521+
(drop
1522+
(ref.cast_desc_eq (ref $struct)
1523+
(ref.cast (ref $struct)
1524+
(local.get $x)
1525+
)
1526+
(struct.new $desc) ;; this has no effects
1527+
)
1528+
)
1529+
)
14621530
)

0 commit comments

Comments
 (0)