Skip to content

Commit 4ca3c23

Browse files
committed
Fix LICM to avoid hoisting never-executed traps
It is legal for the optimizer to consider code after a loop always reachable, but when a loop has no exits, or when the loops exits are dominated by a conditional statement, we should not consider conditional statements within the loop as dominating all possible execution paths through the loop. At least not when there is at least one path through the loop that contains a "synchronization point", such as a function that may contain a memory barrier, perform I/O, or exit the program. Sadly, we still don't model synchronization points in the optimizer, so we need to conservatively assume all loops have a synchronization point and avoid hoisting conditional traps that may never be executed. Fixes rdar://66791257 (Print statement provokes "Can't unsafeBitCast between types of different sizes" when optimizations enabled) Originated in 2014.
1 parent 147274b commit 4ca3c23

File tree

3 files changed

+92
-3
lines changed

3 files changed

+92
-3
lines changed

include/swift/SIL/LoopInfo.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,16 @@ class SILLoop : public llvm::LoopBase<SILBasicBlock, SILLoop> {
5050
/// this loop by unrolling or versioning.
5151
bool canDuplicate(SILInstruction *Inst) const;
5252

53+
void getExitingAndLatchBlocks(
54+
SmallVectorImpl<SILBasicBlock *> &ExitingAndLatchBlocks) const {
55+
this->getExitingBlocks(ExitingAndLatchBlocks);
56+
SILBasicBlock *header = getHeader();
57+
for (auto *predBB : header->getPredecessorBlocks()) {
58+
if (contains(predBB) && !this->isLoopExiting(predBB))
59+
ExitingAndLatchBlocks.push_back(predBB);
60+
}
61+
}
62+
5363
private:
5464
friend class llvm::LoopInfoBase<SILBasicBlock, SILLoop>;
5565

lib/SILOptimizer/LoopTransforms/LICM.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,16 +214,16 @@ static void getDominatingBlocks(SmallVectorImpl<SILBasicBlock *> &domBlocks,
214214
SILLoop *Loop, DominanceInfo *DT) {
215215
auto HeaderBB = Loop->getHeader();
216216
auto DTRoot = DT->getNode(HeaderBB);
217-
SmallVector<SILBasicBlock *, 8> ExitingBBs;
218-
Loop->getExitingBlocks(ExitingBBs);
217+
SmallVector<SILBasicBlock *, 8> ExitingAndLatchBBs;
218+
Loop->getExitingAndLatchBlocks(ExitingAndLatchBBs);
219219
for (llvm::df_iterator<DominanceInfoNode *> It = llvm::df_begin(DTRoot),
220220
E = llvm::df_end(DTRoot);
221221
It != E;) {
222222
auto *CurBB = It->getBlock();
223223

224224
// Don't decent into control-dependent code. Only traverse into basic blocks
225225
// that dominate all exits.
226-
if (!std::all_of(ExitingBBs.begin(), ExitingBBs.end(),
226+
if (!std::all_of(ExitingAndLatchBBs.begin(), ExitingAndLatchBBs.end(),
227227
[=](SILBasicBlock *ExitBB) {
228228
return DT->dominates(CurBB, ExitBB);
229229
})) {

test/SILOptimizer/licm.sil

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,3 +854,82 @@ bb9(%39 : $Builtin.Int64): // Preds: bb7
854854
dealloc_stack %3 : $*Index // id: %41
855855
return %40 : $Int64 // id: %42
856856
}
857+
858+
// testConditionalTrapInInfiniteSyncLoop and
859+
// testConditionalTrapDominatingSyncLoopExit
860+
//
861+
// It's legal for the optimizer to consider code after the loop as
862+
// always reachable, but when a loop has no exits, or when the loops
863+
// exits are dominated by a conditional statement we should not
864+
// consider conditional statements within the loop as dominating all
865+
// possible execution paths through the loop. At least not when there
866+
// is at least one path through the loop that contains a
867+
// "synchronization point", such as a function that may contain a
868+
// memory barrier, perform I/O, or exit the program.
869+
sil @mayExit : $@convention(thin) () -> ()
870+
871+
// CHECK-LABEL: sil @testConditionalTrapInInfiniteSyncLoop : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> () {
872+
// CHECK: bb0
873+
// CHECK-NOT: cond_fail
874+
// CHECK: br bb1
875+
// CHECK: bb1:
876+
// CHECK: cond_br %0, bb2, bb3
877+
// CHECK: bb2:
878+
// CHECK: cond_fail %1 : $Builtin.Int1, "arithmetic overflow"
879+
// CHECK-LABEL: } // end sil function 'testConditionalTrapInInfiniteSyncLoop'
880+
sil @testConditionalTrapInInfiniteSyncLoop : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> () {
881+
bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1):
882+
br bb1
883+
884+
bb1: // loop head
885+
cond_br %0, bb2, bb3
886+
887+
bb2: // maybe never executed
888+
cond_fail %1 : $Builtin.Int1, "arithmetic overflow"
889+
br bb4
890+
891+
bb3:
892+
// synchronization point: has "real" side-effects that we can't
893+
// reorder with traps
894+
%f = function_ref @mayExit : $@convention(thin) () -> ()
895+
apply %f() : $@convention(thin) () -> ()
896+
br bb4
897+
898+
bb4: // latch
899+
br bb1
900+
}
901+
902+
// CHECK-LABEL: sil @testConditionalTrapDominatingSyncLoopExit : $@convention(thin) (Builtin.Int1, Builtin.Int1, Builtin.Int1) -> () {
903+
// CHECK: bb0
904+
// CHECK-NOT: cond_fail
905+
// CHECK: br bb1
906+
// CHECK: bb1:
907+
// CHECK: cond_br %0, bb2, bb4
908+
// CHECK: bb2:
909+
// CHECK: cond_fail %1 : $Builtin.Int1, "arithmetic overflow"
910+
// CHECK-LABEL: } // end sil function 'testConditionalTrapDominatingSyncLoopExit'
911+
sil @testConditionalTrapDominatingSyncLoopExit : $@convention(thin) (Builtin.Int1, Builtin.Int1, Builtin.Int1) -> () {
912+
bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1, %2 : $Builtin.Int1):
913+
br bb1
914+
915+
bb1: // loop head
916+
cond_br %0, bb2, bb4
917+
918+
bb2: // maybe never executed
919+
cond_fail %1 : $Builtin.Int1, "arithmetic overflow"
920+
cond_br %2, bb3, bb5
921+
922+
bb3: // tail
923+
br bb1
924+
925+
bb4:
926+
// synchronization point: has "real" side-effects that we can't
927+
// reorder with traps
928+
%f = function_ref @mayExit : $@convention(thin) () -> ()
929+
apply %f() : $@convention(thin) () -> ()
930+
br bb1
931+
932+
bb5:
933+
%99 = tuple ()
934+
return %99 : $()
935+
}

0 commit comments

Comments
 (0)