Files
swift-mirror/test/SILOptimizer/predictable_memaccess_opts.sil
Michael Gottesman f854547c55 [ownership] Enable ownership verification by default.
I also removed the -verify-sil-ownership flag in favor of a disable flag
-disable-sil-ownership-verifier. I used this on only two tests that still need
work to get them to pass with ownership, but whose problems are well understood,
small corner cases. I am going to fix them in follow on commits. I detail them
below:

1. SILOptimizer/definite_init_inout_super_init.swift. This is a test case where
DI is supposed to error. The only problem is that we crash before we error since
the code emitting by SILGen to trigger this error does not pass ownership
invariants. I have spoken with JoeG about this and he suggested that I fix this
earlier in the compiler. Since we do not run the ownership verifier without
asserts enabled, this should not affect compiler users. Given that it has
triggered DI errors previously I think it is safe to disable ownership here.

2. PrintAsObjC/extensions.swift. In this case, the signature generated by type
lowering for one of the thunks here uses an unsafe +0 return value instead of
doing an autorelease return. The ownership checker rightly flags this leak. This
is going to require either an AST level change or a change to TypeLowering. I
think it is safe to turn this off since it is such a corner case that it was
found by a test that has nothing to do with it.

rdar://43398898
2019-03-25 00:11:52 -07:00

689 lines
31 KiB
Plaintext

// 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 : $()
}