Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions lib/SILOptimizer/LoopTransforms/LICM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -963,6 +963,41 @@ static bool storesCommonlyDominateLoopExits(SILValue addr, SILLoop *loop,
if (stores.count(header) != 0)
return true;

// Also a store in the pre-header dominates all exists. Although the situation
// is a bit different here: the store in the pre-header remains - it's not
// (re)moved by the LICM transformation.
// But even if the loop-stores are not dominating the loop exits, it
// makes sense to move them out of the loop if this case. When this is done,
// dead-store-elimination can then most likely eliminate the store in the
// pre-header.
//
// pre_header:
// store %v1 to %addr
// header:
// cond_br %cond, then, tail
// then:
// store %v2 to %addr // a conditional store in the loop
// br tail
// tail:
// cond_br %loop_cond, header, exit
// exit:
//
// will be transformed to
//
// pre_header:
// store %v1 to %addr // <- can be removed by DSE afterwards
// header:
// cond_br %cond, then, tail
// then:
// br tail
// tail(%phi):
// cond_br %loop_cond, header, exit
// exit:
// store %phi to %addr
//
if (stores.count(loop->getLoopPreheader()) != 0)
return true;

// Propagate the store-is-not-alive flag through the control flow in the loop,
// starting at the header.
SmallPtrSet<SILBasicBlock *, 16> storesNotAlive;
Expand Down
41 changes: 41 additions & 0 deletions test/SILOptimizer/licm.sil
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,47 @@ bb6:
return %12 : $()
}

// CHECK-LABEL: sil @hoist_when_store_is_in_preheader
// CHECK: bb0(%0 : $*Int32, %1 : $Int32):
// CHECK: store
// CHECK: load
// CHECK: bb1(%{{[0-9]+}} : $Int32):
// CHECK-NOT: load
// CHECK-NOT: store
// CHECK: bb4([[P:%[0-9]+]] : $Int32):
// CHECK: bb6:
// CHECK: store [[P]] to %0
// CHECK: } // end sil function 'hoist_when_store_is_in_preheader'
sil @hoist_when_store_is_in_preheader : $@convention(thin) (@inout Int32, Int32) -> () {
bb0(%0 : $*Int32, %1 : $Int32):
%8 = struct_element_addr %0 : $*Int32, #Int32._value
%9 = struct_extract %1 : $Int32, #Int32._value
%10 = integer_literal $Builtin.Int1, 0
store %1 to %0 : $*Int32
br bb1

bb1:
%17 = load %8 : $*Builtin.Int32
%18 = builtin "sadd_with_overflow_Int64"(%17 : $Builtin.Int32, %9 : $Builtin.Int32, %10 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%19 = tuple_extract %18 : $(Builtin.Int32, Builtin.Int1), 0
%20 = struct $Int32 (%19 : $Builtin.Int32)
cond_br undef, bb2, bb3
bb2:
br bb4
bb3:
store %20 to %0 : $*Int32
br bb4
bb4:
cond_br undef, bb5, bb6

bb5:
br bb1

bb6:
%12 = tuple ()
return %12 : $()
}

// CHECK-LABEL: sil @hoist_loads_and_stores_multiple_exits
// CHECK: [[V1:%[0-9]+]] = load %0
// CHECK: br bb1([[V1]] : $Int32)
Expand Down