blob: f261e4a12b4adc4ae12b22589afed2ea298c88e3 [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
}
sil @guaranteed_object_user : $@convention(thin) (@guaranteed 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: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[ARG_COPY]]
// 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: [[RESULT:%.*]] = struct $NativeObjectPair ([[ARG1_COPY:%.*]] : $Builtin.NativeObject, [[ARG2_COPY:%.*]] : $Builtin.NativeObject)
// CHECK: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[RESULT]]
// 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: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[RESULT]]
// 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: [[RESULT:%.*]] = struct $NativeObjectPair ([[ARG1_COPY:%.*]] : $Builtin.NativeObject, [[ARG2_COPY:%.*]] : $Builtin.NativeObject)
// CHECK: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[RESULT]]
// 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: [[SECOND_ADDR:%.*]] = struct_element_addr [[STACK]]
// CHECK: [[SECOND_VAL_COPY:%.*]] = load [copy] [[SECOND_ADDR]]
// CHECK: [[RESULT:%.*]] = struct $NativeObjectPair ([[ARG1_COPY:%.*]] : $Builtin.NativeObject, [[SECOND_VAL_COPY]] : $Builtin.NativeObject)
// CHECK: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[RESULT]]
// 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: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[COPIED_ARG_FIELD]]
// 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: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[COPIED_ARG_FIELD]]
// 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: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: return [[ARG1_COPY]]
// 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: br bb3([[LHS2_COPY]] :
//
// CHECK: bb2:
// CHECK: destroy_value [[LHS2_COPY]]
// CHECK: br bb3([[LHS1_COPY]] :
//
// 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:%.*]] :
// CHECK: [[STACK:%.*]] = alloc_stack $Builtin.NativeObject
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK: store [[ARG]] to [init] [[STACK]]
// CHECK: [[BORROWED_ARG_COPY:%.*]] = begin_borrow [[ARG_COPY]]
// CHECK: [[RESULT:%.*]] = copy_value [[BORROWED_ARG_COPY]]
// CHECK: end_borrow [[BORROWED_ARG_COPY]]
// CHECK: destroy_value [[ARG_COPY]]
// 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
%2 = load_borrow %1 : $*Builtin.NativeObject
%3 = copy_value %2 : $Builtin.NativeObject
end_borrow %2 : $Builtin.NativeObject
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 @guaranteed_object_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 @guaranteed_object_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: [[BORROWED_TUP_0_COPY:%.*]] = begin_borrow [[TUP_0_COPY]]
// CHECK: [[BORROWED_TUP_1_COPY:%.*]] = begin_borrow [[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 [[TUP_0_COPY]]
// CHECK: end_borrow [[BORROWED_TUP_1_COPY]]
// CHECK: destroy_value [[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 @guaranteed_object_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 : $()
}