blob: 8fa9df6db1b1e7dbf79668d3a61e63727ecac1db [file] [log] [blame]
// RUN: %target-sil-opt -enable-sil-verify-all -predictable-memaccess-opts %s | %FileCheck %s
sil_stage raw
import Builtin
import Swift
//////////////////
// Declarations //
//////////////////
class Klass {}
struct NativeObjectPair {
var x: Builtin.NativeObject
var y: Builtin.NativeObject
}
struct IntPair {
var x: Builtin.Int32
var y: Builtin.Int32
}
sil @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
sil @intpair_user : $@convention(thin) (IntPair) -> ()
sil @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
sil @inout_int32_user : $@convention(thin) (@inout Builtin.Int32) -> ()
sil @get_object : $@convention(thin) () -> @owned Builtin.NativeObject
sil @nativeobject_tuple_user : $@convention(thin) (@guaranteed (Builtin.NativeObject, Builtin.NativeObject)) -> ()
/// Needed to avoid tuple scalarization code in the use gatherer.
struct NativeObjectAndTuple {
var first: Builtin.NativeObject
var second: (Builtin.NativeObject, Builtin.NativeObject)
}
///////////
// Tests //
///////////
//===---
// Fully Available Leaf Node Values
//
// CHECK-LABEL: sil [ossa] @simple_trivial_load_promotion : $@convention(thin) (Builtin.Int32) -> Builtin.Int32 {
// CHECK: bb0([[ARG:%.*]] :
// CHECK: return [[ARG]]
// CHECK: } // end sil function 'simple_trivial_load_promotion'
sil [ossa] @simple_trivial_load_promotion : $@convention(thin) (Builtin.Int32) -> Builtin.Int32 {
bb0(%0 : $Builtin.Int32):
%1 = alloc_stack $Builtin.Int32
store %0 to [trivial] %1 : $*Builtin.Int32
%2 = load [trivial] %1 : $*Builtin.Int32
dealloc_stack %1 : $*Builtin.Int32
return %2 : $Builtin.Int32
}
// CHECK-LABEL: sil [ossa] @simple_nontrivial_load_promotion : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
// CHECK: bb0([[ARG:%.*]] :
// CHECK: [[STACK:%.*]] = alloc_stack $Builtin.NativeObject
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK: store [[ARG]] to [init] [[STACK]]
// CHECK: [[ARG_COPY_2:%.*]] = copy_value [[ARG_COPY]]
// CHECK: destroy_value [[ARG_COPY]]
// CHECK: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[ARG_COPY_2]]
// CHECK: } // end sil function 'simple_nontrivial_load_promotion'
sil [ossa] @simple_nontrivial_load_promotion : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = alloc_stack $Builtin.NativeObject
store %0 to [init] %1 : $*Builtin.NativeObject
%2 = load [copy] %1 : $*Builtin.NativeObject
destroy_addr %1 : $*Builtin.NativeObject
dealloc_stack %1 : $*Builtin.NativeObject
return %2 : $Builtin.NativeObject
}
// CHECK-LABEL: sil [ossa] @struct_nontrivial_load_promotion : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned NativeObjectPair {
// CHECK: bb0([[ARG1:%.*]] : @owned $Builtin.NativeObject, [[ARG2:%.*]] : @owned $Builtin.NativeObject):
// CHECK: [[STACK:%.*]] = alloc_stack $NativeObjectPair
// CHECK: [[FIRST_ADDR:%.*]] = struct_element_addr [[STACK]]
// CHECK: [[SECOND_ADDR:%.*]] = struct_element_addr [[STACK]]
// CHECK: [[ARG1_COPY:%.*]] = copy_value [[ARG1]]
// CHECK: store [[ARG1]] to [init] [[FIRST_ADDR]]
// CHECK: [[ARG2_COPY:%.*]] = copy_value [[ARG2]]
// CHECK: store [[ARG2]] to [init] [[SECOND_ADDR]]
// CHECK: [[ARG1_COPY_BORROW:%.*]] = begin_borrow [[ARG1_COPY]]
// CHECK: [[ARG2_COPY_BORROW:%.*]] = begin_borrow [[ARG2_COPY]]
// CHECK: [[RESULT:%.*]] = struct $NativeObjectPair ([[ARG1_COPY_BORROW:%.*]] : $Builtin.NativeObject, [[ARG2_COPY_BORROW:%.*]] : $Builtin.NativeObject)
// CHECK: [[RESULT_COPY_1:%.*]] = copy_value [[RESULT]]
// CHECK: [[RESULT_COPY_2:%.*]] = copy_value [[RESULT_COPY_1]]
// CHECK: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[RESULT_COPY_2]]
// CHECK: } // end sil function 'struct_nontrivial_load_promotion'
sil [ossa] @struct_nontrivial_load_promotion : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned NativeObjectPair {
bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject):
%2 = alloc_stack $NativeObjectPair
%3 = struct_element_addr %2 : $*NativeObjectPair, #NativeObjectPair.x
%4 = struct_element_addr %2 : $*NativeObjectPair, #NativeObjectPair.y
store %0 to [init] %3 : $*Builtin.NativeObject
store %1 to [init] %4 : $*Builtin.NativeObject
%5 = load [copy] %2 : $*NativeObjectPair
destroy_addr %2 : $*NativeObjectPair
dealloc_stack %2 : $*NativeObjectPair
return %5 : $NativeObjectPair
}
// CHECK-LABEL: sil [ossa] @tuple_nontrivial_load_promotion : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned (Builtin.NativeObject, Builtin.NativeObject) {
// CHECK: bb0([[ARG1:%.*]] : @owned $Builtin.NativeObject, [[ARG2:%.*]] : @owned $Builtin.NativeObject):
// CHECK: [[STACK:%.*]] = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject)
// CHECK: [[FIRST_ADDR:%.*]] = tuple_element_addr [[STACK]]
// CHECK: [[SECOND_ADDR:%.*]] = tuple_element_addr [[STACK]]
// CHECK: [[ARG1_COPY:%.*]] = copy_value [[ARG1]]
// CHECK: store [[ARG1]] to [init] [[FIRST_ADDR]]
// CHECK: [[ARG2_COPY:%.*]] = copy_value [[ARG2]]
// CHECK: store [[ARG2]] to [init] [[SECOND_ADDR]]
// CHECK: [[RESULT:%.*]] = tuple ([[ARG1_COPY:%.*]] : $Builtin.NativeObject, [[ARG2_COPY:%.*]] : $Builtin.NativeObject)
// CHECK: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[RESULT]]
// CHECK: } // end sil function 'tuple_nontrivial_load_promotion'
sil [ossa] @tuple_nontrivial_load_promotion : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned (Builtin.NativeObject, Builtin.NativeObject) {
bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject):
%2 = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject)
%3 = tuple_element_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject), 0
%4 = tuple_element_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject), 1
store %0 to [init] %3 : $*Builtin.NativeObject
store %1 to [init] %4 : $*Builtin.NativeObject
%5 = load [copy] %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
destroy_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
dealloc_stack %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
return %5 : $(Builtin.NativeObject, Builtin.NativeObject)
}
// CHECK-LABEL: sil [ossa] @simple_nontrivial_load_promotion_multi_insertpt : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
// CHECK: bb0([[ARG:%.*]] :
// CHECK: [[STACK:%.*]] = alloc_stack $Builtin.NativeObject
// CHECK: cond_br undef, bb1, bb2
//
// CHECK: bb1:
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK: store [[ARG]] to [init] [[STACK]]
// CHECK: br bb3([[ARG_COPY]] :
//
// CHECK: bb2:
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK: store [[ARG]] to [init] [[STACK]]
// CHECK: br bb3([[ARG_COPY]] :
//
// CHECK: bb3([[RESULT:%.*]] : @owned $Builtin.NativeObject):
// CHECK: [[RESULT_COPY_1:%.*]] = copy_value [[RESULT]]
// CHECK: [[RESULT_COPY_2:%.*]] = copy_value [[RESULT_COPY_1]]
// CHECK: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[RESULT_COPY_2]]
// CHECK: } // end sil function 'simple_nontrivial_load_promotion_multi_insertpt'
sil [ossa] @simple_nontrivial_load_promotion_multi_insertpt : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = alloc_stack $Builtin.NativeObject
cond_br undef, bb1, bb2
bb1:
store %0 to [init] %1 : $*Builtin.NativeObject
br bb3
bb2:
store %0 to [init] %1 : $*Builtin.NativeObject
br bb3
bb3:
%2 = load [copy] %1 : $*Builtin.NativeObject
destroy_addr %1 : $*Builtin.NativeObject
dealloc_stack %1 : $*Builtin.NativeObject
return %2 : $Builtin.NativeObject
}
// CHECK-LABEL: sil [ossa] @struct_nontrivial_load_promotion_multi_insertpt : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned NativeObjectPair {
// CHECK: bb0([[ARG1:%.*]] : @owned $Builtin.NativeObject, [[ARG2:%.*]] : @owned $Builtin.NativeObject):
// CHECK: [[STACK:%.*]] = alloc_stack $NativeObjectPair
// CHECK: cond_br undef, bb1, bb2
//
// CHECK: bb1:
// CHECK: [[FIRST_ADDR:%.*]] = struct_element_addr [[STACK]]
// CHECK: [[SECOND_ADDR:%.*]] = struct_element_addr [[STACK]]
// CHECK: [[ARG1_COPY:%.*]] = copy_value [[ARG1]]
// CHECK: store [[ARG1]] to [init] [[FIRST_ADDR]]
// CHECK: [[ARG2_COPY:%.*]] = copy_value [[ARG2]]
// CHECK: store [[ARG2]] to [init] [[SECOND_ADDR]]
// CHECK: br bb3([[ARG1_COPY]] : $Builtin.NativeObject, [[ARG2_COPY]] : $Builtin.NativeObject)
//
// CHECK: bb2:
// CHECK: [[FIRST_ADDR:%.*]] = struct_element_addr [[STACK]]
// CHECK: [[SECOND_ADDR:%.*]] = struct_element_addr [[STACK]]
// CHECK: [[ARG1_COPY:%.*]] = copy_value [[ARG1]]
// CHECK: store [[ARG1]] to [init] [[FIRST_ADDR]]
// CHECK: [[ARG2_COPY:%.*]] = copy_value [[ARG2]]
// CHECK: store [[ARG2]] to [init] [[SECOND_ADDR]]
// CHECK: br bb3([[ARG1_COPY]] : $Builtin.NativeObject, [[ARG2_COPY]] : $Builtin.NativeObject)
//
// CHECK: bb3([[ARG1_COPY:%.*]] : @owned $Builtin.NativeObject, [[ARG2_COPY:%.*]] : @owned $Builtin.NativeObject):
// CHECK: [[ARG1_COPY_COPY:%.*]] = copy_value [[ARG1_COPY]]
// CHECK: [[ARG2_COPY_COPY:%.*]] = copy_value [[ARG2_COPY]]
// CHECK: [[ARG1_COPY_COPY_BORROW:%.*]] = begin_borrow [[ARG1_COPY_COPY]]
// CHECK: [[ARG2_COPY_COPY_BORROW:%.*]] = begin_borrow [[ARG2_COPY_COPY]]
// CHECK: [[RESULT:%.*]] = struct $NativeObjectPair ([[ARG1_COPY_COPY_BORROW:%.*]] : $Builtin.NativeObject, [[ARG2_COPY_COPY_BORROW:%.*]] : $Builtin.NativeObject)
// CHECK: [[RESULT_COPY:%.*]] = copy_value [[RESULT]]
// CHECK: [[RESULT_COPY_2:%.*]] = copy_value [[RESULT_COPY]]
// CHECK: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[RESULT_COPY_2]]
// CHECK: } // end sil function 'struct_nontrivial_load_promotion_multi_insertpt'
sil [ossa] @struct_nontrivial_load_promotion_multi_insertpt : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned NativeObjectPair {
bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject):
%2 = alloc_stack $NativeObjectPair
cond_br undef, bb1, bb2
bb1:
%3a = struct_element_addr %2 : $*NativeObjectPair, #NativeObjectPair.x
%4a = struct_element_addr %2 : $*NativeObjectPair, #NativeObjectPair.y
store %0 to [init] %3a : $*Builtin.NativeObject
store %1 to [init] %4a : $*Builtin.NativeObject
br bb3
bb2:
%3b = struct_element_addr %2 : $*NativeObjectPair, #NativeObjectPair.x
%4b = struct_element_addr %2 : $*NativeObjectPair, #NativeObjectPair.y
store %0 to [init] %3b : $*Builtin.NativeObject
store %1 to [init] %4b : $*Builtin.NativeObject
br bb3
bb3:
%5 = load [copy] %2 : $*NativeObjectPair
destroy_addr %2 : $*NativeObjectPair
dealloc_stack %2 : $*NativeObjectPair
return %5 : $NativeObjectPair
}
// CHECK-LABEL: sil [ossa] @tuple_nontrivial_load_promotion_multi_insertpt : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned (Builtin.NativeObject, Builtin.NativeObject) {
// CHECK: bb0([[ARG1:%.*]] : @owned $Builtin.NativeObject, [[ARG2:%.*]] : @owned $Builtin.NativeObject):
// CHECK: [[STACK:%.*]] = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject)
// CHECK: cond_br undef, bb1, bb2
//
// CHECK: bb1:
// CHECK: [[FIRST_ADDR:%.*]] = tuple_element_addr [[STACK]]
// CHECK: [[SECOND_ADDR:%.*]] = tuple_element_addr [[STACK]]
// CHECK: [[ARG1_COPY:%.*]] = copy_value [[ARG1]]
// CHECK: store [[ARG1]] to [init] [[FIRST_ADDR]]
// CHECK: [[ARG2_COPY:%.*]] = copy_value [[ARG2]]
// CHECK: store [[ARG2]] to [init] [[SECOND_ADDR]]
// CHECK: br bb3([[ARG1_COPY]] : $Builtin.NativeObject, [[ARG2_COPY]] : $Builtin.NativeObject)
//
// CHECK: bb2:
// CHECK: [[FIRST_ADDR:%.*]] = tuple_element_addr [[STACK]]
// CHECK: [[SECOND_ADDR:%.*]] = tuple_element_addr [[STACK]]
// CHECK: [[ARG1_COPY:%.*]] = copy_value [[ARG1]]
// CHECK: store [[ARG1]] to [init] [[FIRST_ADDR]]
// CHECK: [[ARG2_COPY:%.*]] = copy_value [[ARG2]]
// CHECK: store [[ARG2]] to [init] [[SECOND_ADDR]]
// CHECK: br bb3([[ARG1_COPY]] : $Builtin.NativeObject, [[ARG2_COPY]] : $Builtin.NativeObject)
//
// CHECK: bb3([[ARG1_COPY:%.*]] : @owned $Builtin.NativeObject, [[ARG2_COPY:%.*]] : @owned $Builtin.NativeObject):
// CHECK: [[RESULT:%.*]] = tuple ([[ARG1_COPY:%.*]] : $Builtin.NativeObject, [[ARG2_COPY:%.*]] : $Builtin.NativeObject)
// CHECK: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[RESULT]]
// CHECK: } // end sil function 'tuple_nontrivial_load_promotion_multi_insertpt'
sil [ossa] @tuple_nontrivial_load_promotion_multi_insertpt : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned (Builtin.NativeObject, Builtin.NativeObject) {
bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject):
%2 = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject)
cond_br undef, bb1, bb2
bb1:
%3a = tuple_element_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject), 0
%4a = tuple_element_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject), 1
store %0 to [init] %3a : $*Builtin.NativeObject
store %1 to [init] %4a : $*Builtin.NativeObject
br bb3
bb2:
%3b = tuple_element_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject), 0
%4b = tuple_element_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject), 1
store %0 to [init] %3b : $*Builtin.NativeObject
store %1 to [init] %4b : $*Builtin.NativeObject
br bb3
bb3:
%5 = load [copy] %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
destroy_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
dealloc_stack %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
return %5 : $(Builtin.NativeObject, Builtin.NativeObject)
}
//===---
// Value Not Fully Available
//
// CHECK-LABEL: sil [ossa] @struct_nontrivial_load_promotion_multi_insertpt_value_not_fully_available : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned NativeObjectPair {
// CHECK: bb0([[ARG1:%.*]] : @owned $Builtin.NativeObject, [[ARG2:%.*]] : @owned $Builtin.NativeObject, [[ARG3:%.*]] : @owned $Builtin.NativeObject):
// CHECK: [[STACK:%.*]] = alloc_stack $NativeObjectPair
// CHECK: cond_br undef, bb1, bb2
//
// CHECK: bb1:
// CHECK: [[FIRST_ADDR:%.*]] = struct_element_addr [[STACK]]
// CHECK: [[SECOND_ADDR:%.*]] = struct_element_addr [[STACK]]
// CHECK: [[ARG1_COPY:%.*]] = copy_value [[ARG1]]
// CHECK: store [[ARG1]] to [init] [[FIRST_ADDR]]
// CHECK: store [[ARG2]] to [init] [[SECOND_ADDR]]
// CHECK: destroy_value [[ARG3]]
// CHECK: br bb3([[ARG1_COPY]] : $Builtin.NativeObject)
//
// CHECK: bb2:
// CHECK: [[FIRST_ADDR:%.*]] = struct_element_addr [[STACK]]
// CHECK: [[SECOND_ADDR:%.*]] = struct_element_addr [[STACK]]
// CHECK: [[ARG1_COPY:%.*]] = copy_value [[ARG1]]
// CHECK: store [[ARG1]] to [init] [[FIRST_ADDR]]
// CHECK: destroy_value [[ARG2]]
// CHECK: store [[ARG3]] to [init] [[SECOND_ADDR]]
// CHECK: br bb3([[ARG1_COPY]] : $Builtin.NativeObject)
//
// CHECK: bb3([[ARG1_COPY:%.*]] : @owned $Builtin.NativeObject):
// CHECK: [[ARG1_COPY_COPY:%.*]] = copy_value [[ARG1_COPY]]
// CHECK: [[SECOND_ADDR:%.*]] = struct_element_addr [[STACK]]
// CHECK: [[SECOND_VAL_COPY:%.*]] = load [copy] [[SECOND_ADDR]]
// CHECK: [[ARG1_COPY_COPY_BORROW:%.*]] = begin_borrow [[ARG1_COPY_COPY]]
// CHECK: [[SECOND_VAL_COPY_BORROW:%.*]] = begin_borrow [[SECOND_VAL_COPY]]
// CHECK: [[RESULT:%.*]] = struct $NativeObjectPair ([[ARG1_COPY_COPY_BORROW:%.*]] : $Builtin.NativeObject, [[SECOND_VAL_COPY_BORROW]] : $Builtin.NativeObject)
// CHECK: [[RESULT_COPY_1:%.*]] = copy_value [[RESULT]]
// CHECK: [[RESULT_COPY_2:%.*]] = copy_value [[RESULT_COPY_1]]
// CHECK: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[RESULT_COPY_2]]
// CHECK: } // end sil function 'struct_nontrivial_load_promotion_multi_insertpt_value_not_fully_available'
sil [ossa] @struct_nontrivial_load_promotion_multi_insertpt_value_not_fully_available : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned NativeObjectPair {
bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject, %arg2 : @owned $Builtin.NativeObject):
%2 = alloc_stack $NativeObjectPair
cond_br undef, bb1, bb2
bb1:
%3a = struct_element_addr %2 : $*NativeObjectPair, #NativeObjectPair.x
%4a = struct_element_addr %2 : $*NativeObjectPair, #NativeObjectPair.y
store %0 to [init] %3a : $*Builtin.NativeObject
store %1 to [init] %4a : $*Builtin.NativeObject
destroy_value %arg2 : $Builtin.NativeObject
br bb3
bb2:
%3b = struct_element_addr %2 : $*NativeObjectPair, #NativeObjectPair.x
%4b = struct_element_addr %2 : $*NativeObjectPair, #NativeObjectPair.y
store %0 to [init] %3b : $*Builtin.NativeObject
destroy_value %1 : $Builtin.NativeObject
store %arg2 to [init] %4b : $*Builtin.NativeObject
br bb3
bb3:
%5 = load [copy] %2 : $*NativeObjectPair
destroy_addr %2 : $*NativeObjectPair
dealloc_stack %2 : $*NativeObjectPair
return %5 : $NativeObjectPair
}
// CHECK-LABEL: sil [ossa] @tuple_nontrivial_load_promotion_multi_insertpt_value_not_fully_available : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned (Builtin.NativeObject, Builtin.NativeObject) {
// CHECK: bb0([[ARG1:%.*]] : @owned $Builtin.NativeObject, [[ARG2:%.*]] : @owned $Builtin.NativeObject, [[ARG3:%.*]] : @owned $Builtin.NativeObject):
// CHECK: [[STACK:%.*]] = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject)
// This is here b/c we scalarize loads in our use list. Really, PMO shouldn't scalarize.
// CHECK: [[SCALARIZED_TUPLE_GEP:%.*]] = tuple_element_addr [[STACK]]
// CHECK: cond_br undef, bb1, bb2
//
// CHECK: bb1:
// CHECK: [[FIRST_ADDR:%.*]] = tuple_element_addr [[STACK]]
// CHECK: [[SECOND_ADDR:%.*]] = tuple_element_addr [[STACK]]
// CHECK: [[ARG1_COPY:%.*]] = copy_value [[ARG1]]
// CHECK: store [[ARG1]] to [init] [[FIRST_ADDR]]
// CHECK: store [[ARG2]] to [init] [[SECOND_ADDR]]
// CHECK: destroy_value [[ARG3]]
// CHECK: br bb3([[ARG1_COPY]] : $Builtin.NativeObject)
//
// CHECK: bb2:
// CHECK: [[FIRST_ADDR:%.*]] = tuple_element_addr [[STACK]]
// CHECK: [[SECOND_ADDR:%.*]] = tuple_element_addr [[STACK]]
// CHECK: [[ARG1_COPY:%.*]] = copy_value [[ARG1]]
// CHECK: store [[ARG1]] to [init] [[FIRST_ADDR]]
// CHECK: destroy_value [[ARG2]]
// CHECK: store [[ARG3]] to [init] [[SECOND_ADDR]]
// CHECK: br bb3([[ARG1_COPY]] : $Builtin.NativeObject)
//
// CHECK: bb3([[ARG1_COPY:%.*]] : @owned $Builtin.NativeObject):
// CHECK: [[SECOND_VAL_COPY:%.*]] = load [copy] [[SCALARIZED_TUPLE_GEP]]
// CHECK: [[RESULT:%.*]] = tuple ([[ARG1_COPY:%.*]] : $Builtin.NativeObject, [[SECOND_VAL_COPY]] : $Builtin.NativeObject)
// CHECK: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[RESULT]]
// CHECK: } // end sil function 'tuple_nontrivial_load_promotion_multi_insertpt_value_not_fully_available'
sil [ossa] @tuple_nontrivial_load_promotion_multi_insertpt_value_not_fully_available : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned (Builtin.NativeObject, Builtin.NativeObject) {
bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject, %arg2 : @owned $Builtin.NativeObject):
%2 = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject)
cond_br undef, bb1, bb2
bb1:
%3a = tuple_element_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject), 0
%4a = tuple_element_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject), 1
store %0 to [init] %3a : $*Builtin.NativeObject
store %1 to [init] %4a : $*Builtin.NativeObject
destroy_value %arg2 : $Builtin.NativeObject
br bb3
bb2:
%3b = tuple_element_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject), 0
%4b = tuple_element_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject), 1
store %0 to [init] %3b : $*Builtin.NativeObject
destroy_value %1 : $Builtin.NativeObject
store %arg2 to [init] %4b : $*Builtin.NativeObject
br bb3
bb3:
%5 = load [copy] %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
destroy_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
dealloc_stack %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
return %5 : $(Builtin.NativeObject, Builtin.NativeObject)
}
//===---
// Tests For Partial Uses Of Available Value
//
// CHECK-LABEL: sil [ossa] @simple_partialstructuse_load_promotion : $@convention(thin) (@owned NativeObjectPair) -> @owned Builtin.NativeObject {
// CHECK: bb0([[ARG:%.*]] : @owned $NativeObjectPair):
// CHECK: [[STACK:%.*]] = alloc_stack
// CHECK: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
// CHECK: [[BORROWED_ARG_FIELD:%.*]] = struct_extract [[BORROWED_ARG]]
// CHECK: [[COPIED_ARG_FIELD:%.*]] = copy_value [[BORROWED_ARG_FIELD]]
// CHECK: end_borrow [[BORROWED_ARG]]
// CHECK: store [[ARG]] to [init] [[STACK]]
// CHECK: [[COPIED_ARG_FIELD_COPY_1:%.*]] = copy_value [[COPIED_ARG_FIELD]]
// CHECK: [[COPIED_ARG_FIELD_COPY_2:%.*]] = copy_value [[COPIED_ARG_FIELD_COPY_1]]
// CHECK: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[COPIED_ARG_FIELD_COPY_2]]
// CHECK: } // end sil function 'simple_partialstructuse_load_promotion'
sil [ossa] @simple_partialstructuse_load_promotion : $@convention(thin) (@owned NativeObjectPair) -> (@owned Builtin.NativeObject) {
bb0(%0 : @owned $NativeObjectPair):
%1 = alloc_stack $NativeObjectPair
store %0 to [init] %1 : $*NativeObjectPair
%2 = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x
%3 = load [copy] %2 : $*Builtin.NativeObject
destroy_addr %1 : $*NativeObjectPair
dealloc_stack %1 : $*NativeObjectPair
return %3 : $Builtin.NativeObject
}
// CHECK-LABEL: sil [ossa] @simple_partialtupleuse_load_promotion : $@convention(thin) (@owned NativeObjectAndTuple) -> @owned Builtin.NativeObject {
// CHECK: bb0([[ARG:%.*]] : @owned $NativeObjectAndTuple):
// CHECK: [[STACK:%.*]] = alloc_stack
// CHECK: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
// CHECK: [[BORROWED_ARG_FIELD_1:%.*]] = struct_extract [[BORROWED_ARG]]
// CHECK: [[BORROWED_ARG_FIELD_2:%.*]] = tuple_extract [[BORROWED_ARG_FIELD_1]]
// CHECK: [[COPIED_ARG_FIELD:%.*]] = copy_value [[BORROWED_ARG_FIELD_2]]
// CHECK: end_borrow [[BORROWED_ARG]]
// CHECK: store [[ARG]] to [init] [[STACK]]
// CHECK: [[COPIED_ARG_FIELD_COPY_1:%.*]] = copy_value [[COPIED_ARG_FIELD]]
// CHECK: [[COPIED_ARG_FIELD_COPY_2:%.*]] = copy_value [[COPIED_ARG_FIELD_COPY_1]]
// CHECK: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[COPIED_ARG_FIELD_COPY_2]]
// CHECK: } // end sil function 'simple_partialtupleuse_load_promotion'
sil [ossa] @simple_partialtupleuse_load_promotion : $@convention(thin) (@owned NativeObjectAndTuple) -> (@owned Builtin.NativeObject) {
bb0(%0 : @owned $NativeObjectAndTuple):
%1 = alloc_stack $NativeObjectAndTuple
store %0 to [init] %1 : $*NativeObjectAndTuple
%2 = struct_element_addr %1 : $*NativeObjectAndTuple, #NativeObjectAndTuple.second
%3 = tuple_element_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject), 0
%4 = load [copy] %3 : $*Builtin.NativeObject
destroy_addr %1 : $*NativeObjectAndTuple
dealloc_stack %1 : $*NativeObjectAndTuple
return %4 : $Builtin.NativeObject
}
// CHECK-LABEL: sil [ossa] @simple_assignstore : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
// CHECK: bb0([[ARG0:%.*]] : @owned $Builtin.NativeObject, [[ARG1:%.*]] : @owned $Builtin.NativeObject):
// CHECK: [[STACK:%.*]] = alloc_stack $Builtin.NativeObject
// CHECK: store [[ARG0]] to [init] [[STACK]]
// CHECK: [[ARG1_COPY:%.*]] = copy_value [[ARG1]]
// CHECK: store [[ARG1]] to [assign] [[STACK]]
// CHECK: [[ARG1_COPY_1:%.*]] = copy_value [[ARG1_COPY]]
// CHECK: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[ARG1_COPY_1]]
// CHECK: } // end sil function 'simple_assignstore'
sil [ossa] @simple_assignstore : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject):
%2 = alloc_stack $Builtin.NativeObject
store %0 to [init] %2 : $*Builtin.NativeObject
store %1 to [assign] %2 : $*Builtin.NativeObject
%3 = load [copy] %2 : $*Builtin.NativeObject
destroy_addr %2 : $*Builtin.NativeObject
dealloc_stack %2 : $*Builtin.NativeObject
return %3 : $Builtin.NativeObject
}
// CHECK-LABEL: sil [ossa] @diamond_test_2 : $@convention(thin) (@owned NativeObjectPair) -> @owned Builtin.NativeObject {
// CHECK: bb0([[ARG:%.*]] : @owned $NativeObjectPair):
// CHECK: [[STACK:%.*]] = alloc_stack $NativeObjectPair
// CHECK: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
// CHECK: [[LHS1:%.*]] = struct_extract [[BORROWED_ARG]] : $NativeObjectPair, #NativeObjectPair.x
// CHECK: [[LHS1_COPY:%.*]] = copy_value [[LHS1]]
// CHECK: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
// CHECK: [[LHS2:%.*]] = struct_extract [[BORROWED_ARG]] : $NativeObjectPair, #NativeObjectPair.x
// CHECK: [[LHS2_COPY:%.*]] = copy_value [[LHS2]]
// CHECK: store [[ARG]] to [init] [[STACK]]
// CHECK: cond_br undef, bb1, bb2
//
// CHECK: bb1:
// CHECK: destroy_value [[LHS1_COPY]]
// CHECK: [[LHS2_COPY_1:%.*]] = copy_value [[LHS2_COPY]]
// CHECK: [[LHS2_COPY_2:%.*]] = copy_value [[LHS2_COPY_1]]
// CHECK: br bb3([[LHS2_COPY_2]] :
//
// CHECK: bb2:
// CHECK: destroy_value [[LHS2_COPY]]
// CHECK: [[LHS1_COPY_1:%.*]] = copy_value [[LHS1_COPY]]
// CHECK: [[LHS1_COPY_2:%.*]] = copy_value [[LHS1_COPY_1]]
// CHECK: br bb3([[LHS1_COPY_2]] :
//
// CHECK: bb3([[PHI:%.*]] :
// CHECK: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[PHI]]
// CHECK: } // end sil function 'diamond_test_2'
sil [ossa] @diamond_test_2 : $@convention(thin) (@owned NativeObjectPair) -> @owned Builtin.NativeObject {
bb0(%0 : @owned $NativeObjectPair):
%1 = alloc_stack $NativeObjectPair
store %0 to [init] %1 : $*NativeObjectPair
cond_br undef, bb1, bb2
bb1:
%2 = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x
%3 = load [copy] %2 : $*Builtin.NativeObject
br bb3(%3 : $Builtin.NativeObject)
bb2:
%4 = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x
%5 = load [copy] %4 : $*Builtin.NativeObject
br bb3(%5 : $Builtin.NativeObject)
bb3(%6 : @owned $Builtin.NativeObject):
destroy_addr %1 : $*NativeObjectPair
dealloc_stack %1 : $*NativeObjectPair
return %6 : $Builtin.NativeObject
}
////////////////////
// Negative Tests //
////////////////////
// CHECK-LABEL: sil [ossa] @simple_nontrivial_loadtake_no_promote : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
// CHECK: bb0([[ARG:%.*]] :
// CHECK: [[STACK:%.*]] = alloc_stack $Builtin.NativeObject
// CHECK: store [[ARG]] to [init] [[STACK]]
// CHECK: [[RESULT:%.*]] = load [take] [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[RESULT]]
// CHECK: } // end sil function 'simple_nontrivial_loadtake_no_promote'
sil [ossa] @simple_nontrivial_loadtake_no_promote : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = alloc_stack $Builtin.NativeObject
store %0 to [init] %1 : $*Builtin.NativeObject
%2 = load [take] %1 : $*Builtin.NativeObject
dealloc_stack %1 : $*Builtin.NativeObject
return %2 : $Builtin.NativeObject
}
///////////////////////
// Load Borrow Tests //
///////////////////////
// CHECK-LABEL: sil [ossa] @load_borrow_promotion : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
// CHECK: bb0([[ARG:%.*]] :
// Block where we have our store and do our lifetime extending copy_value.
// CHECK: [[STACK:%.*]] = alloc_stack $Builtin.NativeObject
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK: store [[ARG]] to [init] [[STACK]]
// CHECK: br bb1
//
// Our load block. Here, we insert our copy_value + begin_borrow that is
// associated with the load_borrow. We can not use the original copy since even
// though in this situation we know that our copy/borrow would be strongly
// control equivalent, this is not always true. To simplify the algorithm, we
// always insert the copy here. We insert a destroy_value to end the lifetime of
// ARG_COPY since we do not have a loop here.
//
// CHECK: bb1:
// CHECK: [[CONTROL_EQUIVALENT_ARG_COPY:%.*]] = copy_value [[ARG_COPY]]
// CHECK: [[BORROWED_ARG_COPY:%.*]] = begin_borrow [[CONTROL_EQUIVALENT_ARG_COPY]]
// CHECK: destroy_value [[ARG_COPY]]
// CHECK: br bb2
//
// The block where the load_borrow is actually used. We destroy the control
// equivalent arg copy here after the end_borrow.
//
// CHECK: bb2:
// CHECK: [[RESULT:%.*]] = copy_value [[BORROWED_ARG_COPY]]
// CHECK: end_borrow [[BORROWED_ARG_COPY]]
// CHECK: destroy_value [[CONTROL_EQUIVALENT_ARG_COPY]]
// CHECK: br bb3
//
// The block after the load_borrow is ever used.
// CHECK: bb3:
// CHECK: destroy_addr [[STACK]]
// CHECK: return [[RESULT]]
// CHECK: } // end sil function 'load_borrow_promotion'
sil [ossa] @load_borrow_promotion : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = alloc_stack $Builtin.NativeObject
store %0 to [init] %1 : $*Builtin.NativeObject
br bb1
bb1:
%2 = load_borrow %1 : $*Builtin.NativeObject
br bb2
bb2:
%3 = copy_value %2 : $Builtin.NativeObject
end_borrow %2 : $Builtin.NativeObject
br bb3
bb3:
destroy_addr %1 : $*Builtin.NativeObject
dealloc_stack %1 : $*Builtin.NativeObject
return %3 : $Builtin.NativeObject
}
// CHECK-LABEL: sil [ossa] @promote_with_loop_1 : $@convention(thin) (@owned NativeObjectPair) -> () {
// CHECK-NOT: load_borrow
// CHECK: } // end sil function 'promote_with_loop_1'
sil [ossa] @promote_with_loop_1 : $@convention(thin) (@owned NativeObjectPair) -> () {
bb0(%0 : @owned $NativeObjectPair):
%1 = alloc_stack $NativeObjectPair
store %0 to [init] %1 : $*NativeObjectPair
%2 = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x
br bb2
bb2:
%3 = load_borrow %2 : $*Builtin.NativeObject
%4 = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %4(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %3 : $Builtin.NativeObject
br bb2
}
// CHECK-LABEL: sil [ossa] @load_borrow_loop_promote_with_loop_2 : $@convention(thin) (@owned NativeObjectPair) -> () {
// CHECK-NOT: load_borrow
// CHECK: } // end sil function 'load_borrow_loop_promote_with_loop_2'
sil [ossa] @load_borrow_loop_promote_with_loop_2 : $@convention(thin) (@owned NativeObjectPair) -> () {
bb0(%0 : @owned $NativeObjectPair):
%1 = alloc_stack $NativeObjectPair
store %0 to [init] %1 : $*NativeObjectPair
%2 = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x
br bb2
bb2:
%3 = load_borrow %2 : $*Builtin.NativeObject
%4 = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %4(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %3 : $Builtin.NativeObject
cond_br undef, bb3, bb4
bb3:
br bb2
bb4:
destroy_addr %1 : $*NativeObjectPair
dealloc_stack %1 : $*NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @load_borrow_promote_two_backedge_loop : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK-NOT: load_borrow
// CHECK: } // end sil function 'load_borrow_promote_two_backedge_loop'
sil [ossa] @load_borrow_promote_two_backedge_loop : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = alloc_stack $Builtin.NativeObject
store %0 to [init] %1 : $*Builtin.NativeObject
br bb1
bb1:
br bb2
bb2:
cond_br undef, bb3, bb4
bb3:
%2 = load_borrow %1 : $*Builtin.NativeObject
end_borrow %2 : $Builtin.NativeObject
cond_br undef, bb5, bb6
bb4:
%3 = load_borrow %1 : $*Builtin.NativeObject
end_borrow %3 : $Builtin.NativeObject
cond_br undef, bb7, bb8
bb5:
br bb2
bb6:
br bb9
bb7:
br bb2
bb8:
br bb9
bb9:
destroy_addr %1 : $*Builtin.NativeObject
dealloc_stack %1 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [canonical] [ossa] @load_borrow_tuple_scalarize : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () {
// CHECK: bb0([[ARG0:%.*]] : @owned ${{.*}}, [[ARG1:%.*]] :
// CHECK: [[TUP:%.*]] = tuple ([[ARG0]] : ${{.*}}, [[ARG1]] :
// CHECK: ([[TUP_0:%.*]], [[TUP_1:%.*]]) = destructure_tuple [[TUP]]
// CHECK: [[TUP_0_COPY:%.*]] = copy_value [[TUP_0]]
// CHECK: [[TUP_1_COPY:%.*]] = copy_value [[TUP_1]]
// CHECK: [[CONTROL_EQUIVALENT_TUP_0_COPY:%.*]] = copy_value [[TUP_0_COPY]]
// CHECK: [[BORROWED_TUP_0_COPY:%.*]] = begin_borrow [[CONTROL_EQUIVALENT_TUP_0_COPY]]
// CHECK: destroy_value [[TUP_0_COPY]]
// CHECK: [[CONTROL_EQUIVALENT_TUP_1_COPY:%.*]] = copy_value [[TUP_1_COPY]]
// CHECK: [[BORROWED_TUP_1_COPY:%.*]] = begin_borrow [[CONTROL_EQUIVALENT_TUP_1_COPY]]
// CHECK: destroy_value [[TUP_1_COPY]]
// CHECK: [[BORROWED_TUP:%.*]] = tuple ([[BORROWED_TUP_0_COPY]] : ${{.*}}, [[BORROWED_TUP_1_COPY]] :
// CHECK: [[TUP_EXT_1:%.*]] = tuple_extract [[BORROWED_TUP]] :
// CHECK: [[TUP_EXT_2:%.*]] = tuple_extract [[BORROWED_TUP]] :
// CHECK: apply {{%.*}}([[TUP_EXT_1]])
// CHECK: apply {{%.*}}([[TUP_EXT_2]])
// CHECK: end_borrow [[BORROWED_TUP_0_COPY]]
// CHECK: destroy_value [[CONTROL_EQUIVALENT_TUP_0_COPY]]
// CHECK: end_borrow [[BORROWED_TUP_1_COPY]]
// CHECK: destroy_value [[CONTROL_EQUIVALENT_TUP_1_COPY]]
// CHECK: } // end sil function 'load_borrow_tuple_scalarize'
sil [canonical] [ossa] @load_borrow_tuple_scalarize : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject):
%2 = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject)
%3 = tuple (%0 : $Builtin.NativeObject, %1 : $Builtin.NativeObject)
store %3 to [init] %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
%4 = load_borrow %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
%5 = tuple_extract %4 : $(Builtin.NativeObject, Builtin.NativeObject), 0
%6 = tuple_extract %4 : $(Builtin.NativeObject, Builtin.NativeObject), 1
%7 = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %7(%5) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %7(%6) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %4 : $(Builtin.NativeObject, Builtin.NativeObject)
destroy_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
dealloc_stack %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @trivial_multiple_available_values_diamond_followed_by_loop_trivial : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> () {
// CHECK: bb0(
// CHECK-NOT: load [trivial] %{{[0-9][0-9]*}} : $*IntPair
// CHECK-NOT: bb{{[0-9][0-9]*}}(
// CHECK: } // end sil function 'trivial_multiple_available_values_diamond_followed_by_loop_trivial'
sil [ossa] @trivial_multiple_available_values_diamond_followed_by_loop_trivial : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> () {
bb0(%0a : $Builtin.Int32, %0b : $Builtin.Int32):
%func = function_ref @intpair_user : $@convention(thin) (IntPair) -> ()
%1 = alloc_stack $IntPair
%1a = struct_element_addr %1 : $*IntPair, #IntPair.x
%1b = struct_element_addr %1 : $*IntPair, #IntPair.y
cond_br undef, bb1, bb2
bb1:
store %0a to [trivial] %1a : $*Builtin.Int32
store %0b to [trivial] %1b : $*Builtin.Int32
br bb3
bb2:
store %0a to [trivial] %1a : $*Builtin.Int32
store %0b to [trivial] %1b : $*Builtin.Int32
br bb3
bb3:
br bb4
bb4:
br bb5
bb5:
%2 = load [trivial] %1 : $*IntPair
cond_br undef, bb6, bb7
bb6:
apply %func(%2) : $@convention(thin) (IntPair) -> ()
br bb5
bb7:
apply %func(%2) : $@convention(thin) (IntPair) -> ()
dealloc_stack %1 : $*IntPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @trivial_multiple_available_values_diamond_followed_by_loop_trivial_reload : $@convention(thin) (Builtin.Int32, Builtin.Int32, Builtin.Int32) -> () {
// CHECK: bb0(
// CHECK-NOT: load [trivial] %{{[0-9][0-9]*}} : $*IntPair
// CHECK-NOT: bb{{[0-9][0-9]*}}(
// CHECK: } // end sil function 'trivial_multiple_available_values_diamond_followed_by_loop_trivial_reload'
sil [ossa] @trivial_multiple_available_values_diamond_followed_by_loop_trivial_reload : $@convention(thin) (Builtin.Int32, Builtin.Int32, Builtin.Int32) -> () {
bb0(%0a : $Builtin.Int32, %0b : $Builtin.Int32, %0c : $Builtin.Int32):
%func = function_ref @intpair_user : $@convention(thin) (IntPair) -> ()
%1 = alloc_stack $IntPair
%1a = struct_element_addr %1 : $*IntPair, #IntPair.x
%1b = struct_element_addr %1 : $*IntPair, #IntPair.y
cond_br undef, bb1, bb2
bb1:
store %0a to [trivial] %1a : $*Builtin.Int32
store %0c to [trivial] %1b : $*Builtin.Int32
br bb3
bb2:
store %0a to [trivial] %1a : $*Builtin.Int32
store %0b to [trivial] %1b : $*Builtin.Int32
br bb3
bb3:
br bb4
bb4:
br bb5
bb5:
%2 = load [trivial] %1 : $*IntPair
cond_br undef, bb6, bb7
bb6:
apply %func(%2) : $@convention(thin) (IntPair) -> ()
br bb5
bb7:
apply %func(%2) : $@convention(thin) (IntPair) -> ()
dealloc_stack %1 : $*IntPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @trivial_multiple_available_values_diamond_followed_by_loop_trivial_store_in_loop : $@convention(thin) (Builtin.Int32, Builtin.Int32, Builtin.Int32) -> () {
// CHECK-NOT: load
// CHECK: } // end sil function 'trivial_multiple_available_values_diamond_followed_by_loop_trivial_store_in_loop'
sil [ossa] @trivial_multiple_available_values_diamond_followed_by_loop_trivial_store_in_loop : $@convention(thin) (Builtin.Int32, Builtin.Int32, Builtin.Int32) -> () {
bb0(%0a : $Builtin.Int32, %0b : $Builtin.Int32, %0c : $Builtin.Int32):
%func = function_ref @intpair_user : $@convention(thin) (IntPair) -> ()
%1 = alloc_stack $IntPair
%1a = struct_element_addr %1 : $*IntPair, #IntPair.x
%1b = struct_element_addr %1 : $*IntPair, #IntPair.y
cond_br undef, bb1, bb2
bb1:
store %0a to [trivial] %1a : $*Builtin.Int32
store %0b to [trivial] %1b : $*Builtin.Int32
br bb3
bb2:
store %0a to [trivial] %1a : $*Builtin.Int32
store %0b to [trivial] %1b : $*Builtin.Int32
br bb3
bb3:
br bb4
bb4:
br bb5
bb5:
%2 = load [trivial] %1 : $*IntPair
cond_br undef, bb6, bb7
bb6:
apply %func(%2) : $@convention(thin) (IntPair) -> ()
store %0b to [trivial] %1b : $*Builtin.Int32
br bb5
bb7:
apply %func(%2) : $@convention(thin) (IntPair) -> ()
dealloc_stack %1 : $*IntPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @multiple_available_values_diamond_followed_by_loop : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () {
// CHECK: bb0(
// CHECK-NOT: load_borrow
// CHECK: } // end sil function 'multiple_available_values_diamond_followed_by_loop'
sil [ossa] @multiple_available_values_diamond_followed_by_loop : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () {
bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject):
%func = function_ref @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
%1 = alloc_stack $NativeObjectPair
%1a = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x
%1b = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.y
cond_br undef, bb1, bb2
bb1:
store %0a to [init] %1a : $*Builtin.NativeObject
store %0b to [init] %1b : $*Builtin.NativeObject
br bb3
bb2:
store %0a to [init] %1a : $*Builtin.NativeObject
store %0b to [init] %1b : $*Builtin.NativeObject
br bb3
bb3:
br bb4
bb4:
br bb5
bb5:
%2 = load_borrow %1 : $*NativeObjectPair
cond_br undef, bb6, bb7
bb6:
apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
end_borrow %2 : $NativeObjectPair
br bb5
bb7:
apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
end_borrow %2 : $NativeObjectPair
destroy_addr %1 : $*NativeObjectPair
dealloc_stack %1 : $*NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @multiple_available_values_diamond_followed_by_loop_reload : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () {
// CHECK-NOT: load_borrow
// CHECK: } // end sil function 'multiple_available_values_diamond_followed_by_loop_reload'
sil [ossa] @multiple_available_values_diamond_followed_by_loop_reload : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () {
bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject, %0c : @owned $Builtin.NativeObject):
%func = function_ref @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
%1 = alloc_stack $NativeObjectPair
%1a = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x
%1b = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.y
cond_br undef, bb1, bb2
bb1:
store %0a to [init] %1a : $*Builtin.NativeObject
store %0c to [init] %1b : $*Builtin.NativeObject
destroy_value %0b : $Builtin.NativeObject
br bb3
bb2:
store %0a to [init] %1a : $*Builtin.NativeObject
store %0b to [init] %1b : $*Builtin.NativeObject
destroy_value %0c : $Builtin.NativeObject
br bb3
bb3:
br bb4
bb4:
br bb5
bb5:
%2 = load_borrow %1 : $*NativeObjectPair
cond_br undef, bb6, bb7
bb6:
apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
end_borrow %2 : $NativeObjectPair
br bb5
bb7:
apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
end_borrow %2 : $NativeObjectPair
destroy_addr %1 : $*NativeObjectPair
dealloc_stack %1 : $*NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @multiple_available_values_diamond_followed_by_loop_store_in_loop : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
// CHECK-NOT: load_borrow
// CHECK: } // end sil function 'multiple_available_values_diamond_followed_by_loop_store_in_loop'
sil [ossa] @multiple_available_values_diamond_followed_by_loop_store_in_loop : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject, %0c : @guaranteed $Builtin.NativeObject):
%func = function_ref @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
%1 = alloc_stack $NativeObjectPair
%1a = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x
%1b = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.y
%0bhat = copy_value %0b : $Builtin.NativeObject
cond_br undef, bb1, bb2
bb1:
store %0a to [init] %1a : $*Builtin.NativeObject
store %0b to [init] %1b : $*Builtin.NativeObject
br bb3
bb2:
store %0a to [init] %1a : $*Builtin.NativeObject
store %0b to [init] %1b : $*Builtin.NativeObject
br bb3
bb3:
br bb4
bb4:
br bb5
bb5:
%2 = load_borrow %1 : $*NativeObjectPair
cond_br undef, bb6, bb7
bb6:
apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
end_borrow %2 : $NativeObjectPair
destroy_addr %1b : $*Builtin.NativeObject
%0bhat2 = copy_value %0bhat : $Builtin.NativeObject
store %0bhat2 to [init] %1b : $*Builtin.NativeObject
br bb5
bb7:
apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
end_borrow %2 : $NativeObjectPair
destroy_value %0bhat : $Builtin.NativeObject
destroy_addr %1 : $*NativeObjectPair
dealloc_stack %1 : $*NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [canonical] [ossa] @loop_carry_loadborrow : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK-NOT: load_borrow
// CHECK: } // end sil function 'loop_carry_loadborrow'
sil [canonical] [ossa] @loop_carry_loadborrow : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%func = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
%1 = alloc_stack $Builtin.NativeObject
store %0 to [init] %1 : $*Builtin.NativeObject
cond_br undef, bb1, bb7
bb1:
br bb2
bb2:
br bb3
bb3:
%2 = load_borrow %1 : $*Builtin.NativeObject
cond_br undef, bb4, bb5
bb4:
apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $Builtin.NativeObject
br bb2
bb5:
apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $Builtin.NativeObject
br bb6
bb6:
br bb8
bb7:
br bb8
bb8:
destroy_addr %1 : $*Builtin.NativeObject
dealloc_stack %1 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [canonical] [ossa] @loop_carry_loadborrow_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK-NOT: load_borrow
// CHECK: } // end sil function 'loop_carry_loadborrow_2'
sil [canonical] [ossa] @loop_carry_loadborrow_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%func = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
%1 = alloc_stack $Builtin.NativeObject
store %0 to [init] %1 : $*Builtin.NativeObject
cond_br undef, bb1, bb7
bb1:
br bb2
bb2:
br bb3
bb3:
%2 = load_borrow %1 : $*Builtin.NativeObject
cond_br undef, bb4, bb5
bb4:
apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $Builtin.NativeObject
br bb2
bb5:
apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $Builtin.NativeObject
br bb6
bb6:
br bb8
bb7:
br bb8
bb8:
destroy_addr %1 : $*Builtin.NativeObject
dealloc_stack %1 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [canonical] [ossa] @loop_carry_loadborrow_3 : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
// CHECK-NOT: load_borrow
// CHECK: } // end sil function 'loop_carry_loadborrow_3'
sil [canonical] [ossa] @loop_carry_loadborrow_3 : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject, %0c : @guaranteed $Builtin.NativeObject):
%func = function_ref @nativeobject_tuple_user : $@convention(thin) (@guaranteed (Builtin.NativeObject, Builtin.NativeObject)) -> ()
%1 = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject)
%1a = tuple_element_addr %1 : $*(Builtin.NativeObject, Builtin.NativeObject), 0
%1b = tuple_element_addr %1 : $*(Builtin.NativeObject, Builtin.NativeObject), 1
store %0a to [init] %1a : $*Builtin.NativeObject
store %0b to [init] %1b : $*Builtin.NativeObject
cond_br undef, bb1, bb7
bb1:
br bb2
bb2:
br bb3
bb3:
%0ccopy = copy_value %0c : $Builtin.NativeObject
destroy_addr %1a : $*Builtin.NativeObject
store %0ccopy to [init] %1a : $*Builtin.NativeObject
%2 = load_borrow %1 : $*(Builtin.NativeObject, Builtin.NativeObject)
cond_br undef, bb4, bb5
bb4:
apply %func(%2) : $@convention(thin) (@guaranteed (Builtin.NativeObject, Builtin.NativeObject)) -> ()
end_borrow %2 : $(Builtin.NativeObject, Builtin.NativeObject)
br bb2
bb5:
apply %func(%2) : $@convention(thin) (@guaranteed (Builtin.NativeObject, Builtin.NativeObject)) -> ()
end_borrow %2 : $(Builtin.NativeObject, Builtin.NativeObject)
br bb6
bb6:
br bb8
bb7:
br bb8
bb8:
destroy_addr %1 : $*(Builtin.NativeObject, Builtin.NativeObject)
dealloc_stack %1 : $*(Builtin.NativeObject, Builtin.NativeObject)
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [canonical] [ossa] @loop_carry_loadborrow_4 : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
// CHECK-NOT: load_borrow
// CHECK: } // end sil function 'loop_carry_loadborrow_4'
sil [canonical] [ossa] @loop_carry_loadborrow_4 : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject, %0c : @guaranteed $Builtin.NativeObject):
%func = function_ref @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
%1 = alloc_stack $NativeObjectPair
%1a = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x
%1b = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.y
store %0a to [init] %1a : $*Builtin.NativeObject
store %0b to [init] %1b : $*Builtin.NativeObject
cond_br undef, bb1, bb7
bb1:
br bb2
bb2:
br bb3
bb3:
%0ccopy = copy_value %0c : $Builtin.NativeObject
destroy_addr %1a : $*Builtin.NativeObject
store %0ccopy to [init] %1a : $*Builtin.NativeObject
%2 = load_borrow %1 : $*NativeObjectPair
cond_br undef, bb4, bb5
bb4:
apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
end_borrow %2 : $NativeObjectPair
br bb2
bb5:
apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
end_borrow %2 : $NativeObjectPair
br bb6
bb6:
br bb8
bb7:
br bb8
bb8:
destroy_addr %1 : $*NativeObjectPair
dealloc_stack %1 : $*NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @loop_carry_load_borrow_phi_not_control_equivalent : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK-NOT: load_borrow
// CHECK: } // end sil function 'loop_carry_load_borrow_phi_not_control_equivalent'
sil [ossa] @loop_carry_load_borrow_phi_not_control_equivalent : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%arg : @owned $Builtin.NativeObject):
%func = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
%0 = alloc_stack $Builtin.NativeObject
cond_br undef, bb1, bb2
bb1:
cond_br undef, bb3, bb4
bb2:
store %arg to [init] %0 : $*Builtin.NativeObject
br bb5
bb3:
store %arg to [init] %0 : $*Builtin.NativeObject
br bb6
bb4:
store %arg to [init] %0 : $*Builtin.NativeObject
br bb7
bb5:
br bb8
bb6:
br bb8
bb7:
br bbPreLoopHeader
bb8:
br bbPreLoopHeader
bbPreLoopHeader:
br bbLoop
bbLoop:
br bbLoop1
bbLoop1:
br bbLoop2
bbLoop2:
%2 = load_borrow %0 : $*Builtin.NativeObject
cond_br undef, bbLoop3, bbLoop4
bbLoop3:
apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $Builtin.NativeObject
br bbLoop2
bbLoop4:
apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $Builtin.NativeObject
br bbEnd
bbEnd:
destroy_addr %0 : $*Builtin.NativeObject
dealloc_stack %0 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// In this case, we will have that we need to separately lifetime extend our phi
// node's copy to prevent leaks along the edge skipping the loop.
// CHECK-LABEL: sil [ossa] @loop_carry_load_borrow_phi_not_control_equivalent_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK-NOT: load_borrow
// CHECK: } // end sil function 'loop_carry_load_borrow_phi_not_control_equivalent_2'
sil [ossa] @loop_carry_load_borrow_phi_not_control_equivalent_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%arg : @owned $Builtin.NativeObject):
%func = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
%0 = alloc_stack $Builtin.NativeObject
cond_br undef, bb1, bb2
bb1:
cond_br undef, bb3, bb4
bb2:
store %arg to [init] %0 : $*Builtin.NativeObject
br bb5
bb3:
store %arg to [init] %0 : $*Builtin.NativeObject
br bb6
bb4:
store %arg to [init] %0 : $*Builtin.NativeObject
br bb7
bb5:
br bb8a
bb6:
br bb8a
bb7:
br bbPreLoopHeader
bb8a:
br bb8
bb8:
cond_br undef, bbPreLoopHeader1, bbSkipLoop
bbPreLoopHeader:
br bbLoop
bbPreLoopHeader1:
br bbLoop
bbLoop:
br bbLoop1
bbLoop1:
br bbLoop2
bbLoop2:
%2 = load_borrow %0 : $*Builtin.NativeObject
br bbLoop6
bbLoop6:
cond_br undef, bbLoop3, bbLoop4
bbLoop3:
apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $Builtin.NativeObject
br bbLoop5
bbLoop5:
br bbLoop2
bbLoop4:
apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $Builtin.NativeObject
br bbEnd
bbSkipLoop:
br bbEnd
bbEnd:
destroy_addr %0 : $*Builtin.NativeObject
dealloc_stack %0 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
//---
// CHECK-LABEL: sil [ossa] @load_copy_promote_with_loop_1 : $@convention(thin) (@owned NativeObjectPair) -> () {
// CHECK-NOT: load_borrow
// CHECK: } // end sil function 'load_copy_promote_with_loop_1'
sil [ossa] @load_copy_promote_with_loop_1 : $@convention(thin) (@owned NativeObjectPair) -> () {
bb0(%0 : @owned $NativeObjectPair):
%1 = alloc_stack $NativeObjectPair
store %0 to [init] %1 : $*NativeObjectPair
%2 = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x
br bb2
bb2:
%3 = load [copy] %2 : $*Builtin.NativeObject
%4 = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %4(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %3 : $Builtin.NativeObject
br bb2
}
// CHECK-LABEL: sil [ossa] @load_copy_loop_promote_with_loop_2 : $@convention(thin) (@owned NativeObjectPair) -> () {
// CHECK-NOT: load [copy]
// CHECK: } // end sil function 'load_copy_loop_promote_with_loop_2'
sil [ossa] @load_copy_loop_promote_with_loop_2 : $@convention(thin) (@owned NativeObjectPair) -> () {
bb0(%0 : @owned $NativeObjectPair):
%1 = alloc_stack $NativeObjectPair
store %0 to [init] %1 : $*NativeObjectPair
%2 = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x
br bb2
bb2:
%3 = load [copy] %2 : $*Builtin.NativeObject
%4 = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %4(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %3 : $Builtin.NativeObject
cond_br undef, bb3, bb4
bb3:
br bb2
bb4:
destroy_addr %1 : $*NativeObjectPair
dealloc_stack %1 : $*NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @load_copy_promote_two_backedge_loop : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK-NOT: load [copy]
// CHECK: } // end sil function 'load_copy_promote_two_backedge_loop'
sil [ossa] @load_copy_promote_two_backedge_loop : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = alloc_stack $Builtin.NativeObject
store %0 to [init] %1 : $*Builtin.NativeObject
br bb1
bb1:
br bb2
bb2:
cond_br undef, bb3, bb4
bb3:
%2 = load [copy] %1 : $*Builtin.NativeObject
destroy_value %2 : $Builtin.NativeObject
cond_br undef, bb5, bb6
bb4:
%3 = load [copy] %1 : $*Builtin.NativeObject
destroy_value %3 : $Builtin.NativeObject
cond_br undef, bb7, bb8
bb5:
br bb2
bb6:
br bb9
bb7:
br bb2
bb8:
br bb9
bb9:
destroy_addr %1 : $*Builtin.NativeObject
dealloc_stack %1 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @load_copy_multiple_available_values_diamond_followed_by_loop : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () {
// CHECK: bb0(
// CHECK-NOT: load [copy]
// CHECK: } // end sil function 'load_copy_multiple_available_values_diamond_followed_by_loop'
sil [ossa] @load_copy_multiple_available_values_diamond_followed_by_loop : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () {
bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject):
%func = function_ref @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
%1 = alloc_stack $NativeObjectPair
%1a = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x
%1b = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.y
cond_br undef, bb1, bb2
bb1:
store %0a to [init] %1a : $*Builtin.NativeObject
store %0b to [init] %1b : $*Builtin.NativeObject
br bb3
bb2:
store %0a to [init] %1a : $*Builtin.NativeObject
store %0b to [init] %1b : $*Builtin.NativeObject
br bb3
bb3:
br bb4
bb4:
br bb5
bb5:
%2 = load [copy] %1 : $*NativeObjectPair
cond_br undef, bb6, bb7
bb6:
apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
destroy_value %2 : $NativeObjectPair
br bb5
bb7:
apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
destroy_value %2 : $NativeObjectPair
destroy_addr %1 : $*NativeObjectPair
dealloc_stack %1 : $*NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @load_copy_multiple_available_values_diamond_followed_by_loop_reload : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () {
// CHECK-NOT: load [copy] {{%.*}} : $*NativeObjectPair
// CHECK: } // end sil function 'load_copy_multiple_available_values_diamond_followed_by_loop_reload'
sil [ossa] @load_copy_multiple_available_values_diamond_followed_by_loop_reload : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () {
bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject, %0c : @owned $Builtin.NativeObject):
%func = function_ref @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
%1 = alloc_stack $NativeObjectPair
%1a = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x
%1b = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.y
cond_br undef, bb1, bb2
bb1:
store %0a to [init] %1a : $*Builtin.NativeObject
store %0c to [init] %1b : $*Builtin.NativeObject
destroy_value %0b : $Builtin.NativeObject
br bb3
bb2:
store %0a to [init] %1a : $*Builtin.NativeObject
store %0b to [init] %1b : $*Builtin.NativeObject
destroy_value %0c : $Builtin.NativeObject
br bb3
bb3:
br bb4
bb4:
br bb5
bb5:
%2 = load [copy] %1 : $*NativeObjectPair
cond_br undef, bb6, bb7
bb6:
apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
destroy_value %2 : $NativeObjectPair
br bb5
bb7:
apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
destroy_value %2 : $NativeObjectPair
destroy_addr %1 : $*NativeObjectPair
dealloc_stack %1 : $*NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @load_copy_multiple_available_values_diamond_followed_by_loop_store_in_loop : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
// CHECK-NOT: load [copy] {{%.*}} : $*NativeObjectPair
// CHECK: } // end sil function 'load_copy_multiple_available_values_diamond_followed_by_loop_store_in_loop'
sil [ossa] @load_copy_multiple_available_values_diamond_followed_by_loop_store_in_loop : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject, %0c : @guaranteed $Builtin.NativeObject):
%func = function_ref @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
%1 = alloc_stack $NativeObjectPair
%1a = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x
%1b = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.y
%0bhat = copy_value %0b : $Builtin.NativeObject
cond_br undef, bb1, bb2
bb1:
store %0a to [init] %1a : $*Builtin.NativeObject
store %0b to [init] %1b : $*Builtin.NativeObject
br bb3
bb2:
store %0a to [init] %1a : $*Builtin.NativeObject
store %0b to [init] %1b : $*Builtin.NativeObject
br bb3
bb3:
br bb4
bb4:
br bb5
bb5:
%2 = load [copy] %1 : $*NativeObjectPair
cond_br undef, bb6, bb7
bb6:
apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
destroy_value %2 : $NativeObjectPair
destroy_addr %1b : $*Builtin.NativeObject
%0bhat2 = copy_value %0bhat : $Builtin.NativeObject
store %0bhat2 to [init] %1b : $*Builtin.NativeObject
br bb5
bb7:
apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
destroy_value %2 : $NativeObjectPair
destroy_value %0bhat : $Builtin.NativeObject
destroy_addr %1 : $*NativeObjectPair
dealloc_stack %1 : $*NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [canonical] [ossa] @loop_carry_loadcopy : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK-NOT: load [copy]
// CHECK: } // end sil function 'loop_carry_loadcopy'
sil [canonical] [ossa] @loop_carry_loadcopy : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%func = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
%1 = alloc_stack $Builtin.NativeObject
store %0 to [init] %1 : $*Builtin.NativeObject
cond_br undef, bb1, bb7
bb1:
br bb2
bb2:
br bb3
bb3:
%2 = load [copy] %1 : $*Builtin.NativeObject
cond_br undef, bb4, bb5
bb4:
apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %2 : $Builtin.NativeObject
br bb2
bb5:
apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %2 : $Builtin.NativeObject
br bb6
bb6:
br bb8
bb7:
br bb8
bb8:
destroy_addr %1 : $*Builtin.NativeObject
dealloc_stack %1 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [canonical] [ossa] @loop_carry_loadcopy_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK-NOT: load [copy]
// CHECK: } // end sil function 'loop_carry_loadcopy_2'
sil [canonical] [ossa] @loop_carry_loadcopy_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%func = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
%1 = alloc_stack $Builtin.NativeObject
store %0 to [init] %1 : $*Builtin.NativeObject
cond_br undef, bb1, bb7
bb1:
br bb2
bb2:
br bb3
bb3:
%2 = load [copy] %1 : $*Builtin.NativeObject
cond_br undef, bb4, bb5
bb4:
apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %2 : $Builtin.NativeObject
br bb2
bb5:
apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %2 : $Builtin.NativeObject
br bb6
bb6:
br bb8
bb7:
br bb8
bb8:
destroy_addr %1 : $*Builtin.NativeObject
dealloc_stack %1 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [canonical] [ossa] @loop_carry_loadcopy_3 : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
// CHECK-NOT: load [copy]
// CHECK: } // end sil function 'loop_carry_loadcopy_3'
sil [canonical] [ossa] @loop_carry_loadcopy_3 : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject, %0c : @guaranteed $Builtin.NativeObject):
%func = function_ref @nativeobject_tuple_user : $@convention(thin) (@guaranteed (Builtin.NativeObject, Builtin.NativeObject)) -> ()
%1 = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject)
%1a = tuple_element_addr %1 : $*(Builtin.NativeObject, Builtin.NativeObject), 0
%1b = tuple_element_addr %1 : $*(Builtin.NativeObject, Builtin.NativeObject), 1
store %0a to [init] %1a : $*Builtin.NativeObject
store %0b to [init] %1b : $*Builtin.NativeObject
cond_br undef, bb1, bb7
bb1:
br bb2
bb2:
br bb3
bb3:
%0ccopy = copy_value %0c : $Builtin.NativeObject
destroy_addr %1a : $*Builtin.NativeObject
store %0ccopy to [init] %1a : $*Builtin.NativeObject
%2 = load [copy] %1 : $*(Builtin.NativeObject, Builtin.NativeObject)
cond_br undef, bb4, bb5
bb4:
apply %func(%2) : $@convention(thin) (@guaranteed (Builtin.NativeObject, Builtin.NativeObject)) -> ()
destroy_value %2 : $(Builtin.NativeObject, Builtin.NativeObject)
br bb2
bb5:
apply %func(%2) : $@convention(thin) (@guaranteed (Builtin.NativeObject, Builtin.NativeObject)) -> ()
destroy_value %2 : $(Builtin.NativeObject, Builtin.NativeObject)
br bb6
bb6:
br bb8
bb7:
br bb8
bb8:
destroy_addr %1 : $*(Builtin.NativeObject, Builtin.NativeObject)
dealloc_stack %1 : $*(Builtin.NativeObject, Builtin.NativeObject)
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [canonical] [ossa] @loop_carry_loadcopy_4 : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
// CHECK-NOT: load [copy]
// CHECK: } // end sil function 'loop_carry_loadcopy_4'
sil [canonical] [ossa] @loop_carry_loadcopy_4 : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject, %0c : @guaranteed $Builtin.NativeObject):
%func = function_ref @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
%1 = alloc_stack $NativeObjectPair
%1a = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x
%1b = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.y
store %0a to [init] %1a : $*Builtin.NativeObject
store %0b to [init] %1b : $*Builtin.NativeObject
cond_br undef, bb1, bb7
bb1:
br bb2
bb2:
br bb3
bb3:
%0ccopy = copy_value %0c : $Builtin.NativeObject
destroy_addr %1a : $*Builtin.NativeObject
store %0ccopy to [init] %1a : $*Builtin.NativeObject
%2 = load [copy] %1 : $*NativeObjectPair
cond_br undef, bb4, bb5
bb4:
apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
destroy_value %2 : $NativeObjectPair
br bb2
bb5:
apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> ()
destroy_value %2 : $NativeObjectPair
br bb6
bb6:
br bb8
bb7:
br bb8
bb8:
destroy_addr %1 : $*NativeObjectPair
dealloc_stack %1 : $*NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @load_copy_loop_carry_load_copy_phi_not_control_equivalent : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK-NOT: load [copy]
// CHECK: } // end sil function 'load_copy_loop_carry_load_copy_phi_not_control_equivalent'
sil [ossa] @load_copy_loop_carry_load_copy_phi_not_control_equivalent : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%arg : @owned $Builtin.NativeObject):
%func = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
%0 = alloc_stack $Builtin.NativeObject
cond_br undef, bb1, bb2
bb1:
cond_br undef, bb3, bb4
bb2:
store %arg to [init] %0 : $*Builtin.NativeObject
br bb5
bb3:
store %arg to [init] %0 : $*Builtin.NativeObject
br bb6
bb4:
store %arg to [init] %0 : $*Builtin.NativeObject
br bb7
bb5:
br bb8
bb6:
br bb8
bb7:
br bbPreLoopHeader
bb8:
br bbPreLoopHeader
bbPreLoopHeader:
br bbLoop
bbLoop:
br bbLoop1
bbLoop1:
br bbLoop2
bbLoop2:
%2 = load [copy] %0 : $*Builtin.NativeObject
cond_br undef, bbLoop3, bbLoop4
bbLoop3:
apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %2 : $Builtin.NativeObject
br bbLoop2
bbLoop4:
apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %2 : $Builtin.NativeObject
br bbEnd
bbEnd:
destroy_addr %0 : $*Builtin.NativeObject
dealloc_stack %0 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// In this case, we will have that we need to separately lifetime extend our phi
// node's copy to prevent leaks along the edge skipping the loop.
// CHECK-LABEL: sil [ossa] @load_copy_loop_carry_load_copy_phi_not_control_equivalent_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK-NOT: load [copy]
// CHECK: } // end sil function 'load_copy_loop_carry_load_copy_phi_not_control_equivalent_2'
sil [ossa] @load_copy_loop_carry_load_copy_phi_not_control_equivalent_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%arg : @owned $Builtin.NativeObject):
%func = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
%0 = alloc_stack $Builtin.NativeObject
cond_br undef, bb1, bb2
bb1:
cond_br undef, bb3, bb4
bb2:
store %arg to [init] %0 : $*Builtin.NativeObject
br bb5
bb3:
store %arg to [init] %0 : $*Builtin.NativeObject
br bb6
bb4:
store %arg to [init] %0 : $*Builtin.NativeObject
br bb7
bb5:
br bb8a
bb6:
br bb8a
bb7:
br bbPreLoopHeader
bb8a:
br bb8
bb8:
cond_br undef, bbPreLoopHeader1, bbSkipLoop
bbPreLoopHeader:
br bbLoop
bbPreLoopHeader1:
br bbLoop
bbLoop:
br bbLoop1
bbLoop1:
br bbLoop2
bbLoop2:
%2 = load [copy] %0 : $*Builtin.NativeObject
br bbLoop6
bbLoop6:
cond_br undef, bbLoop3, bbLoop4
bbLoop3:
apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %2 : $Builtin.NativeObject
br bbLoop5
bbLoop5:
br bbLoop2
bbLoop4:
apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %2 : $Builtin.NativeObject
br bbEnd
bbSkipLoop:
br bbEnd
bbEnd:
destroy_addr %0 : $*Builtin.NativeObject
dealloc_stack %0 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}