Files
swift-mirror/test/SILOptimizer/dead-object-elimination.sil
Erik Eckstein 8c9a5ba1b6 Optimizer: rewrite the DeadObjectElimination pass
DeadObjectElimination  eliminates dead `alloc_stack` and `alloc_ref` allocations.

**Stack allocations**

A stack allocation is dead if its stored values never escape and all loads can be forwarded directly to the stored values:

```
  %s = alloc_stack $Foo
  store %v to [init] %s : $*Foo
  %l = load [take] %s : $*Foo
  dealloc_stack %s : $*Foo
```
->
```
  // %l is replaced with %v
```

This also handles field-level stores and loads. Destroy instructions for field values whose containing object is destroyed replace the original aggregate destroy:

```
  %s = alloc_stack $Foo
  %fa = struct_element_addr %s : $*Foo, #Foo.x
  store %x to [init] %fa : $*Int
  destroy_addr %s : $*Foo
  dealloc_stack %s : $*Foo
```
->
```
  destroy_value %x : $Int
```

**Heap allocations**

A heap allocation is dead if it never escapes and its destructor has no observable side effects. Stored field values are destroyed in place of the object destructor:

```
  %obj = alloc_ref $Foo
  %addr = ref_element_addr %obj : $Foo, #Foo.x
  store %x to [init] %addr : $*Int
  destroy_value %obj : $Foo
```
->
```
  destroy_value %x : $Int
```

The pass replaces the old DeadObjectElimination and SILMem2Reg. It combines the advantages of both passes:

* The old DeadObjectElimination can only remove an `alloc_stack` or `alloc_ref` if there are no loads from such allocations.

* SILMem2Reg can handle loads, but can only remove `alloc_stack`s and not `alloc_ref`s.

The new pass can handle loads from both, `alloc_stack` and `alloc_ref`.
This means, for example, it can do array element propagation (an array buffer is an `alloc_ref) and, if there are no other uses of the array,
completely eliminate the array.

Also, the new pass has other improvements compared to the old passes. E.g. it can deal with objects where the individual fields are initialized with separate stores.

This change also adds the pass variant MandatoryDeadObjectElimination. It replaces the old PredictableDeadAllocationElimination pass.
2026-07-13 10:04:16 +02:00

5782 lines
188 KiB
Plaintext

// RUN: %target-sil-opt -dead-object-elimination -enable-experimental-feature RawLayout %s | %FileCheck %s
// REQUIRES: swift_feature_RawLayout
import Swift
import Builtin
import SwiftShims
//////////
// Data //
//////////
class TrivialDestructor {
var int : Builtin.Int32
var ptr : Builtin.NativeObject
init()
deinit { }
}
class Kl {}
class NontrivialDestructor {
@_hasStorage var p : Kl
@_hasStorage var i : Int
init()
}
class ArrayStorage {
@_hasStorage var bodyField : Kl
init()
}
class Kl2 {
@_hasStorage var i: Int64
}
class Klass {}
struct SmallCodesizeStruct {
var cls1 : Klass
var cls2 : Klass
}
struct LargeCodesizeStruct {
var s1: SmallCodesizeStruct
var s2: SmallCodesizeStruct
var s3: SmallCodesizeStruct
var s4: SmallCodesizeStruct
var s5: SmallCodesizeStruct
}
enum FakeOptional<T> {
case some(T)
case none
}
protocol P { }
struct X : P { }
class C: P {}
class D : C {}
enum E {
case one(C)
}
struct S {
var field: C
}
struct J {
var c: C
}
struct Ix {
var j: J
}
struct S1 {
var i: Ix
}
struct S2x {
var t: (J, J)
}
struct WrapperStruct {
var cls : Klass
}
struct NonTrivialStruct {
var val:Klass
}
public enum NonTrivialEnum {
case some1(Klass)
case some2(NonTrivialStruct)
}
enum KlassOptional {
case some(Klass)
case none
}
enum Result<S, F> {
case success(S)
case failure(F)
}
struct Sy {
var v1: AnyObject
var v2: AnyObject
}
struct S3 {
var v1: AnyObject
var v2: (AnyObject, AnyObject)
var v3: AnyObject
}
struct FileDescriptor : ~Copyable {
@_hasStorage private var fd: Int { get set }
init(_ fd: Int)
deinit
}
@_rawLayout(like: Int)
struct RawLayoutStruct : ~Copyable {
deinit
}
protocol P2 {
func bar()
}
struct SP2 : P2 {
var i: Int
func bar()
}
struct Pair {
var o: AnyObject
var i: Int
}
struct Triple {
var a: AnyObject
var b: AnyObject
var c: AnyObject
}
sil [ossa] @$s4main17TrivialDestructorCfD : $@convention(method) (@owned TrivialDestructor) -> () {
bb0(%0 : @owned $TrivialDestructor):
// Alloc/Dealloc stack should not disrupt elimination of the
// alloc_ref.
%1 = alloc_stack $Builtin.Int64
dealloc_stack %1
// Storing into the struct should not disrupt elimination of the
// alloc_ref.
%b = begin_borrow %0
%2 = ref_element_addr %b, #TrivialDestructor.int
%3 = integer_literal $Builtin.Int32, 1
store %3 to [trivial] %2
end_borrow %b
// Calling a builtin without side effects should not disrupt
// elimination of the alloc_ref.
%4 = integer_literal $Builtin.Int32, 0
%6 = builtin "xor_Int32" (%4, %3) : $Builtin.Int32
fix_lifetime %0
// Calling dealloc ref on self should not disrupt elimination of the
// alloc_ref.
dealloc_ref %0
%7 = tuple()
return %7
}
// Fake destructor for NontrivialDestructor
sil [ossa] @$s4main20NontrivialDestructorCfD : $@convention(method) (@owned NontrivialDestructor) -> () {
bb0(%0 : @owned $NontrivialDestructor):
%1 = apply undef() : $@convention(thin) () -> ()
dealloc_ref %0 : $NontrivialDestructor
%7 = tuple()
return %7 : $()
}
sil [ossa] @$s4main3Kl2CfD : $@convention(method) (@owned Kl2) -> () {
bb0(%0 : @owned $Kl2):
%1 = begin_borrow %0
%2 = unchecked_ref_cast %1 to $Builtin.NativeObject
%3 = unchecked_ownership_conversion %2, @guaranteed to @owned
end_borrow %1
end_lifetime %0
%6 = unchecked_ref_cast %3 to $Kl2
dealloc_ref %6
%8 = tuple ()
return %8
}
sil @ptr_user : $@convention(thin) (Builtin.NativeObject) -> ()
sil @int_user : $@convention(thin) (Builtin.Int32) -> ()
///////////
// Tests //
///////////
// Trivial case. Remove the alloc_ref.
//
// CHECK-LABEL: sil [ossa] @trivial_destructor_trivial : $@convention(thin) () -> () {
// CHECK: bb0
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil [ossa] @trivial_destructor_trivial : $@convention(thin) () -> () {
%0 = alloc_ref $TrivialDestructor
destroy_value %0 : $TrivialDestructor
%1 = tuple()
return %1 : $()
}
// CHECK-LABEL: sil [ossa] @non_trivial_destructor : $@convention(thin) () -> () {
// CHECK: alloc_ref
// CHECK-LABEL: } // end sil function 'non_trivial_destructor'
sil [ossa] @non_trivial_destructor : $@convention(thin) () -> () {
%0 = alloc_ref $NontrivialDestructor
destroy_value %0
%r = tuple()
return %r
}
// If the destructor is not called, we don't care about it.
//
// CHECK-LABEL: sil [ossa] @devirtualized_destructor : $@convention(thin) () -> () {
// CHECK: bb0
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil [ossa] @devirtualized_destructor : $@convention(thin) () -> () {
%0 = alloc_ref $NontrivialDestructor
%1 = begin_dealloc_ref %0 : $NontrivialDestructor of %0 : $NontrivialDestructor
fix_lifetime %1 : $NontrivialDestructor
dealloc_ref %1 : $NontrivialDestructor
%4 = tuple()
return %4 : $()
}
// CHECK-LABEL: sil [ossa] @store_to_non_trivial_property1
// CHECK-NOT: alloc_ref [stack] $NontrivialDestructor
// CHECK: } // end sil function 'store_to_non_trivial_property1'
sil [ossa] @store_to_non_trivial_property1 : $@convention(thin) () -> () {
bb0:
%0 = apply undef () : $@convention(thin) () -> @owned Kl
%1 = alloc_ref [stack] $NontrivialDestructor
%2 = begin_borrow %1 : $NontrivialDestructor
%3 = ref_element_addr %2 : $NontrivialDestructor, #NontrivialDestructor.p
store %0 to [init] %3 : $*Kl
end_borrow %2 : $NontrivialDestructor
%6 = begin_dealloc_ref %1 : $NontrivialDestructor of %1 : $NontrivialDestructor
dealloc_ref %6 : $NontrivialDestructor
dealloc_stack_ref %1 : $NontrivialDestructor
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @store_to_trivial_property
// CHECK: alloc_ref
// CHECK: } // end sil function 'store_to_trivial_property'
sil [ossa] @store_to_trivial_property : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%1 = alloc_ref [stack] $NontrivialDestructor
%2 = begin_borrow %1 : $NontrivialDestructor
%3 = ref_element_addr %2 : $NontrivialDestructor, #NontrivialDestructor.i
%4 = begin_access [modify] [dynamic] %3 : $*Int
store %0 to [trivial] %4 : $*Int
end_access %4 : $*Int
end_borrow %2 : $NontrivialDestructor
%6 = begin_dealloc_ref %1 : $NontrivialDestructor of %1 : $NontrivialDestructor
dealloc_ref %6 : $NontrivialDestructor
dealloc_stack_ref %1 : $NontrivialDestructor
%r = tuple ()
return %r : $()
}
// We load/use a pointer from the alloc_ref, do nothing.
//
// CHECK-LABEL: sil [ossa] @trivial_destructor_load :
// CHECK-NOT: alloc_ref
// CHECK: = apply %{{[0-9]+}}(%0)
// CHECK: } // end sil function 'trivial_destructor_load'
sil [ossa] @trivial_destructor_load : $@convention(thin) (Builtin.Int32) -> () {
bb0(%a : $Builtin.Int32):
%0 = alloc_ref $TrivialDestructor
%1 = begin_borrow %0 : $TrivialDestructor
%2 = ref_element_addr %1 : $TrivialDestructor, #TrivialDestructor.int
store %a to [trivial] %2
%3 = load [trivial] %2 : $*Builtin.Int32
%4 = function_ref @int_user : $@convention(thin) (Builtin.Int32) -> ()
apply %4 (%3) : $@convention(thin) (Builtin.Int32) -> ()
end_borrow %1 : $TrivialDestructor
destroy_value %0 : $TrivialDestructor
%r = tuple()
return %r : $()
}
// We store into the alloc_ref, eliminate it!
//
// CHECK-LABEL: sil [ossa] @trivial_destructor_store_into : $@convention(thin) () -> () {
// CHECK-NOT: alloc_ref
// CHECK-LABEL: } // end sil function 'trivial_destructor_store_into'
sil [ossa] @trivial_destructor_store_into : $@convention(thin) () -> () {
%0 = alloc_ref $TrivialDestructor
%b = begin_borrow %0 : $TrivialDestructor
%1 = ref_element_addr %b : $TrivialDestructor, #TrivialDestructor.int
%2 = integer_literal $Builtin.Int32, 5
store %2 to [trivial] %1 : $*Builtin.Int32
end_borrow %b : $TrivialDestructor
destroy_value %0 : $TrivialDestructor
%4 = tuple()
return %4 : $()
}
// We store a pointer from the alloc_ref, don't do anything!
//
// CHECK-LABEL: sil [ossa] @trivial_destructor_store_ptr
// CHECK: alloc_ref
// CHECK-LABEL: } // end sil function 'trivial_destructor_store_ptr'
sil [ossa] @trivial_destructor_store_ptr : $@convention(thin) (@inout Builtin.RawPointer) -> () {
bb0(%0 : $*Builtin.RawPointer):
%1 = alloc_ref $TrivialDestructor
%b = begin_borrow %1 : $TrivialDestructor
%2 = ref_element_addr %b : $TrivialDestructor, #TrivialDestructor.int
%3 = address_to_pointer %2 : $*Builtin.Int32 to $Builtin.RawPointer
store %3 to [trivial] %0 : $*Builtin.RawPointer
end_borrow %b : $TrivialDestructor
destroy_value %1 : $TrivialDestructor
%4 = tuple()
return %4 : $()
}
// We are returning the alloc_ref, do nothing.
//
// CHECK-LABEL: sil [ossa] @trivial_destructor_return_value_use :
// CHECK: alloc_ref
// CHECK-LABEL: } // end sil function 'trivial_destructor_return_value_use'
sil [ossa] @trivial_destructor_return_value_use : $@convention(thin) () -> @owned TrivialDestructor {
%0 = alloc_ref $TrivialDestructor
return %0 : $TrivialDestructor
}
// CHECK-LABEL: sil [ossa] @copy_and_destroy :
// CHECK: alloc_ref
// CHECK-LABEL: } // end sil function 'copy_and_destroy'
sil [ossa] @copy_and_destroy : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = alloc_ref $TrivialDestructor
%2 = begin_borrow %1
%3 = ref_element_addr %2, #TrivialDestructor.ptr
store %0 to [init] %3
end_borrow %2
%6 = copy_value %1
destroy_value %1
destroy_value %6
%r = tuple()
return %r
}
class NonTrivialDestructor {
var ptr : Builtin.NativeObject
init()
deinit { }
}
sil [ossa] @_TFC4main17NonTrivialDestructorD : $@convention(method) (@owned NonTrivialDestructor) -> () {
bb0(%0 : @owned $NonTrivialDestructor):
%b = begin_borrow %0 : $NonTrivialDestructor
%1 = ref_element_addr %b : $NonTrivialDestructor, #NonTrivialDestructor.ptr
%2 = load [copy] %1 : $*Builtin.NativeObject
end_borrow %b : $NonTrivialDestructor
destroy_value %2 : $Builtin.NativeObject
dealloc_ref %0 : $NonTrivialDestructor
%3 = tuple()
return %3 : $()
}
class NonTrivialDestructor2 {
var ptr : NonTrivialDestructor
init()
deinit { }
}
// Test if dealloc_ref on a different value disrupts the algorithm.
sil [ossa] @_TFC4main17NonTrivialDestructor2D : $@convention(method) (@owned NonTrivialDestructor2) -> () {
bb0(%0 : @owned $NonTrivialDestructor2):
%b = begin_borrow %0 : $NonTrivialDestructor2
%1 = ref_element_addr %b : $NonTrivialDestructor2, #NonTrivialDestructor2.ptr
%2 = load [copy] %1 : $*NonTrivialDestructor
end_borrow %b : $NonTrivialDestructor2
dealloc_ref %2 : $NonTrivialDestructor
dealloc_ref %0 : $NonTrivialDestructor2
%3 = tuple()
return %3 : $()
}
class NonTrivialDestructor3 {
var ptr : Builtin.NativeObject
init()
deinit { }
}
// Make sure a non-builtin apply disrupts the algorithm.
sil [ossa] @_TFC4main17NonTrivialDestructor3D : $@convention(method) (@owned NonTrivialDestructor3) -> () {
bb0(%0 : @owned $NonTrivialDestructor3):
%b = begin_borrow %0 : $NonTrivialDestructor3
%1 = ref_element_addr %b : $NonTrivialDestructor3, #NonTrivialDestructor3.ptr
%2 = load [take] %1 : $*Builtin.NativeObject
%3 = function_ref @ptr_user : $@convention(thin) (Builtin.NativeObject) -> ()
apply %3 (%2) : $@convention(thin) (Builtin.NativeObject) -> ()
destroy_value %2 : $Builtin.NativeObject
end_borrow %b : $NonTrivialDestructor3
dealloc_ref %0 : $NonTrivialDestructor3
%4 = tuple()
return %4 : $()
}
class NonTrivialObjCDestructor {
var ptr : Builtin.NativeObject
init() { }
deinit { }
}
// Make sure we do not handle objc_methods
sil [ossa] @_TFC4main17NonTrivialObjCDestructorD : $@convention(objc_method) (@owned NonTrivialObjCDestructor) -> () {
bb0(%0 : @owned $NonTrivialObjCDestructor):
dealloc_ref %0 : $NonTrivialObjCDestructor
%1 = tuple()
return %1 : $()
}
// CHECK-LABEL: sil [ossa] @non_trivial_destructor_objc_destructor : $@convention(thin) () -> () {
// CHECK: alloc_ref
// CHECK-LABEL: } // end sil function 'non_trivial_destructor_objc_destructor'
sil [ossa] @non_trivial_destructor_objc_destructor : $@convention(thin) () -> () {
%0 = alloc_ref $NonTrivialObjCDestructor
destroy_value %0 : $NonTrivialObjCDestructor
%1 = tuple()
return %1 : $()
}
// CHECK-LABEL: sil [ossa] @non_trivial_destructor_on_stack : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK-NEXT: %0 = tuple ()
// CHECK-NEXT: return %0
sil [ossa] @non_trivial_destructor_on_stack : $@convention(thin) () -> () {
%0 = alloc_stack $NonTrivialDestructor
dealloc_stack %0 : $*NonTrivialDestructor
%1 = tuple()
return %1 : $()
}
sil [ossa] @non_trivial_destructor_on_stack_with_stores1 : $@convention(thin) (@owned NonTrivialDestructor) -> () {
bb0(%0 : @owned $NonTrivialDestructor):
%copy = copy_value %0 : $NonTrivialDestructor
%1 = alloc_stack $NonTrivialDestructor
store %0 to [init] %1 : $*NonTrivialDestructor
store %copy to [assign] %1 : $*NonTrivialDestructor
destroy_addr %1 : $*NonTrivialDestructor
dealloc_stack %1 : $*NonTrivialDestructor
%2 = tuple()
return %2 : $()
}
sil [ossa] @non_trivial_destructor_on_stack_with_stores2 : $@convention(thin) (@owned NonTrivialDestructor, @owned NonTrivialDestructor) -> () {
bb0(%0 : @owned $NonTrivialDestructor, %1 : @owned $NonTrivialDestructor):
%2 = alloc_stack $NonTrivialDestructor
store %0 to [init] %2 : $*NonTrivialDestructor
store %1 to [assign] %2 : $*NonTrivialDestructor
destroy_addr %2 : $*NonTrivialDestructor
dealloc_stack %2 : $*NonTrivialDestructor
%3 = tuple()
return %3 : $()
}
// CHECK-LABEL: sil [ossa] @trivial_destructor_on_stack : $@convention(thin) () -> () {
// CHECK-NOT: alloc_stack
// CHECK-NOT: dealloc_stack
// CHECK: return
sil [ossa] @trivial_destructor_on_stack : $@convention(thin) () -> () {
%0 = alloc_stack $Int
destroy_addr %0 : $*Int
dealloc_stack %0 : $*Int
%1 = tuple()
return %1 : $()
}
// CHECK-LABEL: sil [ossa] @remove_dead_enum_stackloc :
// CHECK: bb0:
// CHECK-NEXT: %0 = tuple ()
// CHECK-NEXT: return %0
sil [ossa] @remove_dead_enum_stackloc : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $FloatingPointRoundingRule
inject_enum_addr %0 : $*FloatingPointRoundingRule, #FloatingPointRoundingRule.toNearestOrEven!enumelt
destroy_addr %0 : $*FloatingPointRoundingRule
dealloc_stack %0 : $*FloatingPointRoundingRule
%1 = tuple ()
return %1 : $()
}
// CHECK-LABEL: sil [ossa] @remove_dead_optional_existential :
// CHECK: bb0(%0 : $X):
// CHECK-NEXT: %1 = tuple ()
// CHECK-NEXT: return %1
sil [ossa] @remove_dead_optional_existential : $@convention(thin) (X) -> () {
bb0(%0 : $X):
%3 = alloc_stack $Optional<P>
%4 = init_enum_data_addr %3 : $*Optional<P>, #Optional.some!enumelt
%5 = init_existential_addr %4 : $*P, $X
store %0 to [trivial] %5 : $*X
inject_enum_addr %3 : $*Optional<P>, #Optional.some!enumelt
destroy_addr %3 : $*Optional<P>
dealloc_stack %3 : $*Optional<P>
%10 = tuple ()
return %10 : $()
}
// If we have an instruction that mayTrap that uses the alloc_ref, we can't
// eliminate it.
//
// CHECK-LABEL: sil [ossa] @trivial_destructor_may_trap : $@convention(thin) () -> () {
// CHECK: alloc_ref
sil [ossa] @trivial_destructor_may_trap : $@convention(thin) () -> () {
%0 = alloc_ref $TrivialDestructor
%1 = unconditional_checked_cast %0 : $TrivialDestructor to AnyObject
destroy_value %1 : $AnyObject
%4 = tuple()
return %4 : $()
}
// CHECK-LABEL: sil [ossa] @remove_dead_array_with_destroy_simple
// CHECK-NOT: alloc_ref
// CHECK: } // end sil function 'remove_dead_array_with_destroy_simple'
sil [ossa] @remove_dead_array_with_destroy_simple : $@convention(thin) () -> () {
bb0:
%0 = apply undef () : $@convention(thin) () -> @owned Kl
%copy = copy_value %0 : $Kl
%3 = integer_literal $Builtin.Word, 2
%4 = alloc_ref [tail_elems $Kl * %3 : $Builtin.Word] $ArrayStorage
%5 = begin_borrow %4 : $ArrayStorage
%11 = ref_tail_addr %5 : $ArrayStorage, $Kl
%12 = integer_literal $Builtin.Word, 0
%13 = index_addr [projection] %11 : $*Kl, %12 : $Builtin.Word
store %0 to [init] %13 : $*Kl
%27 = integer_literal $Builtin.Word, 1
%28 = index_addr [projection] %11 : $*Kl, %27 : $Builtin.Word
store %copy to [init] %28 : $*Kl
end_borrow %5 : $ArrayStorage
%6 = begin_dealloc_ref %4 : $ArrayStorage of %4 : $ArrayStorage
%7 = begin_borrow %6 : $ArrayStorage
%8 = ref_tail_addr %7 : $ArrayStorage, $Kl
%65 = address_to_pointer %8 : $*Kl to $Builtin.RawPointer
%66 = metatype $@thick Kl.Type
%67 = builtin "destroyArray"<Kl>(%66 : $@thick Kl.Type, %65 : $Builtin.RawPointer, %3 : $Builtin.Word) : $()
end_borrow %7 : $ArrayStorage
dealloc_ref %6 : $ArrayStorage
%10 = tuple ()
return %10 : $()
}
// CHECK-LABEL: sil [ossa] @remove_dead_array_with_destroy_complex
// CHECK-NOT: alloc_ref
// CHECK: } // end sil function 'remove_dead_array_with_destroy_complex'
sil [ossa] @remove_dead_array_with_destroy_complex : $@convention(thin) (@guaranteed String, Int, UInt) -> () {
bb0(%0 : @guaranteed $String, %1 : $Int, %2 : $UInt):
%copy0 = copy_value %0 : $String
%copy1 = copy_value %0 : $String
%3 = integer_literal $Builtin.Word, 2
%4 = alloc_ref [stack] [tail_elems $(Int, String) * %3 : $Builtin.Word] $_ContiguousArrayStorage<(Int, String)>
%5 = upcast %4 : $_ContiguousArrayStorage<(Int, String)> to $__ContiguousArrayStorageBase
%6 = struct $_SwiftArrayBodyStorage (%1 : $Int, %2 : $UInt)
%7 = struct $_ArrayBody (%6 : $_SwiftArrayBodyStorage)
%b = begin_borrow %5 : $__ContiguousArrayStorageBase
%9 = ref_element_addr %b : $__ContiguousArrayStorageBase, #__ContiguousArrayStorageBase.countAndCapacity
store %7 to [trivial] %9 : $*_ArrayBody
%11 = ref_tail_addr %b : $__ContiguousArrayStorageBase, $(Int, String)
%12 = tuple_element_addr %11 : $*(Int, String), 0
%13 = tuple_element_addr %11 : $*(Int, String), 1
store %1 to [trivial] %12 : $*Int
store %copy0 to [init] %13 : $*String
%27 = integer_literal $Builtin.Word, 1
%28 = index_addr [projection] %11 : $*(Int, String), %27 : $Builtin.Word
%29 = tuple_element_addr %28 : $*(Int, String), 0
%30 = tuple_element_addr %28 : $*(Int, String), 1
store %1 to [trivial] %29 : $*Int
store %copy1 to [init] %30 : $*String
end_borrow %b : $__ContiguousArrayStorageBase
%31 = begin_dealloc_ref %5 : $__ContiguousArrayStorageBase of %4 : $_ContiguousArrayStorage<(Int, String)>
%b2 = begin_borrow %31 : $__ContiguousArrayStorageBase
%64 = ref_tail_addr %b2 : $__ContiguousArrayStorageBase, $(Int, String)
%65 = address_to_pointer %64 : $*(Int, String) to $Builtin.RawPointer
%66 = metatype $@thick (Int, String).Type
%67 = builtin "destroyArray"<(Int, String)>(%66 : $@thick (Int, String).Type, %65 : $Builtin.RawPointer, %3 : $Builtin.Word) : $()
end_borrow %b2 : $__ContiguousArrayStorageBase
dealloc_ref %31 : $__ContiguousArrayStorageBase
dealloc_stack_ref %4 : $_ContiguousArrayStorage<(Int, String)>
%10 = tuple ()
return %10 : $()
}
sil @createit : $@convention(thin) () -> @owned Kl
// Check that we don't crash here.
sil [ossa] @not_dominating_stores : $@convention(thin) () -> () {
bb0:
%7 = integer_literal $Builtin.Word, 1
%10 = alloc_ref [stack] [tail_elems $Kl * %7 : $Builtin.Word] $_ContiguousArrayStorage<Kl>
%b = begin_borrow %10 : $_ContiguousArrayStorage<Kl>
%11 = upcast %b : $_ContiguousArrayStorage<Kl> to $__ContiguousArrayStorageBase
%18 = ref_tail_addr %11 : $__ContiguousArrayStorageBase, $Kl
%35 = function_ref @createit : $@convention(thin) () -> @owned Kl
cond_br undef, bb1, bb2
bb1:
%36 = apply %35() : $@convention(thin) () -> @owned Kl
store %36 to [init] %18 : $*Kl
br bb3
bb2:
%46 = apply %35() : $@convention(thin) () -> @owned Kl
store %46 to [init] %18 : $*Kl
br bb3
bb3:
end_borrow %b : $_ContiguousArrayStorage<Kl>
destroy_value %10 : $_ContiguousArrayStorage<Kl>
dealloc_stack_ref %10 : $_ContiguousArrayStorage<Kl>
%1 = tuple()
return %1 : $()
}
sil [ossa] @$ss23_ContiguousArrayStorageCfD : $@convention(method) <Element> (@owned _ContiguousArrayStorage<Element>) -> () {
bb0(%0 : @owned $_ContiguousArrayStorage<Element>):
%b = begin_borrow %0 : $_ContiguousArrayStorage<Element>
%1 = ref_tail_addr %b : $_ContiguousArrayStorage<Element>, $Element
%2 = address_to_pointer %1 : $*Element to $Builtin.RawPointer
%10 = metatype $@thick Element.Type
%12 = builtin "destroyArray"<Element>(%10 : $@thick Element.Type, %2 : $Builtin.RawPointer, undef : $Builtin.Word) : $()
end_borrow %b : $_ContiguousArrayStorage<Element>
dealloc_ref %0 : $_ContiguousArrayStorage<Element>
%15 = tuple ()
return %15 : $()
}
// CHECK-LABEL: sil [ossa] @dead_alloc_with_complex_ossa_destructor
// CHECK-NOT: alloc_ref
// CHECK: } // end sil function 'dead_alloc_with_complex_ossa_destructor'
sil [ossa] @dead_alloc_with_complex_ossa_destructor : $@convention(thin) () -> Int64 {
bb0:
%0 = alloc_ref $Kl2
%1 = move_value [lexical] %0
%2 = end_init_let_ref %1
%3 = begin_borrow %2
%4 = integer_literal $Builtin.Int64, 27
%5 = struct $Int64 (%4)
%6 = ref_element_addr %3, #Kl2.i
store %5 to [trivial] %6
end_borrow %3
%9 = move_value [lexical] [var_decl] %2
debug_value %9, let, name "k"
destroy_value %9
return %5
}
struct UInt64 {
var _value: Builtin.Int64
}
// CHECK-LABEL: sil [ossa] @dont_remove_store_read_via_address_to_pointer :
// CHECK: [[S:%[0-9]+]] = alloc_stack
// CHECK: tuple_element_addr [[S]]{{.*}}, 0
// CHECK: store
// CHECK: tuple_element_addr [[S]]{{.*}}, 1
// CHECK: store
// CHECK: } // end sil function 'dont_remove_store_read_via_address_to_pointer'
sil [ossa] @dont_remove_store_read_via_address_to_pointer : $@convention(thin) (UInt64, UInt64) -> Builtin.Int64 {
bb0(%0 : $UInt64, %1 : $UInt64):
%2 = alloc_stack $(UInt64, UInt64)
%3 = tuple_element_addr %2, 0
store %0 to [trivial] %3
%5 = tuple_element_addr %2, 1
store %1 to [trivial] %5
%7 = address_to_pointer [stack_protection] %2 to $Builtin.RawPointer
%8 = pointer_to_address %7 to $*UInt64
%9 = struct_element_addr %8, #UInt64._value
%10 = load [trivial] %9
dealloc_stack %2
return %10
}
// CHECK-LABEL: sil [ossa] @store_only_allocas :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'store_only_allocas'
// simple.foo0 (c : Swift.Int64) -> ()
sil [ossa] @store_only_allocas : $@convention(thin) (Int64) -> () {
bb0(%0 : $Int64):
%1 = alloc_stack $Int64, var, name "c"
store %0 to [trivial] %1 : $*Int64
// function_ref Swift.print (val : Swift.Int64) -> ()
%3 = function_ref @_Ts5printFT3valSi_T_ : $@convention(thin) (Int64) -> ()
%4 = apply %3(%0) : $@convention(thin) (Int64) -> ()
dealloc_stack %1 : $*Int64
%6 = tuple ()
return %6 : $()
}
// Swift.print (val : Swift.Int64) -> ()
sil [ossa] @_Ts5printFT3valSi_T_ : $@convention(thin) (Int64) -> ()
// CHECK-LABEL: sil [ossa] @multiple_store_vals :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'multiple_store_vals'
// simple.foo1 (c : Swift.Int64) -> Swift.Int64
sil [ossa] @multiple_store_vals : $@convention(thin) (Int64) -> Int64 {
bb0(%0 : $Int64):
%1 = alloc_stack $Int64, var, name "c"
store %0 to [trivial] %1 : $*Int64
%3 = alloc_stack $Int64, var, name "x"
%4 = integer_literal $Builtin.Int64, 2
%5 = struct $Int64 (%4 : $Builtin.Int64)
store %5 to [trivial] %3 : $*Int64
%7 = integer_literal $Builtin.Int64, 5
%8 = integer_literal $Builtin.Int1, 0
%9 = struct $Int64 (%7 : $Builtin.Int64)
cond_fail %8 : $Builtin.Int1
store %9 to [trivial] %3 : $*Int64
store %9 to [trivial] %3 : $*Int64
dealloc_stack %3 : $*Int64
dealloc_stack %1 : $*Int64
return %9 : $Int64
}
// CHECK-LABEL: sil [ossa] @multiple_store_vals2 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'multiple_store_vals2'
// simple.foo2 (c : Swift.Int64) -> Swift.Int64
sil [ossa] @multiple_store_vals2 : $@convention(thin) (Int64) -> Int64 {
bb0(%0 : $Int64):
%1 = alloc_stack $Int64, var, name "c"
store %0 to [trivial] %1 : $*Int64
%3 = alloc_box $<τ_0_0> { var τ_0_0 } <Int64>, var, name "x"
%3a = project_box %3 : $<τ_0_0> { var τ_0_0 } <Int64>, 0
%4 = integer_literal $Builtin.Int64, 2
%5 = struct $Int64 (%4 : $Builtin.Int64)
store %5 to [trivial] %3a : $*Int64
%8 = struct_extract %0 : $Int64, #Int64._value
%9 = builtin "cmp_sgt_Int64"(%8 : $Builtin.Int64, %4 : $Builtin.Int64) : $Builtin.Int1
cond_br %9, bb1, bb2
bb1:
destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Int64>
br bb3(%5 : $Int64)
bb2:
%13 = integer_literal $Builtin.Int64, 5
%14 = struct $Int64 (%13 : $Builtin.Int64)
cond_fail %9 : $Builtin.Int1
destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Int64>
br bb3(%14 : $Int64)
bb3(%18 : $Int64):
dealloc_stack %1 : $*Int64
return %18 : $Int64
}
// CHECK-LABEL: sil [ossa] @with_loads2 :
// CHECK: bb3([[RET:%[0-9]+]] : $Int64):
// CHECK-LABEL: } // end sil function 'with_loads2'
// simple.foo2 (c : Swift.Int64) -> Swift.Int64
sil [ossa] @with_loads2 : $@convention(thin) (Int64) -> Int64 {
bb0(%0 : $Int64):
%1 = alloc_stack $Int64, var, name "c"
store %0 to [trivial] %1 : $*Int64
%3 = alloc_box $<τ_0_0> { var τ_0_0 } <Int64>, var, name "x"
%3a = project_box %3 : $<τ_0_0> { var τ_0_0 } <Int64>, 0
%4 = integer_literal $Builtin.Int64, 2
%5 = struct $Int64 (%4 : $Builtin.Int64)
store %5 to [trivial] %3a : $*Int64
%8 = struct_extract %0 : $Int64, #Int64._value
%9 = builtin "cmp_sgt_Int64"(%8 : $Builtin.Int64, %4 : $Builtin.Int64) : $Builtin.Int1
cond_br %9, bb1, bb2
bb1:
destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Int64>
br bb3(%5 : $Int64)
bb2:
%13 = integer_literal $Builtin.Int64, 5
%14 = struct $Int64 (%13 : $Builtin.Int64)
cond_fail %9 : $Builtin.Int1
destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Int64>
br bb3(%14 : $Int64)
bb3(%18 : $Int64):
%20 = load [trivial] %1 : $*Int64
dealloc_stack %1 : $*Int64
return %18 : $Int64
}
// CHECK-LABEL: sil [ossa] @basic_block_with_loads_and_stores :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'basic_block_with_loads_and_stores'
// test.foo3 (c : Swift.Int64) -> ()
sil [ossa] @basic_block_with_loads_and_stores : $@convention(thin) (Int64) -> () {
bb0(%0 : $Int64):
%1 = alloc_stack $Int64, var, name "c"
store %0 to [trivial] %1 : $*Int64
%3 = alloc_stack $Int64, var, name "x"
%4 = integer_literal $Builtin.Int64, 3
%5 = struct $Int64 (%4 : $Builtin.Int64)
store %5 to [trivial] %3 : $*Int64
%7 = integer_literal $Builtin.Int64, 3
%9 = struct_extract %0 : $Int64, #Int64._value
%10 = builtin "cmp_sgt_Int64"(%9 : $Builtin.Int64, %7 : $Builtin.Int64) : $Builtin.Int1
%12 = integer_literal $Builtin.Int64, 2
%13 = struct $Int64 (%12 : $Builtin.Int64)
store %13 to [trivial] %3 : $*Int64
// function_ref Swift.print (val : Swift.Int64) -> ()
%16 = function_ref @_Ts5printFT3valSi_T_ : $@convention(thin) (Int64) -> ()
%17 = load [trivial] %3 : $*Int64
%18 = apply %16(%17) : $@convention(thin) (Int64) -> ()
dealloc_stack %3 : $*Int64
dealloc_stack %1 : $*Int64
%21 = tuple ()
return %21 : $()
}
// CHECK-LABEL: sil [ossa] @load_uninitialized_empty :
// CHECK: load
// CHECK-LABEL: } // end sil function 'load_uninitialized_empty'
sil [ossa] @load_uninitialized_empty : $@convention(thin) (@inout ()) -> () {
bb0(%0 : $*()):
%1 = alloc_stack $()
%2 = load [trivial] %1 : $*()
store %2 to [trivial] %0 : $*()
dealloc_stack %1 : $*()
%3 = tuple ()
return %3 : $()
}
// CHECK-LABEL: sil [ossa] @mem2reg_debug_value :
// CHECK-NOT: alloc_stack
// CHECK-NOT: debug_value {{.*}} expr op_deref
// CHECK: debug_value %0
// CHECK-LABEL: } // end sil function 'mem2reg_debug_value'
sil [ossa] @mem2reg_debug_value : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
%1 = alloc_stack $Int
store %0 to [trivial] %1 : $*Int
debug_value %1 : $*Int, expr op_deref
%2 = load [trivial] %1 : $*Int
dealloc_stack %1 : $*Int
return %2 : $Int
}
// CHECK-LABEL: sil [ossa] @mem2reg_struct_addr :
// CHECK-NOT: alloc_stack
// CHECK: struct_extract
// CHECK-LABEL: } // end sil function 'mem2reg_struct_addr'
sil [ossa] @mem2reg_struct_addr : $@convention(thin) (Int64) -> Builtin.Int64 {
bb0(%0 : $Int64):
%1 = alloc_stack $Int64
store %0 to [trivial] %1 : $*Int64
%2 = struct_element_addr %1 : $*Int64, #Int64._value
%3 = load [trivial] %2 : $*Builtin.Int64
dealloc_stack %1 : $*Int64
return %3 : $Builtin.Int64
}
// CHECK-LABEL: sil [ossa] @mem2reg_tuple_addr :
// CHECK-NOT: alloc_stack
// CHECK: tuple_extract {{.*}}, 0
// CHECK-LABEL: } // end sil function 'mem2reg_tuple_addr'
sil [ossa] @mem2reg_tuple_addr : $@convention(thin) (Int64) -> Int64 {
bb0(%0 : $Int64):
%1 = alloc_stack $(Int64, Int64)
%2 = tuple (%0 : $Int64, %0 : $Int64)
store %2 to [trivial] %1 : $*(Int64, Int64)
%4 = tuple_element_addr %1 : $*(Int64, Int64), 0
%5 = load [trivial] %4 : $*Int64
dealloc_stack %1 : $*(Int64, Int64)
return %5 : $Int64
}
// CHECK-LABEL: sil [ossa] @struct_extract_if_then_else :
// CHECK-NOT: alloc_stack
sil [ossa] @struct_extract_if_then_else : $@convention(thin) (Int64) -> Int64 {
bb0(%0 : $Int64):
%1 = alloc_stack $Int64
store %0 to [trivial] %1 : $*Int64
%3 = integer_literal $Builtin.Int64, 2
%4 = struct_extract %0 : $Int64, #Int64._value
%5 = builtin "cmp_sgt_Int64"(%4 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
%6 = struct_element_addr %1 : $*Int64, #Int64._value
cond_br %5, bb1, bb2
// CHECK: bb1:
// CHECK: struct_extract %0
bb1:
%8 = load [trivial] %6 : $*Builtin.Int64
%9 = integer_literal $Builtin.Int64, 1
%10 = integer_literal $Builtin.Int1, 0
%11 = builtin "sadd_with_overflow_Int64"(%8 : $Builtin.Int64, %9 : $Builtin.Int64, %10 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
%12 = tuple_extract %11 : $(Builtin.Int64, Builtin.Int1), 0
br bb3(%12 : $Builtin.Int64)
// CHECK: bb2:
// CHECK: struct_extract %0
bb2:
%14 = load [trivial] %6 : $*Builtin.Int64
%15 = integer_literal $Builtin.Int64, 2
%16 = integer_literal $Builtin.Int1, 0
%17 = builtin "sadd_with_overflow_Int64"(%14 : $Builtin.Int64, %15 : $Builtin.Int64, %16 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
%18 = tuple_extract %17 : $(Builtin.Int64, Builtin.Int1), 0
br bb3(%18 : $Builtin.Int64)
// CHECK-NOT: dealloc_stack
bb3(%20 : $Builtin.Int64):
dealloc_stack %1 : $*Int64
%22 = struct $Int64 (%20 : $Builtin.Int64)
return %22 : $Int64
}
// CHECK-LABEL: } // end sil function 'struct_extract_if_then_else'
sil [ossa] @first : $@convention(thin) () -> Int
sil [ossa] @second : $@convention(thin) () -> Int
// CHECK: sil [ossa] @promote_function_refs :
sil [ossa] @promote_function_refs : $@convention(thin) (Bool) -> Int {
// CHECK: bb0
bb0(%0 : $Bool):
// CHECK-NOT: [[STACK:%.*]] = alloc_stack
%1 = alloc_stack $@callee_owned () -> Int
debug_value %0 : $Bool
%3 = struct_extract %0 : $Bool, #Bool._value
cond_br %3, bb1, bb2
// CHECK: bb1
bb1:
// CHECK: [[FIRSTREF:%.*]] = function_ref @first
%5 = function_ref @first : $@convention(thin) () -> Int
// CHECK: [[FIRSTTHICK:%.*]] = thin_to_thick_function [[FIRSTREF]]
%6 = thin_to_thick_function %5 : $@convention(thin) () -> Int to $@callee_owned () -> Int
// CHECK-NOT: store
store %6 to [init] %1 : $*@callee_owned () -> Int
// CHECK: br bb3([[FIRSTTHICK]])
br bb3
// CHECK: bb2
bb2:
// CHECK: [[SECONDREF:%.*]] = function_ref @second
%9 = function_ref @second : $@convention(thin) () -> Int
// CHECK: [[SECONDTHICK:%.*]] = thin_to_thick_function [[SECONDREF]]
%10 = thin_to_thick_function %9 : $@convention(thin) () -> Int to $@callee_owned () -> Int
// CHECK-NOT: store
store %10 to [init] %1 : $*@callee_owned () -> Int
// CHECK: br bb3([[SECONDTHICK]])
br bb3
// CHECK: bb3([[ARG:%.*]] : @owned $@callee_owned () -> Int):
bb3:
// CHECK-NOT: load
%13 = load [copy] %1 : $*@callee_owned () -> Int
// CHECK: [[COPY:%.*]] = copy_value [[ARG]]
// CHECK: [[RESULT:%.*]] = apply [[COPY]]
%15 = apply %13() : $@callee_owned () -> Int
br bb4
// NOTE: This block and the branch above exist to ensure that we
// test what happens when %1 hasn't already been loaded in this
// block.
// CHECK: bb4
bb4:
// CHECK-NOT: destroy_addr
// : destroy_value [[ARG]]
// The above destroy is eliminated by owned value canonicalization.
destroy_addr %1 : $*@callee_owned () -> Int
// CHECK-NOT: dealloc_stack
dealloc_stack %1 : $*@callee_owned () -> Int
return %15 : $Int
}
// CHECK-LABEL: } // end sil function 'promote_function_refs'
// Test cases where the only use is a debug_value_addr
// CHECK-LABEL: sil [ossa] @no_real_uses :
sil [ossa] @no_real_uses : $@convention(thin) () -> () {
// CHECK: bb0
bb0:
// CHECK-NOT: alloc_stack
%0 = alloc_stack [dynamic_lifetime] $Builtin.Int32
// CHECK-NOT: debug_value {{.*}} expr op_deref
debug_value %0 : $*Builtin.Int32, let, name "x", argno 1, expr op_deref
// CHECK-NOT: dealloc_stack
dealloc_stack %0 : $*Builtin.Int32
%1 = tuple ()
return %1 : $()
}
// CHECK-LABEL: } // end sil function 'no_real_uses'
// CHECK-LABEL: sil [ossa] @keep_release :
// CHECK: destroy_value %0
// CHECK-LABEL: } // end sil function 'keep_release'
sil [ossa] @keep_release : $@convention(thin) (@owned AnyObject) -> () {
bb0(%0 : @owned $AnyObject):
%1 = alloc_stack $AnyObject
store %0 to [init] %1 : $*AnyObject
destroy_addr %1 : $*AnyObject
dealloc_stack %1 : $*AnyObject
%7 = tuple ()
return %7 : $()
}
// Test cases where there are dead address instructions.
// CHECK-LABEL: sil [ossa] @dead_use :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'dead_use'
sil [ossa] @dead_use : $@convention(thin) () -> () {
%0 = alloc_stack $Int64
%1 = struct_element_addr %0 : $*Int64, #Int64._value
dealloc_stack %0 : $*Int64
%2 = alloc_stack $(Int64, Int64)
%3 = tuple_element_addr %2 : $*(Int64, Int64), 0
dealloc_stack %2 : $*(Int64, Int64)
%4 = tuple ()
return %4 : $()
}
// CHECK-LABEL: sil [ossa] @dont_crash_on_dead_arg_use :
// CHECK: bb0{{.*}}:
// CHECK: tuple ()
// CHECK-LABEL: } // end sil function 'dont_crash_on_dead_arg_use'
sil [ossa] @dont_crash_on_dead_arg_use : $@convention(thin) (@inout Int64) -> () {
bb0(%0 : $*Int64):
%2 = alloc_stack $Int64
%1 = struct_element_addr %0 : $*Int64, #Int64._value
%3 = struct_element_addr %2 : $*Int64, #Int64._value
dealloc_stack %2 : $*Int64
%4 = tuple ()
return %4 : $()
}
// Make sure that we do expand destroy_addr appropriately for code-size
// trade-offs.
// CHECK-LABEL: sil [ossa] @large_struct_test :
// CHECK: bb0([[ARG0:%.*]] : @owned $LargeCodesizeStruct):
// CHECK: destroy_value [[ARG0]]
// CHECK: } // end sil function 'large_struct_test'
sil [ossa] @large_struct_test : $@convention(thin) (@owned LargeCodesizeStruct) -> () {
bb0(%0 : @owned $LargeCodesizeStruct):
%1 = alloc_stack $LargeCodesizeStruct
store %0 to [init] %1 : $*LargeCodesizeStruct
destroy_addr %1 : $*LargeCodesizeStruct
dealloc_stack %1 : $*LargeCodesizeStruct
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil [ossa] @small_struct_test :
// CHECK: bb0([[ARG0:%.*]] : @owned $SmallCodesizeStruct):
// CHECK: destroy_value [[ARG0]]
// CHECK: } // end sil function 'small_struct_test'
sil [ossa] @small_struct_test : $@convention(thin) (@owned SmallCodesizeStruct) -> () {
bb0(%0 : @owned $SmallCodesizeStruct):
%1 = alloc_stack $SmallCodesizeStruct
store %0 to [init] %1 : $*SmallCodesizeStruct
destroy_addr %1 : $*SmallCodesizeStruct
dealloc_stack %1 : $*SmallCodesizeStruct
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil [ossa] @small_struct_multi_test :
// CHECK-NOT: alloc_stack
// CHECK: [[COPY:%.*]] = copy_value %0
// CHECK-NEXT: destroy_value %0
// CHECK-NEXT: begin_borrow [[COPY]]
// CHECK-NEXT: debug_value
// CHECK-NEXT: end_borrow
// CHECK-NEXT: destroy_value [[COPY]]
// CHECK: bb2:
// CHECK-NEXT: destroy_value %0
// CHECK-LABEL: } // end sil function 'small_struct_multi_test'
sil [ossa] @small_struct_multi_test : $@convention(thin) (@owned SmallCodesizeStruct) -> () {
bb0(%0 : @owned $SmallCodesizeStruct):
%1 = alloc_stack $SmallCodesizeStruct
store %0 to [init] %1 : $*SmallCodesizeStruct
cond_br undef, bb1, bb2
bb1:
%3 = load [copy] %1 : $*SmallCodesizeStruct
destroy_addr %1 : $*SmallCodesizeStruct
dealloc_stack %1 : $*SmallCodesizeStruct
%4 = begin_borrow %3 : $SmallCodesizeStruct
debug_value %4 : $SmallCodesizeStruct
end_borrow %4 : $SmallCodesizeStruct
destroy_value %3 : $SmallCodesizeStruct
br bb3
bb2:
destroy_addr %1 : $*SmallCodesizeStruct
dealloc_stack %1 : $*SmallCodesizeStruct
br bb3
bb3:
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil [ossa] @dead_address_projections :
// CHECK-NOT: alloc_stack
// CHECK: } // end sil function 'dead_address_projections'
sil [ossa] @dead_address_projections : $@convention(thin) (((), ())) -> ((), ()) {
bb0(%0 : $((), ())):
%1 = alloc_stack $((), ())
%200 = tuple_element_addr %1 : $*((), ()), 0
%300 = tuple_element_addr %1 : $*((), ()), 1
cond_br undef, bb1, bb2
bb1:
store %0 to [trivial] %1 : $*((), ())
dealloc_stack %1 : $*((), ())
br bb3
bb2:
dealloc_stack %1 : $*((), ())
br bb3
bb3:
return %0
}
// CHECK-LABEL: sil [ossa] @load_tuple_of_void :
// CHECK: alloc_stack
// CHECK: } // end sil function 'load_tuple_of_void'
sil [ossa] @load_tuple_of_void : $@convention(thin) () -> ((), ()) {
bb0:
%1 = alloc_stack $((), ())
%16 = load [trivial] %1 : $*((), ())
dealloc_stack %1 : $*((), ())
return %16 : $((), ())
}
// CHECK-LABEL: sil [ossa] @test_optional_in_multiple_blocks :
// CHECK-NOT: alloc_stack
// CHECK: } // end sil function 'test_optional_in_multiple_blocks'
sil [ossa] @test_optional_in_multiple_blocks : $@convention(method) (@guaranteed FakeOptional<Klass>) -> () {
bb0(%0 : @guaranteed $FakeOptional<Klass>):
%1 = copy_value %0 : $FakeOptional<Klass>
%32 = alloc_stack $FakeOptional<Klass>
store %1 to [init] %32 : $*FakeOptional<Klass>
switch_enum %0 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb6, case #FakeOptional.none!enumelt: bb5
bb5:
dealloc_stack %32 : $*FakeOptional<Klass>
br bb7
bb6(%50 : @guaranteed $Klass):
%53 = load [copy] %32 : $*FakeOptional<Klass>
destroy_value %53 : $FakeOptional<Klass>
destroy_addr %32 : $*FakeOptional<Klass>
dealloc_stack %32 : $*FakeOptional<Klass>
br bb7
bb7:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @test_optional_in_multiple_blocks_lexical :
// CHECK-NOT: alloc_stack
// CHECK: } // end sil function 'test_optional_in_multiple_blocks_lexical'
sil [ossa] @test_optional_in_multiple_blocks_lexical : $@convention(method) (@guaranteed FakeOptional<Klass>) -> () {
bb0(%0 : @guaranteed $FakeOptional<Klass>):
%1 = copy_value %0 : $FakeOptional<Klass>
%32 = alloc_stack [lexical] $FakeOptional<Klass>
store %1 to [init] %32 : $*FakeOptional<Klass>
switch_enum %0 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb6, case #FakeOptional.none!enumelt: bb5
bb5:
dealloc_stack %32 : $*FakeOptional<Klass>
br bb7
bb6(%50 : @guaranteed $Klass):
%53 = load [copy] %32 : $*FakeOptional<Klass>
destroy_value %53 : $FakeOptional<Klass>
destroy_addr %32 : $*FakeOptional<Klass>
dealloc_stack %32 : $*FakeOptional<Klass>
br bb7
bb7:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @test_optional_in_multiple_blocks_lexical_storedvalue :
// CHECK-NOT: alloc_stack
// CHECK: } // end sil function 'test_optional_in_multiple_blocks_lexical_storedvalue'
sil [ossa] @test_optional_in_multiple_blocks_lexical_storedvalue : $@convention(method) (@owned FakeOptional<Klass>) -> () {
bb0(%0 : @owned $FakeOptional<Klass>):
%1 = copy_value %0 : $FakeOptional<Klass>
%32 = alloc_stack $FakeOptional<Klass>
store %0 to [init] %32 : $*FakeOptional<Klass>
switch_enum %1 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb6, case #FakeOptional.none!enumelt: bb5
bb5:
dealloc_stack %32 : $*FakeOptional<Klass>
br bb7
bb6(%50 : @owned $Klass):
%53 = load [copy] %32 : $*FakeOptional<Klass>
destroy_value %53 : $FakeOptional<Klass>
destroy_value %50 : $Klass
destroy_addr %32 : $*FakeOptional<Klass>
dealloc_stack %32 : $*FakeOptional<Klass>
br bb7
bb7:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @optimize_optional_in_single_block :
// CHECK-NOT: alloc_stack
// CHECK: } // end sil function 'optimize_optional_in_single_block'
sil [ossa] @optimize_optional_in_single_block : $@convention(method) (@guaranteed FakeOptional<Klass>) -> () {
bb0(%0 : @guaranteed $FakeOptional<Klass>):
switch_enum %0 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb6, case #FakeOptional.none!enumelt: bb5
bb5:
br bb7
bb6(%50 : @guaranteed $Klass):
%32 = alloc_stack $FakeOptional<Klass>
%1 = copy_value %0 : $FakeOptional<Klass>
store %1 to [init] %32 : $*FakeOptional<Klass>
%53 = load [take] %32 : $*FakeOptional<Klass>
destroy_value %53 : $FakeOptional<Klass>
dealloc_stack %32 : $*FakeOptional<Klass>
br bb7
bb7:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @switch_enum_out_of_new_phi_block : {{.*}} {
// CHECK-NOT: alloc_stack
// CHECK: } // end sil function 'switch_enum_out_of_new_phi_block'
sil [ossa] @switch_enum_out_of_new_phi_block : $() -> () {
entry:
%addr = alloc_stack $FakeOptional<Klass>
cond_br undef, store_none, agg_either
store_none:
%none1 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
store %none1 to [init] %addr : $*FakeOptional<Klass>
br switcheroo
agg_either:
cond_br undef, agg_some, agg_none
agg_some:
%Klass = apply undef() : $@convention(thin) () -> (@owned Klass)
%some = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %Klass : $Klass
br store_maybe(%some : $FakeOptional<Klass>)
agg_none:
%none2 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br store_maybe(%none2 : $FakeOptional<Klass>)
store_maybe(%maybe : @owned $FakeOptional<Klass>):
store %maybe to [init] %addr : $*FakeOptional<Klass>
br switcheroo
switcheroo:
%borrow = load_borrow %addr : $*FakeOptional<Klass>
switch_enum %borrow : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb14, case #FakeOptional.none!enumelt: bb15
bb14(%some_borrowed : @guaranteed $Klass):
end_borrow %borrow : $FakeOptional<Klass>
destroy_addr %addr : $*FakeOptional<Klass>
br bb16
bb15:
end_borrow %borrow : $FakeOptional<Klass>
br bb16
bb16:
dealloc_stack %addr : $*FakeOptional<Klass>
%retval = tuple ()
return %retval : $()
}
// This is optimized by `load` and `store_borrow` simplification
// CHECK-LABEL: sil [ossa] @debug_value_of_store_borrow_addr_multi_block : {{.*}} {
// CHECK: store_borrow
// CHECK-LABEL: } // end sil function 'debug_value_of_store_borrow_addr_multi_block'
sil [ossa] @debug_value_of_store_borrow_addr_multi_block : $@convention(thin) (@owned S) -> () {
entry(%instance : @owned $S):
br header
header:
%lifetime = begin_borrow %instance : $S
%stack = alloc_stack $S
%stack_borrow = store_borrow %lifetime to %stack : $*S
debug_value %stack_borrow : $*S, expr op_deref
br body
body:
%field_addr = struct_element_addr %stack_borrow : $*S, #S.field
%field = load [copy] %field_addr : $*C
end_borrow %stack_borrow : $*S
dealloc_stack %stack : $*S
end_borrow %lifetime : $S
destroy_value %field : $C
cond_br undef, backedge, exit
backedge:
br header
exit:
destroy_value %instance : $S
%retval = tuple ()
return %retval : $()
}
// This is optimized by `load` and `store_borrow` simplification
// CHECK-LABEL: sil [ossa] @debug_value_of_store_borrow_addr_single_block : {{.*}} {
// CHECK: store_borrow
// CHECK-LABEL: } // end sil function 'debug_value_of_store_borrow_addr_single_block'
sil [ossa] @debug_value_of_store_borrow_addr_single_block : $@convention(thin) (@owned S) -> () {
entry(%instance : @owned $S):
br header
header:
%lifetime = begin_borrow %instance : $S
%stack = alloc_stack $S
%stack_borrow = store_borrow %lifetime to %stack : $*S
debug_value %stack_borrow : $*S, expr op_deref
%field_addr = struct_element_addr %stack_borrow : $*S, #S.field
%field = load [copy] %field_addr : $*C
end_borrow %stack_borrow : $*S
dealloc_stack %stack : $*S
end_borrow %lifetime : $S
destroy_value %field : $C
cond_br undef, backedge, exit
backedge:
br header
exit:
destroy_value %instance : $S
%retval = tuple ()
return %retval : $()
}
// CHECK-LABEL: sil [ossa] @dont_canonicalize_undef : {{.*}} {
// CHECK: [[RETVAL:%[^,]+]] = tuple
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'dont_canonicalize_undef'
sil [ossa] @dont_canonicalize_undef : $@convention(thin) () -> () {
%addr = alloc_stack $()
store undef to [trivial] %addr : $*()
dealloc_stack %addr : $*()
%retval = tuple ()
return %retval : $()
}
// CHECK-LABEL: sil [ossa] @dont_canonicalize_erased_copy : {{.*}} {
// CHECK: bb0(%0 :
// CHECK: destroy_value %0
// CHECK-LABEL: } // end sil function 'dont_canonicalize_erased_copy'
sil [ossa] @dont_canonicalize_erased_copy : $@convention(thin) (@owned C) -> () {
entry(%instance : @owned $C):
%stack = alloc_stack $C
%copy = copy_value %instance : $C
store %copy to [init] %stack : $*C
%loaded_copy = load [take] %stack : $*C
destroy_value %loaded_copy : $C
store %instance to [init] %stack : $*C
%loaded_instance = load [take] %stack : $*C
destroy_value %loaded_instance : $C
dealloc_stack %stack : $*C
%retval = tuple ()
return %retval : $()
}
// CHECK-LABEL: sil [ossa] @no_promo_proj_uac_1 : {{.*}} {
// CHECK: alloc_stack
// CHECK-LABEL: } // end sil function 'no_promo_proj_uac_1'
sil [ossa] @no_promo_proj_uac_1 : $@convention(thin) () -> () {
bb0:
%s = apply undef() : $@convention(thin) () -> (@owned S1)
%addr = alloc_stack $S1
store %s to [init] %addr
%i_addr = unchecked_addr_cast %addr to $*Ix
%j_addr = struct_element_addr %i_addr, #Ix.j
%j = load [copy] %j_addr
destroy_addr %addr
dealloc_stack %addr
apply undef(%j) : $@convention(thin) (@owned J) -> ()
%retval = tuple ()
return %retval
}
// CHECK-LABEL: sil [ossa] @no_promo_proj_uac_2 : {{.*}} {
// CHECK: alloc_stack
// CHECK-LABEL: } // end sil function 'no_promo_proj_uac_2'
sil [ossa] @no_promo_proj_uac_2 : $@convention(thin) () -> () {
bb0:
%s = apply undef() : $@convention(thin) () -> (@owned S2x)
%addr = alloc_stack $S2x
store %s to [init] %addr
%t_addr = unchecked_addr_cast %addr to $*(J, J)
%j_addr = tuple_element_addr %t_addr, 0
%j = load [copy] %j_addr
destroy_addr %addr
dealloc_stack %addr
apply undef(%j) : $@convention(thin) (@owned J) -> ()
%retval = tuple ()
return %retval
}
// CHECK-LABEL: sil [ossa] @no_promo_uac_uac : {{.*}} {
// CHECK: alloc_stack
// CHECK-LABEL: } // end sil function 'no_promo_uac_uac'
sil [ossa] @no_promo_uac_uac : $@convention(thin) () -> () {
bb0:
%s = apply undef() : $@convention(thin) () -> (@owned S1)
%addr = alloc_stack $S1
store %s to [init] %addr
%i_addr = unchecked_addr_cast %addr to $*Ix
%j_addr = unchecked_addr_cast %i_addr to $*J
%j = load [copy] %j_addr
destroy_addr %addr
dealloc_stack %addr
apply undef(%j) : $@convention(thin) (@owned J) -> ()
%retval = tuple ()
return %retval
}
// CHECK-LABEL: sil [ossa] @dead_end_only_store_non_lexical :
// CHECK-NOT: alloc_stack
// CHECK: destroy_value [dead_end] %0
// CHECK-LABEL: } // end sil function 'dead_end_only_store_non_lexical'
sil [ossa] @dead_end_only_store_non_lexical : $@convention(thin) (@owned C) -> () {
bb0(%0 : @owned $C):
%1 = alloc_stack $C
store %0 to [init] %1
unreachable
}
// CHECK-LABEL: sil [ossa] @write_only_in_dead_end :
// CHECK: bb2:
// CHECK-NEXT: [[L:%.*]] = load [take] %0
// CHECK-NEXT: dealloc_stack %0
// CHECK-NEXT: destroy_value [dead_end] [[L]]
// CHECK-LABEL: } // end sil function 'write_only_in_dead_end'
sil [ossa] @write_only_in_dead_end : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $any Error
%1 = alloc_stack $any Error
try_apply undef(%1) : $@noescape @callee_guaranteed () -> ((), @error_indirect any Error), normal bb1, error bb2
bb1(%3 : $()):
dealloc_stack %1
dealloc_stack %0
return %3
bb2:
%7 = load [take] %1
dealloc_stack %1
store %7 to [init] %0
unreachable
}
// CHECK-LABEL: sil [ossa] @write_only_in_single_block_dead_end :
// CHECK: apply
// CHECK-NEXT: [[L:%.*]] = load [take] %0
// CHECK-NEXT: dealloc_stack %0
// CHECK-NEXT: end_lifetime [[L]]
// CHECK-LABEL: } // end sil function 'write_only_in_single_block_dead_end'
sil [ossa] @write_only_in_single_block_dead_end : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $AnyObject
%1 = alloc_stack $AnyObject
%2 = apply undef(%1) : $@noescape @callee_guaranteed () -> @out AnyObject
%7 = load [take] %1
dealloc_stack %1
store %7 to [init] %0
dealloc_stack %0
unreachable
}
sil shared [noinline] @blackhole_spl : $@convention(thin) (@guaranteed Klass) -> () {
bb0(%0 : $Klass):
%1 = tuple ()
return %1 : $()
}
// CHECK-LABEL: sil [ossa] @store_only_allocas2 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'store_only_allocas2'
sil [ossa] @store_only_allocas2 : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
%1 = alloc_stack $Klass
store %0 to [init] %1 : $*Klass
%2 = function_ref @blackhole_spl : $@convention(thin) (@guaranteed Klass) -> ()
%3 = load [take] %1 : $*Klass
%4 = apply %2(%3) : $@convention(thin) (@guaranteed Klass) -> ()
destroy_value %3 : $Klass
dealloc_stack %1 : $*Klass
%6 = tuple ()
return %6 : $()
}
// CHECK-LABEL: sil [ossa] @multiple_store_vals_b :
// CHECK-NOT: alloc_stack
// CHECK: destroy_value %0
// CHECK: [[FUNC:%.*]] = function_ref @blackhole_spl :
// CHECK: apply [[FUNC]](%1) : $@convention(thin) (@guaranteed Klass) -> ()
// CHECK: destroy_value %1
// CHECK-LABEL: } // end sil function 'multiple_store_vals_b'
sil [ossa] @multiple_store_vals_b : $@convention(thin) (@owned Klass, @owned Klass) -> () {
bb0(%0 : @owned $Klass, %1 : @owned $Klass):
%2 = alloc_stack $Klass
store %0 to [init] %2 : $*Klass
%3 = integer_literal $Builtin.Int1, 0
cond_fail %3 : $Builtin.Int1
store %1 to [assign] %2 : $*Klass
%4 = function_ref @blackhole_spl : $@convention(thin) (@guaranteed Klass) -> ()
%5 = load [take] %2 : $*Klass
%6 = apply %4(%5) : $@convention(thin) (@guaranteed Klass) -> ()
destroy_value %5 : $Klass
dealloc_stack %2 : $*Klass
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil [ossa] @multiple_store_vals2b :
// CHECK-NOT: alloc_stack
// CHECK: destroy_value %0
// CHECK: [[FUNC:%.*]] = function_ref @blackhole_spl :
// CHECK: apply [[FUNC]](%1) : $@convention(thin) (@guaranteed Klass) -> ()
// CHECK: destroy_value %1
// CHECK-LABEL: } // end sil function 'multiple_store_vals2b'
sil [ossa] @multiple_store_vals2b : $@convention(thin) (@owned Klass, @owned Klass) -> () {
bb0(%0 : @owned $Klass, %1 : @owned $Klass):
%2 = alloc_stack $Klass
store %0 to [init] %2 : $*Klass
%3 = integer_literal $Builtin.Int1, 0
cond_fail %3 : $Builtin.Int1
destroy_addr %2 : $*Klass
store %1 to [init] %2 : $*Klass
%4 = function_ref @blackhole_spl : $@convention(thin) (@guaranteed Klass) -> ()
%5 = load [take] %2 : $*Klass
%6 = apply %4(%5) : $@convention(thin) (@guaranteed Klass) -> ()
destroy_value %5 : $Klass
dealloc_stack %2 : $*Klass
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil [ossa] @multiple_store_vals3 :
// CHECK-NOT: alloc_stack
// The COPY0 copy/destroy is eliminated by owned value canonicalization.
// : [[COPY0:%.*]] = copy_value %0
// CHECK: [[COPY1:%.*]] = copy_value %1
// : destroy_value [[COPY0]]
// CHECK: [[FUNC:%.*]] = function_ref @blackhole_spl :
// CHECK: apply [[FUNC]]([[COPY1]]) : $@convention(thin) (@guaranteed Klass) -> ()
// CHECK: destroy_value [[COPY1]]
// CHECK-LABEL: } // end sil function 'multiple_store_vals3'
sil [ossa] @multiple_store_vals3 : $@convention(thin) (@guaranteed Klass, @guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass, %1 : @guaranteed $Klass):
%2 = alloc_stack $Klass
%copy0 = copy_value %0 : $Klass
store %copy0 to [init] %2 : $*Klass
%3 = integer_literal $Builtin.Int1, 0
cond_fail %3 : $Builtin.Int1
%copy1 = copy_value %1 : $Klass
store %copy1 to [assign] %2 : $*Klass
%4 = function_ref @blackhole_spl : $@convention(thin) (@guaranteed Klass) -> ()
%5 = load [take] %2 : $*Klass
%6 = apply %4(%5) : $@convention(thin) (@guaranteed Klass) -> ()
destroy_value %5 : $Klass
dealloc_stack %2 : $*Klass
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil [ossa] @multiple_store_vals4 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'multiple_store_vals4'
sil [ossa] @multiple_store_vals4 : $@convention(thin) (@owned Klass, @owned Klass) -> () {
bb0(%0 : @owned $Klass, %1 : @owned $Klass):
%2 = alloc_stack $Klass
store %0 to [init] %2 : $*Klass
%3 = alloc_box $<τ_0_0> { var τ_0_0 } <Klass>
%3a = project_box %3 : $<τ_0_0> { var τ_0_0 } <Klass>, 0
store %1 to [assign] %2 : $*Klass
cond_br undef, bb1, bb2
bb1:
destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Klass>
br bb3
bb2:
destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Klass>
br bb3
bb3:
destroy_addr %2 : $*Klass
dealloc_stack %2 : $*Klass
%ret = tuple ()
return %ret : $()
}
// CHECK-LABEL: sil [ossa] @multiple_store_vals5 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'multiple_store_vals5'
sil [ossa] @multiple_store_vals5 : $@convention(thin) (@owned Klass, @owned Klass, @owned Klass) -> () {
bb0(%0 : @owned $Klass, %1 : @owned $Klass, %2 : @owned $Klass):
%stk = alloc_stack $Klass
store %0 to [init] %stk : $*Klass
%3 = alloc_box $<τ_0_0> { var τ_0_0 } <Klass>
%3a = project_box %3 : $<τ_0_0> { var τ_0_0 } <Klass>, 0
store %1 to [assign] %stk : $*Klass
store %2 to [assign] %stk : $*Klass
cond_br undef, bb1, bb2
bb1:
destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Klass>
br bb3
bb2:
destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Klass>
br bb3
bb3:
destroy_addr %stk : $*Klass
dealloc_stack %stk : $*Klass
%ret = tuple ()
return %ret : $()
}
// CHECK-LABEL: sil [ossa] @multiple_store_vals6 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'multiple_store_vals6'
sil [ossa] @multiple_store_vals6 : $@convention(thin) (@owned Klass, @owned Klass) -> () {
bb0(%0 : @owned $Klass, %1 : @owned $Klass):
br bb1
bb1:
%2 = alloc_stack $Klass
store %0 to [init] %2 : $*Klass
%3 = integer_literal $Builtin.Int1, 0
cond_fail %3 : $Builtin.Int1
store %1 to [assign] %2 : $*Klass
br bb2
bb2:
%4 = function_ref @blackhole_spl : $@convention(thin) (@guaranteed Klass) -> ()
%5 = load [take] %2 : $*Klass
%6 = apply %4(%5) : $@convention(thin) (@guaranteed Klass) -> ()
destroy_value %5 : $Klass
dealloc_stack %2 : $*Klass
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil [ossa] @multiple_store_vals7 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'multiple_store_vals7'
sil [ossa] @multiple_store_vals7 : $@convention(thin) (@owned Klass, @owned Klass, @owned Klass) -> () {
bb0(%0 : @owned $Klass, %1 : @owned $Klass, %2 : @owned $Klass):
%stk = alloc_stack $Klass
store %0 to [init] %stk : $*Klass
%3 = integer_literal $Builtin.Int1, 0
cond_fail %3 : $Builtin.Int1
br bb1
bb1:
store %1 to [assign] %stk : $*Klass
store %2 to [assign] %stk : $*Klass
br bb2
bb2:
%4 = function_ref @blackhole_spl : $@convention(thin) (@guaranteed Klass) -> ()
%5 = load [take] %stk : $*Klass
%6 = apply %4(%5) : $@convention(thin) (@guaranteed Klass) -> ()
destroy_value %5 : $Klass
dealloc_stack %stk : $*Klass
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil [ossa] @multiple_store_vals8 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'multiple_store_vals8'
sil [ossa] @multiple_store_vals8 : $@convention(thin) (@owned Klass, @owned Klass, @owned Klass) -> () {
bb0(%0 : @owned $Klass, %1 : @owned $Klass, %2 : @owned $Klass):
%stk = alloc_stack $Klass
store %0 to [init] %stk : $*Klass
%3 = integer_literal $Builtin.Int1, 0
cond_fail %3 : $Builtin.Int1
br bb1
bb1:
store %1 to [assign] %stk : $*Klass
destroy_addr %stk : $*Klass
store %2 to [init] %stk : $*Klass
br bb2
bb2:
%4 = function_ref @blackhole_spl : $@convention(thin) (@guaranteed Klass) -> ()
%5 = load [take] %stk : $*Klass
%6 = apply %4(%5) : $@convention(thin) (@guaranteed Klass) -> ()
destroy_value %5 : $Klass
dealloc_stack %stk : $*Klass
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil [ossa] @with_loads :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'with_loads'
sil [ossa] @with_loads : $@convention(thin) (@owned Klass, @owned Klass) -> @owned Klass {
bb0(%0 : @owned $Klass, %1 : @owned $Klass):
%2 = alloc_stack $Klass
store %0 to [init] %2 : $*Klass
%3 = alloc_box $<τ_0_0> { var τ_0_0 } <Klass>
%3a = project_box %3 : $<τ_0_0> { var τ_0_0 } <Klass>, 0
store %1 to [assign] %2 : $*Klass
cond_br undef, bb1, bb2
bb1:
destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Klass>
br bb3
bb2:
destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Klass>
br bb3
bb3:
%ret = load [take] %2 : $*Klass
dealloc_stack %2 : $*Klass
return %ret : $Klass
}
// CHECK-LABEL: sil [ossa] @basic_block_with_loads_and_stores2 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'basic_block_with_loads_and_stores2'
sil [ossa] @basic_block_with_loads_and_stores2 : $@convention(thin) (@owned Klass, @owned Klass) -> () {
bb0(%0 : @owned $Klass, %1 : @owned $Klass):
%2 = alloc_stack $Klass
store %0 to [init] %2 : $*Klass
%3 = alloc_stack $Klass
store %1 to [init] %3 : $*Klass
%local = alloc_ref $Klass
store %local to [assign] %3 : $*Klass
%func = function_ref @blackhole_spl : $@convention(thin) (@guaranteed Klass) -> ()
%arg = load [take] %3 : $*Klass
%applyres = apply %func(%arg) : $@convention(thin) (@guaranteed Klass) -> ()
destroy_value %arg : $Klass
destroy_addr %2 : $*Klass
dealloc_stack %3 : $*Klass
dealloc_stack %2 : $*Klass
%res = tuple ()
return %res : $()
}
// CHECK-LABEL: sil [ossa] @basic_block_with_loads_copy_and_take :
// CHECK-NOT: alloc_stack
// The COPY/destroy pair is eliminated by owned value canonicalization.
// : [[COPY:%.*]] = copy_value %0
// : destroy_value [[COPY]]
// CHECK: destroy_value %0
// CHECK-LABEL: } // end sil function 'basic_block_with_loads_copy_and_take'
sil [ossa] @basic_block_with_loads_copy_and_take : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
%1 = alloc_stack $Klass
store %0 to [init] %1 : $*Klass
%copy = load [copy] %1 : $*Klass
%take = load [take] %1 : $*Klass
destroy_value %copy : $Klass
destroy_value %take : $Klass
dealloc_stack %1 : $*Klass
%res = tuple ()
return %res : $()
}
// load [copy] is not used as RunningVal
// StackAllocationPromoter::fixBranchesAndUses will delete the loads and replace with %0
// CHECK-LABEL: sil [ossa] @multi_basic_block_with_loads_copy_and_take_1 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'multi_basic_block_with_loads_copy_and_take_1'
sil [ossa] @multi_basic_block_with_loads_copy_and_take_1 : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
%1 = alloc_stack $Klass
store %0 to [init] %1 : $*Klass
br bb1
bb1:
%copy = load [copy] %1 : $*Klass
%take = load [take] %1 : $*Klass
destroy_value %copy : $Klass
destroy_value %take : $Klass
dealloc_stack %1 : $*Klass
%res = tuple ()
return %res : $()
}
// load [copy] is not used as RunningVal
// StackAllocationPromoter::fixBranchesAndUses will delete the loads and replace with %0
// CHECK-LABEL: sil [ossa] @multi_basic_block_with_loads_copy_and_take_2 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'multi_basic_block_with_loads_copy_and_take_2'
sil [ossa] @multi_basic_block_with_loads_copy_and_take_2 : $@convention(thin) (@owned Klass) -> @owned Klass {
bb0(%0 : @owned $Klass):
%1 = alloc_stack $Klass
store %0 to [init] %1 : $*Klass
br bb1
bb1:
%copy = load [copy] %1 : $*Klass
%take = load [take] %1 : $*Klass
destroy_value %take : $Klass
dealloc_stack %1 : $*Klass
return %copy : $Klass
}
// load [take] is used as RunningVal in bb1
// CHECK-LABEL: sil [ossa] @multi_basic_block_with_loads_copy_and_take_3 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'multi_basic_block_with_loads_copy_and_take_3'
sil [ossa] @multi_basic_block_with_loads_copy_and_take_3 : $@convention(thin) (@owned Klass) -> @owned Klass {
bb0(%0 : @owned $Klass):
%1 = alloc_stack $Klass
store %0 to [init] %1 : $*Klass
br bb1
bb1:
%take = load [take] %1 : $*Klass
%copy = copy_value %take : $Klass
destroy_value %take : $Klass
dealloc_stack %1 : $*Klass
return %copy : $Klass
}
// CHECK-LABEL: sil [ossa] @multi_basic_block_with_store_assign :
// CHECK-NOT: alloc_stack
// CHECK: destroy_value %0
// CHECK-LABEL: } // end sil function 'multi_basic_block_with_store_assign'
sil [ossa] @multi_basic_block_with_store_assign : $@convention(thin) (@owned Klass, @owned Klass) -> @owned Klass {
bb0(%0 : @owned $Klass, %1: @owned $Klass):
%stk = alloc_stack $Klass
store %0 to [init] %stk : $*Klass
br bb1
bb1:
store %1 to [assign] %stk : $*Klass
%res = load [take] %stk : $*Klass
dealloc_stack %stk : $*Klass
return %res : $Klass
}
// CHECK-LABEL: sil [ossa] @multi_basic_block_with_phiarg :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: bb1:
// CHECK: br bb3(%1)
// CHECK-LABEL: bb2:
// CHECK: br bb3(%0)
// CHECK-LABEL: } // end sil function 'multi_basic_block_with_phiarg'
sil [ossa] @multi_basic_block_with_phiarg : $@convention(thin) (@owned Klass, @owned Klass) -> () {
bb0(%0 : @owned $Klass, %1 : @owned $Klass):
%stk = alloc_stack $Klass
cond_br undef, bb1, bb2
bb1:
store %1 to [init] %stk : $*Klass
destroy_value %0 : $Klass
br bb3
bb2:
store %0 to [init] %stk : $*Klass
destroy_value %1 : $Klass
br bb3
bb3:
%val = load [take] %stk : $*Klass
destroy_value %val : $Klass
dealloc_stack %stk : $*Klass
%res = tuple ()
return %res : $()
}
// CHECK-LABEL: sil [ossa] @multi_asi_basic_block_with_phiarg :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: bb1:
// CHECK: br bb3(%1, %0)
// CHECK-LABEL: bb2:
// CHECK: br bb3(%0, %1)
// CHECK: bb3([[PHI1:%.*]] : @owned $Klass, [[PHI2:%.*]] : @owned $Klass):
// CHECK: destroy_value [[PHI1]]
// CHECK: destroy_value [[PHI2]]
// CHECK-LABEL: } // end sil function 'multi_asi_basic_block_with_phiarg'
sil [ossa] @multi_asi_basic_block_with_phiarg : $@convention(thin) (@owned Klass, @owned Klass) -> () {
bb0(%0 : @owned $Klass, %1 : @owned $Klass):
%stk1 = alloc_stack $Klass
%stk2 = alloc_stack $Klass
cond_br undef, bb1, bb2
bb1:
store %1 to [init] %stk1 : $*Klass
store %0 to [init] %stk2 : $*Klass
br bb3
bb2:
store %1 to [init] %stk2 : $*Klass
store %0 to [init] %stk1 : $*Klass
br bb3
bb3:
%val1 = load [take] %stk1 : $*Klass
destroy_value %val1 : $Klass
%val2 = load [take] %stk2 : $*Klass
destroy_value %val2 : $Klass
dealloc_stack %stk2 : $*Klass
dealloc_stack %stk1 : $*Klass
%res = tuple ()
return %res : $()
}
// Test to check no dead args are passed to bb3 as phi arg
// CHECK-LABEL: sil [ossa] @multi_basic_block_stack_deallocated_phiarg :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: bb2:
// CHECK: br bb3
// CHECK: bb3:
// CHECK-LABEL: } // end sil function 'multi_basic_block_stack_deallocated_phiarg'
sil [ossa] @multi_basic_block_stack_deallocated_phiarg : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
%stk = alloc_stack $Klass
cond_br undef, bb1, bb2
bb1:
dealloc_stack %stk : $*Klass
destroy_value %0 : $Klass
br bb3
bb2:
store %0 to [init] %stk : $*Klass
%val = load [take] %stk : $*Klass
dealloc_stack %stk : $*Klass
destroy_value %val : $Klass
br bb3
bb3:
%res = tuple ()
return %res : $()
}
// Test to check no dead args are passed to bb3 as phi arg
// CHECK-LABEL: sil [ossa] @multi_asi_basic_block_stack_deallocated_phiarg :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: bb2:
// CHECK: br bb3
// CHECK: bb3:
// CHECK-LABEL: } // end sil function 'multi_asi_basic_block_stack_deallocated_phiarg'
sil [ossa] @multi_asi_basic_block_stack_deallocated_phiarg : $@convention(thin) (@owned Klass, @owned Klass) -> () {
bb0(%0 : @owned $Klass, %1 : @owned $Klass):
%stk1 = alloc_stack $Klass
%stk2 = alloc_stack $Klass
cond_br undef, bb1, bb2
bb1:
dealloc_stack %stk2 : $*Klass
dealloc_stack %stk1 : $*Klass
destroy_value %0 : $Klass
destroy_value %1 : $Klass
br bb3
bb2:
store %0 to [init] %stk1 : $*Klass
%val1 = load [take] %stk1 : $*Klass
store %1 to [init] %stk2 : $*Klass
%val2 = load [take] %stk2 : $*Klass
destroy_value %val1 : $Klass
destroy_value %val2 : $Klass
dealloc_stack %stk2 : $*Klass
dealloc_stack %stk1 : $*Klass
br bb3
bb3:
%res = tuple ()
return %res : $()
}
// CHECK-LABEL: sil [ossa] @multi_basic_block_destroyed_last_stored_val_phiarg :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: bb3:
// CHECK-LABEL: } // end sil function 'multi_basic_block_destroyed_last_stored_val_phiarg'
sil [ossa] @multi_basic_block_destroyed_last_stored_val_phiarg : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
%stk = alloc_stack $Klass
cond_br undef, bb1, bb2
bb1:
destroy_value %0 : $Klass
br bb3
bb2:
store %0 to [init] %stk : $*Klass
%val = load [take] %stk : $*Klass
destroy_value %val : $Klass
br bb3
bb3:
dealloc_stack %stk : $*Klass
%res = tuple ()
return %res : $()
}
// CHECK-LABEL: sil [ossa] @mem2reg_debug_value2 :
// CHECK-NOT: alloc_stack
// CHECK-NOT: debug_value {{.*}} expr op_deref
// CHECK: debug_value %0
// CHECK-LABEL: } // end sil function 'mem2reg_debug_value2'
sil [ossa] @mem2reg_debug_value2 : $@convention(thin) (@owned Klass) -> @owned Klass {
bb0(%0 : @owned $Klass):
%1 = alloc_stack $Klass
store %0 to [init] %1 : $*Klass
debug_value %1 : $*Klass, expr op_deref
%2 = load [take] %1 : $*Klass
dealloc_stack %1 : $*Klass
return %2 : $Klass
}
// CHECK-LABEL: sil [ossa] @mem2reg_struct_addr2 :
// CHECK-NOT: alloc_stack
// CHECK: [[BORROW:%.*]] = begin_borrow %0
// CHECK: [[ELE:%.*]] = struct_extract [[BORROW]]
// CHECK: [[COPY:%.*]] = copy_value [[ELE]]
// CHECK: end_borrow [[BORROW]]
// CHECK: return [[COPY]]
// CHECK-LABEL: } // end sil function 'mem2reg_struct_addr2'
sil [ossa] @mem2reg_struct_addr2 : $@convention(thin) (@owned SmallCodesizeStruct) -> @owned Klass {
bb0(%0 : @owned $SmallCodesizeStruct):
%1 = alloc_stack $SmallCodesizeStruct
store %0 to [init] %1 : $*SmallCodesizeStruct
%2 = struct_element_addr %1 : $*SmallCodesizeStruct, #SmallCodesizeStruct.cls1
%3 = load [copy] %2 : $*Klass
destroy_addr %1 : $*SmallCodesizeStruct
dealloc_stack %1 : $*SmallCodesizeStruct
return %3 : $Klass
}
// SILMem2Reg is disabled when there is a load [take] with struct_element_addr/tuple_element_addr
// CHECK-LABEL: sil [ossa] @mem2reg_struct_addr_load_take :
// CHECK: %1 = destructure_struct %0
// CHECK: destroy_value %1
// CHECK-NEXT: tuple
// CHECK-LABEL: } // end sil function 'mem2reg_struct_addr_load_take'
sil [ossa] @mem2reg_struct_addr_load_take : $@convention(thin) (@owned WrapperStruct) -> () {
bb0(%0 : @owned $WrapperStruct):
%1 = alloc_stack $WrapperStruct
store %0 to [init] %1 : $*WrapperStruct
%2 = struct_element_addr %1 : $*WrapperStruct, #WrapperStruct.cls
%3 = load [take] %2 : $*Klass
destroy_value %3 : $Klass
dealloc_stack %1 : $*WrapperStruct
%tup = tuple ()
return %tup : $()
}
// CHECK-LABEL: sil [ossa] @mem2reg_tuple_addr2 :
// CHECK-NOT: alloc_stack
// CHECK: [[TUP:%.*]] = tuple (%0, %1)
// CHECK: [[BORROW:%.*]] = begin_borrow [[TUP]]
// CHECK: [[ELE:%.*]] = tuple_extract [[BORROW]]
// CHECK: [[COPY:%.*]] = copy_value [[ELE]]
// CHECK: end_borrow [[BORROW]]
// CHECK: return [[COPY]]
// CHECK-LABEL: } // end sil function 'mem2reg_tuple_addr2'
sil [ossa] @mem2reg_tuple_addr2 : $@convention(thin) (@owned Klass, @owned Klass) -> @owned Klass {
bb0(%0 : @owned $Klass, %1 : @owned $Klass):
%stk = alloc_stack $(Klass, Klass)
%2 = tuple (%0 : $Klass, %1 : $Klass)
store %2 to [init] %stk : $*(Klass, Klass)
%4 = tuple_element_addr %stk : $*(Klass, Klass), 0
%5 = load [copy] %4 : $*Klass
destroy_addr %stk : $*(Klass, Klass)
dealloc_stack %stk : $*(Klass, Klass)
return %5 : $Klass
}
// CHECK-LABEL: sil [ossa] @struct_extract_if_then_else2 :
// CHECK-NOT: alloc_stack
sil [ossa] @struct_extract_if_then_else2 : $@convention(thin) (Int64) -> Int64 {
bb0(%0 : $Int64):
%1 = alloc_stack $Int64
store %0 to [trivial] %1 : $*Int64
%3 = integer_literal $Builtin.Int64, 2
%4 = struct_extract %0 : $Int64, #Int64._value
%5 = builtin "cmp_sgt_Int64"(%4 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
%6 = struct_element_addr %1 : $*Int64, #Int64._value
cond_br %5, bb1, bb2
// CHECK: bb1:
// CHECK: struct_extract %0
bb1:
%8 = load [trivial] %6 : $*Builtin.Int64
%9 = integer_literal $Builtin.Int64, 1
%10 = integer_literal $Builtin.Int1, 0
%11 = builtin "sadd_with_overflow_Int64"(%8 : $Builtin.Int64, %9 : $Builtin.Int64, %10 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
%12 = tuple_extract %11 : $(Builtin.Int64, Builtin.Int1), 0
br bb3(%12 : $Builtin.Int64)
// CHECK: bb2:
// CHECK: struct_extract %0
bb2:
%14 = load [trivial] %6 : $*Builtin.Int64
%15 = integer_literal $Builtin.Int64, 2
%16 = integer_literal $Builtin.Int1, 0
%17 = builtin "sadd_with_overflow_Int64"(%14 : $Builtin.Int64, %15 : $Builtin.Int64, %16 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
%18 = tuple_extract %17 : $(Builtin.Int64, Builtin.Int1), 0
br bb3(%18 : $Builtin.Int64)
// CHECK-NOT: dealloc_stack
bb3(%20 : $Builtin.Int64):
dealloc_stack %1 : $*Int64
%22 = struct $Int64 (%20 : $Builtin.Int64)
return %22 : $Int64
}
// CHECK-LABEL: } // end sil function 'struct_extract_if_then_else2'
// Test cases where the only use is a debug_value_addr
// CHECK-LABEL: sil [ossa] @no_real_uses2 :
sil [ossa] @no_real_uses2 : $@convention(thin) () -> () {
// CHECK: bb0
bb0:
// CHECK-NOT: alloc_stack
%0 = alloc_stack $Klass
%local = alloc_ref $Klass
store %local to [init] %0 : $*Klass
// CHECK-NOT: debug_value {{.*}} expr op_deref
debug_value %0 : $*Klass, expr op_deref
destroy_addr %0 : $*Klass
// CHECK-NOT: dealloc_stack
dealloc_stack %0 : $*Klass
%1 = tuple ()
return %1 : $()
}
// CHECK-LABEL: } // end sil function 'no_real_uses2'
// CHECK-LABEL: sil [ossa] @half_trivial
// CHECK: %1 = copy_value %0
// CHECK-NEXT: destroy_value %1
// CHECK-NEXT: destroy_value %0
// CHECK-NEXT: tuple
// CHECK-LABEL: } // end sil function 'half_trivial'
sil [ossa] @half_trivial : $@convention(thin) (@owned (Builtin.BridgeObject, Builtin.Int32)) -> () {
bb0(%0 : @owned $(Builtin.BridgeObject, Builtin.Int32)):
%1 = alloc_stack $(Builtin.BridgeObject, Builtin.Int32)
store %0 to [init] %1 : $*(Builtin.BridgeObject, Builtin.Int32)
%3 = load [copy] %1 : $*(Builtin.BridgeObject, Builtin.Int32)
destroy_value %3 : $(Builtin.BridgeObject, Builtin.Int32)
destroy_addr %1 : $*(Builtin.BridgeObject, Builtin.Int32)
dealloc_stack %1 : $*(Builtin.BridgeObject, Builtin.Int32)
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil [ossa] @multiple_debug_value :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'multiple_debug_value'
sil [ossa] @multiple_debug_value : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
debug_value %0 : $Klass
%2 = alloc_stack $Klass
store %0 to [init] %2 : $*Klass
debug_value %2 : $*Klass, expr op_deref
%5 = load [take] %2 : $*Klass
destroy_value %5 : $Klass
dealloc_stack %2 : $*Klass
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil [ossa] @multi_basic_block_bug1 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'multi_basic_block_bug1'
sil [ossa] @multi_basic_block_bug1 : $@convention(thin) (@owned Klass, @owned Klass) -> @owned Klass {
bb0(%0 : @owned $Klass, %1 : @owned $Klass):
%stk1 = alloc_stack $Klass
store %0 to [init] %stk1 : $*Klass
cond_br undef, bb1, bb2
bb1:
%new1 = load [take] %stk1 : $*Klass
destroy_value %1 : $Klass
dealloc_stack %stk1 : $*Klass
br bbret(%new1 : $Klass)
bb2:
store %1 to [assign] %stk1 : $*Klass
%new2 = load [take] %stk1 : $*Klass
dealloc_stack %stk1 : $*Klass
br bbret(%new2 : $Klass)
bbret(%new : @owned $Klass):
return %new : $Klass
}
// CHECK-LABEL: sil [ossa] @multi_basic_block_bug2 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'multi_basic_block_bug2'
sil [ossa] @multi_basic_block_bug2 : $@convention(thin) (@owned Klass, @owned Klass) -> @owned Klass {
bb0(%0 : @owned $Klass, %1 : @owned $Klass):
%stk1 = alloc_stack $Klass
store %0 to [init] %stk1 : $*Klass
cond_br undef, bb1, bb2
bb1:
%new1 = load [take] %stk1 : $*Klass
destroy_value %1 : $Klass
br bbret(%new1 : $Klass)
bb2:
store %1 to [assign] %stk1 : $*Klass
%new2 = load [take] %stk1 : $*Klass
br bbret(%new2 : $Klass)
bbret(%new : @owned $Klass):
dealloc_stack %stk1 : $*Klass
return %new : $Klass
}
sil [ossa] @get_nontrivialstruct : $@convention(thin) () -> @owned NonTrivialStruct
sil [ossa] @get_nontrivialenum : $@convention(thin) () -> @owned NonTrivialEnum
sil [ossa] @get_optionalnontrivialstruct : $@convention(thin) () -> @owned FakeOptional<NonTrivialStruct>
sil [ossa] @take_nontrivialstruct : $@convention(thin) (@owned NonTrivialStruct) -> ()
sil @get : $@convention(thin) () -> @owned FakeOptional<Klass>
sil @use : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
// CHECK-LABEL: sil [ossa] @test_dynamiclifetime1 :
// CHECK: alloc_stack [dynamic_lifetime]
// CHECK-LABEL: } // end sil function 'test_dynamiclifetime1'
sil [ossa] @test_dynamiclifetime1 : $@convention(thin) () -> () {
bb0:
%2 = alloc_stack $Builtin.Int1
%3 = alloc_stack [dynamic_lifetime] $NonTrivialStruct
%4 = integer_literal $Builtin.Int1, 0
store %4 to [trivial] %2 : $*Builtin.Int1
cond_br undef, bb1, bb2
bb1:
br bb3
bb2:
%func = function_ref @get_nontrivialstruct : $@convention(thin) () -> @owned NonTrivialStruct
%val = apply %func() : $@convention(thin) () -> @owned NonTrivialStruct
%27 = integer_literal $Builtin.Int1, -1
store %27 to [trivial] %2 : $*Builtin.Int1
store %val to [init] %3 : $*NonTrivialStruct
br bb3
bb3:
%32 = load [trivial] %2 : $*Builtin.Int1
cond_br %32, bb4, bb5
bb4:
%34 = load [take] %3 : $*NonTrivialStruct
destroy_value %34 : $NonTrivialStruct
br bb6
bb5:
br bb6
bb6:
dealloc_stack %3 : $*NonTrivialStruct
dealloc_stack %2 : $*Builtin.Int1
%res = tuple ()
return %res : $()
}
// CHECK-LABEL: sil [ossa] @test_dynamiclifetime2 :
// CHECK: alloc_stack [dynamic_lifetime]
// CHECK-LABEL: } // end sil function 'test_dynamiclifetime2'
sil [ossa] @test_dynamiclifetime2 : $@convention(thin) () -> () {
bb0:
%2 = alloc_stack $Builtin.Int1
%3 = alloc_stack [dynamic_lifetime] $NonTrivialStruct
%4 = integer_literal $Builtin.Int1, 0
store %4 to [trivial] %2 : $*Builtin.Int1
%func1 = function_ref @get_nontrivialstruct : $@convention(thin) () -> @owned NonTrivialStruct
%val1 = apply %func1() : $@convention(thin) () -> @owned NonTrivialStruct
store %val1 to [init] %3 : $*NonTrivialStruct
%ld1 = load [take] %3 : $*NonTrivialStruct
%func2 = function_ref @take_nontrivialstruct : $@convention(thin) (@owned NonTrivialStruct) -> ()
apply %func2(%ld1) : $@convention(thin) (@owned NonTrivialStruct) -> ()
cond_br undef, bb1, bb2
bb1:
br bb3
bb2:
%val = apply %func1() : $@convention(thin) () -> @owned NonTrivialStruct
%27 = integer_literal $Builtin.Int1, -1
store %27 to [trivial] %2 : $*Builtin.Int1
store %val to [init] %3 : $*NonTrivialStruct
br bb3
bb3:
%32 = load [trivial] %2 : $*Builtin.Int1
cond_br %32, bb4, bb5
bb4:
%ld2 = load [take] %3 : $*NonTrivialStruct
destroy_value %ld2 : $NonTrivialStruct
br bb6
bb5:
br bb6
bb6:
dealloc_stack %3 : $*NonTrivialStruct
dealloc_stack %2 : $*Builtin.Int1
%res = tuple ()
return %res : $()
}
// CHECK-LABEL: sil [ossa] @test_deadphi1 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_deadphi1'
sil [ossa] @test_deadphi1 : $@convention(thin) () -> () {
bb0:
br bb1
bb1:
cond_br undef, bb1a, bb6
bb1a:
br bb2
bb2:
%stk = alloc_stack $NonTrivialStruct
cond_br undef, bb3, bb4
bb3:
%func = function_ref @get_nontrivialstruct : $@convention(thin) () -> @owned NonTrivialStruct
%val = apply %func() : $@convention(thin) () -> @owned NonTrivialStruct
store %val to [init] %stk : $*NonTrivialStruct
%lval1 = load [copy] %stk : $*NonTrivialStruct
destroy_value %lval1 : $NonTrivialStruct
%lval2 = load [take] %stk : $*NonTrivialStruct
destroy_value %lval2 : $NonTrivialStruct
dealloc_stack %stk : $*NonTrivialStruct
cond_br undef, bb3a, bb3b
bb3a:
br bb1
bb3b:
br bb5
bb4:
dealloc_stack %stk : $*NonTrivialStruct
unreachable
bb5:
br bb2
bb6:
%res = tuple ()
return %res : $()
}
// CHECK-LABEL: sil [ossa] @test_deadphi2 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_deadphi2'
sil [ossa] @test_deadphi2 : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $NonTrivialStruct
br bb1
bb1:
cond_br undef, bb2, bb3
bb2:
%3 = function_ref @get_nontrivialstruct : $@convention(thin) () -> @owned NonTrivialStruct
%4 = apply %3() : $@convention(thin) () -> @owned NonTrivialStruct
store %4 to [init] %0 : $*NonTrivialStruct
cond_br undef, bb4, bb5
bb3:
dealloc_stack %0 : $*NonTrivialStruct
br bb7
bb4:
%lval1 = load [take] %0 : $*NonTrivialStruct
destroy_value %lval1 : $NonTrivialStruct
dealloc_stack %0 : $*NonTrivialStruct
br bb7
bb5:
%lval2 = load [take] %0 : $*NonTrivialStruct
destroy_value %lval2 : $NonTrivialStruct
dealloc_stack %0 : $*NonTrivialStruct
br bb7
bb6:
%17 = tuple ()
return %17 : $()
bb7:
br bb6
}
// CHECK-LABEL: sil [ossa] @test_deadphi3 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_deadphi3'
sil [ossa] @test_deadphi3 : $@convention(thin) (@owned NonTrivialEnum) -> () {
bb0(%0 : @owned $NonTrivialEnum):
%1 = alloc_stack $NonTrivialStruct
switch_enum %0 : $NonTrivialEnum, case #NonTrivialEnum.some1!enumelt: bb1, case #NonTrivialEnum.some2!enumelt: bb5
bb1(%3 : @owned $Klass):
destroy_value %3 : $Klass
%5 = function_ref @get_optionalnontrivialstruct : $@convention(thin) () -> @owned FakeOptional<NonTrivialStruct>
%6 = apply %5() : $@convention(thin) () -> @owned FakeOptional<NonTrivialStruct>
switch_enum %6 : $FakeOptional<NonTrivialStruct>, case #FakeOptional.some!enumelt: bb4, case #FakeOptional.none!enumelt: bb2
bb2:
br bb3
bb3:
unreachable
bb4(%10 : @owned $NonTrivialStruct):
store %10 to [init] %1 : $*NonTrivialStruct
br bb9
bb5(%13 : @owned $NonTrivialStruct):
destroy_value %13 : $NonTrivialStruct
%15 = function_ref @get_optionalnontrivialstruct : $@convention(thin) () -> @owned FakeOptional<NonTrivialStruct>
%16 = apply %15() : $@convention(thin) () -> @owned FakeOptional<NonTrivialStruct>
switch_enum %16 : $FakeOptional<NonTrivialStruct>, case #FakeOptional.some!enumelt: bb8, case #FakeOptional.none!enumelt: bb6
bb6:
br bb7
bb7:
unreachable
bb8(%20 : @owned $NonTrivialStruct):
store %20 to [init] %1 : $*NonTrivialStruct
br bb9
bb9:
%23 = function_ref @get_nontrivialenum : $@convention(thin) () -> @owned NonTrivialEnum
%24 = apply %23() : $@convention(thin) () -> @owned NonTrivialEnum
switch_enum %24 : $NonTrivialEnum, case #NonTrivialEnum.some1!enumelt: bb10, case #NonTrivialEnum.some2!enumelt: bb11
bb10(%26 : @owned $Klass):
%27 = load [copy] %1 : $*NonTrivialStruct
destroy_value %27 : $NonTrivialStruct
destroy_value %26 : $Klass
br bb12
bb11(%31 : @owned $NonTrivialStruct):
%32 = load [copy] %1 : $*NonTrivialStruct
destroy_value %32 : $NonTrivialStruct
destroy_value %31 : $NonTrivialStruct
br bb12
bb12:
%36 = load [take] %1 : $*NonTrivialStruct
destroy_value %36 : $NonTrivialStruct
dealloc_stack %1 : $*NonTrivialStruct
%39 = tuple ()
return %39 : $()
}
sil @return_optional_or_error : $@convention(thin) () -> (@owned KlassOptional, @error Error)
// CHECK-LABEL: sil [ossa] @test_deadphi4 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_deadphi4'
sil [ossa] @test_deadphi4 : $@convention(thin) (@owned KlassOptional) -> () {
bb0(%0 : @owned $KlassOptional):
%stk = alloc_stack $KlassOptional
switch_enum %0 : $KlassOptional, case #KlassOptional.some!enumelt: bb2, case #KlassOptional.none!enumelt: bb1
bb1:
dealloc_stack %stk : $*KlassOptional
br bb7
bb2(%some : @owned $Klass):
destroy_value %some : $Klass
%19 = function_ref @return_optional_or_error : $@convention(thin) () -> (@owned KlassOptional, @error Error)
try_apply %19() : $@convention(thin) () -> (@owned KlassOptional, @error Error), normal bb3, error bb8
bb3(%callresult : @owned $KlassOptional):
store %callresult to [init] %stk : $*KlassOptional
%29 = load [take] %stk : $*KlassOptional
switch_enum %29 : $KlassOptional, case #KlassOptional.some!enumelt: bb5, case #KlassOptional.none!enumelt: bb4
bb4:
dealloc_stack %stk : $*KlassOptional
br bb7
bb5(%33 : @owned $Klass):
destroy_value %33 : $Klass
dealloc_stack %stk : $*KlassOptional
br bb6
bb6:
%39 = tuple ()
return %39 : $()
bb7:
br bb6
bb8(%err : @owned $Error):
destroy_value [dead_end] %err
unreachable
}
// CHECK-LABEL: sil [ossa] @test_deadphi5 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_deadphi5'
sil [ossa] @test_deadphi5 : $@convention(thin) () -> () {
bb0:
%stk = alloc_stack $NonTrivialStruct
cond_br undef, bb2, bb1
bb1:
%func1 = function_ref @get_nontrivialstruct : $@convention(thin) () -> @owned NonTrivialStruct
%val1 = apply %func1() : $@convention(thin) () -> @owned NonTrivialStruct
store %val1 to [init] %stk : $*NonTrivialStruct
br bb5
bb2:
%func2 = function_ref @get_nontrivialstruct : $@convention(thin) () -> @owned NonTrivialStruct
%val2 = apply %func2() : $@convention(thin) () -> @owned NonTrivialStruct
store %val2 to [init] %stk : $*NonTrivialStruct
cond_br undef, bb3, bb4
bb3:
br bb5
bb4:
%lval1 = load [take] %stk : $*NonTrivialStruct
destroy_value %lval1 : $NonTrivialStruct
dealloc_stack %stk : $*NonTrivialStruct
br bb9
bb5:
cond_br undef, bb6, bb7
bb6:
%lval2 = load [take] %stk : $*NonTrivialStruct
destroy_value %lval2 : $NonTrivialStruct
br bb8
bb7:
%lval3 = load [take] %stk : $*NonTrivialStruct
destroy_value %lval3 : $NonTrivialStruct
br bb8
bb8:
dealloc_stack %stk : $*NonTrivialStruct
br bb9
bb9:
%res = tuple ()
return %res : $()
}
// Test that a load [take] of an unchecked_addr_cast doesn't get promoted.
//
// CHECK-LABEL: sil [ossa] @load_take_unchecked_addr_cast : {{.*}} {
// CHECK: load [take]
// CHECK-LABEL: } // end sil function 'load_take_unchecked_addr_cast'
sil [ossa] @load_take_unchecked_addr_cast : $@convention(thin) (@guaranteed AnyObject) -> () {
entry(%instance : @guaranteed $AnyObject):
%copy = copy_value %instance : $AnyObject
%storage = alloc_stack $AnyObject
store %copy to [init] %storage : $*AnyObject
%cast_addr = unchecked_addr_cast %storage : $*AnyObject to $*Klass
%value = load [take] %cast_addr : $*Klass
dealloc_stack %storage : $*AnyObject
destroy_value %value : $Klass
%retval = tuple ()
return %retval : $()
}
// Don't bail if the original address is destroyed even if we see a cast.
//
// CHECK-LABEL: sil [ossa] @destroy_original_storage : {{.*}} {
// CHECK: destroy_value
// CHECK-LABEL: } // end sil function 'destroy_original_storage'
sil [ossa] @destroy_original_storage : $@convention(thin) (@guaranteed AnyObject) -> () {
entry(%instance : @guaranteed $AnyObject):
%copy = copy_value %instance : $AnyObject
%storage = alloc_stack $AnyObject
store %copy to [init] %storage : $*AnyObject
%cast_addr = unchecked_addr_cast %storage : $*AnyObject to $*Klass
%value = load [copy] %cast_addr : $*Klass
destroy_addr %storage : $*AnyObject
dealloc_stack %storage : $*AnyObject
destroy_value %value : $Klass
%retval = tuple ()
return %retval : $()
}
// Bail if the address produced by an unchecked_addr_cast is destroyed.
//
// CHECK-LABEL: sil [ossa] @destroy_addr_unchecked_addr_cast : {{.*}} {
// CHECK: unchecked_addr_cast
// CHECK: load [copy]
// CHECK-LABEL: } // end sil function 'destroy_addr_unchecked_addr_cast'
sil [ossa] @destroy_addr_unchecked_addr_cast : $@convention(thin) (@guaranteed AnyObject) -> () {
entry(%instance : @guaranteed $AnyObject):
%copy = copy_value %instance : $AnyObject
%storage = alloc_stack $AnyObject
store %copy to [init] %storage : $*AnyObject
%cast_addr = unchecked_addr_cast %storage : $*AnyObject to $*Klass
%value = load [copy] %cast_addr : $*Klass
destroy_addr %cast_addr : $*Klass
dealloc_stack %storage : $*AnyObject
destroy_value %value : $Klass
%retval = tuple ()
return %retval : $()
}
// Bail if there's a load [take] of one of multiple non-trivial fields.
//
// CHECK-LABEL: sil [ossa] @load_take_one_of_two_nontrivial_struct_fields : {{.*}} {
// CHECK: load [take]
// CHECK: destroy_addr
// CHECK-LABEL: } // end sil function 'load_take_one_of_two_nontrivial_struct_fields'
sil [ossa] @load_take_one_of_two_nontrivial_struct_fields : $@convention(thin) (@guaranteed Sy) -> () {
entry(%instance : @guaranteed $Sy):
%copy = copy_value %instance : $Sy
%storage = alloc_stack $Sy
store %copy to [init] %storage : $*Sy
%v1_addr = struct_element_addr %storage : $*Sy, #Sy.v1
%cast_addr = unchecked_addr_cast %v1_addr : $*AnyObject to $*Klass
%value = load [take] %cast_addr : $*Klass
%v2_addr = struct_element_addr %storage : $*Sy, #Sy.v2
destroy_addr %v2_addr : $*AnyObject
dealloc_stack %storage : $*Sy
destroy_value %value : $Klass
%retval = tuple ()
return %retval : $()
}
// CHECK-LABEL: sil [ossa] @load_take_original_despite_cast : {{.*}} {
// CHECK: alloc_stack
// CHECK-LABEL: } // end sil function 'load_take_original_despite_cast'
sil [ossa] @load_take_original_despite_cast : $@convention(thin) (@owned AnyObject) -> () {
entry(%instance : @owned $AnyObject):
%74 = alloc_stack $AnyObject
store %instance to [init] %74 : $*AnyObject
%76 = unchecked_addr_cast %74 : $*AnyObject to $*UInt8
%77 = load [trivial] %76 : $*UInt8
%79 = load [take] %74 : $*AnyObject
destroy_value %79 : $AnyObject
dealloc_stack %74 : $*AnyObject
%82 = tuple ()
return %82 : $()
}
// CHECK-LABEL: sil [ossa] @test_enum_store_borrow_none :
// CHECK: alloc_stack
// CHECK: alloc_stack
// CHECK: dealloc_stack
// CHECK-LABEL: } // end sil function 'test_enum_store_borrow_none'
sil [ossa] @test_enum_store_borrow_none : $@convention(thin) () -> () {
bb0:
%1 = alloc_stack [lexical] $FakeOptional<Klass>
%none = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
%2 = store_borrow %none to %1 : $*FakeOptional<Klass>
%3 = alloc_stack $FakeOptional<Klass>
%4 = load [copy] %2 : $*FakeOptional<Klass>
store %4 to [init] %3 : $*FakeOptional<Klass>
switch_enum_addr %3 : $*FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb1:
%7 = unchecked_inplace_enum_data_addr %3 : $*FakeOptional<Klass>, #FakeOptional.some!enumelt
%8 = load [take] %7 : $*Klass
destroy_value %8 : $Klass
dealloc_stack %3 : $*FakeOptional<Klass>
br bb3
bb2:
dealloc_stack %3 : $*FakeOptional<Klass>
br bb3
bb3:
end_borrow %2 : $*FakeOptional<Klass>
dealloc_stack %1 : $*FakeOptional<Klass>
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_enum_store_none :
// CHECK: alloc_stack
// CHECK-NOT: alloc_stack
// CHECK: dealloc_stack
// CHECK-LABEL: } // end sil function 'test_enum_store_none'
sil [ossa] @test_enum_store_none : $@convention(thin) () -> () {
bb0:
%1 = alloc_stack [lexical] $FakeOptional<Klass>
%none = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
store %none to [init] %1 : $*FakeOptional<Klass>
%3 = alloc_stack $FakeOptional<Klass>
%4 = load [copy] %1 : $*FakeOptional<Klass>
store %4 to [init] %3 : $*FakeOptional<Klass>
switch_enum_addr %3 : $*FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb1:
%7 = unchecked_inplace_enum_data_addr %3 : $*FakeOptional<Klass>, #FakeOptional.some!enumelt
%8 = load [take] %7 : $*Klass
destroy_value %8 : $Klass
dealloc_stack %3 : $*FakeOptional<Klass>
br bb3
bb2:
dealloc_stack %3 : $*FakeOptional<Klass>
br bb3
bb3:
destroy_addr %1 : $*FakeOptional<Klass>
dealloc_stack %1 : $*FakeOptional<Klass>
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_storeborrow_trivial_none_to_lexical_storeborrow_only : $@convention(thin) () -> () {
// CHECK: alloc_stack
// CHECK-LABEL: } // end sil function 'test_storeborrow_trivial_none_to_lexical_storeborrow_only'
sil [ossa] @test_storeborrow_trivial_none_to_lexical_storeborrow_only : $@convention(thin) () -> () {
bb0:
%1 = alloc_stack [lexical] $FakeOptional<Klass>
%none = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
%sbi = store_borrow %none to %1 : $*FakeOptional<Klass>
end_borrow %sbi : $*FakeOptional<Klass>
dealloc_stack %1 : $*FakeOptional<Klass>
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_storeborrow_trivial_none_to_lexical_optional1 : $@convention(thin) () -> () {
// CHECK: alloc_stack
// CHECK-LABEL: } // end sil function 'test_storeborrow_trivial_none_to_lexical_optional1'
sil [ossa] @test_storeborrow_trivial_none_to_lexical_optional1 : $@convention(thin) () -> () {
bb0:
%1 = alloc_stack [lexical] $FakeOptional<Klass>
%none = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
%sbi = store_borrow %none to %1 : $*FakeOptional<Klass>
%ld = load [copy] %sbi : $*FakeOptional<Klass>
apply undef(%ld) : $@convention(thin) (@owned FakeOptional<Klass>) -> ()
end_borrow %sbi : $*FakeOptional<Klass>
dealloc_stack %1 : $*FakeOptional<Klass>
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_storeborrow_trivial_none_to_lexical_optional2 : $@convention(thin) () -> () {
// CHECK: alloc_stack
// CHECK-LABEL: } // end sil function 'test_storeborrow_trivial_none_to_lexical_optional2'
sil [ossa] @test_storeborrow_trivial_none_to_lexical_optional2 : $@convention(thin) () -> () {
bb0:
%1 = alloc_stack [lexical] $FakeOptional<Klass>
%none = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
%sbi = store_borrow %none to %1 : $*FakeOptional<Klass>
%ld = load [copy] %sbi : $*FakeOptional<Klass>
apply undef(%ld) : $@convention(thin) (@owned FakeOptional<Klass>) -> ()
br bb1
bb1:
end_borrow %sbi : $*FakeOptional<Klass>
dealloc_stack %1 : $*FakeOptional<Klass>
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_store_trivial_none_to_lexical_storeonly : $@convention(thin) () -> () {
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_store_trivial_none_to_lexical_storeonly'
sil [ossa] @test_store_trivial_none_to_lexical_storeonly : $@convention(thin) () -> () {
bb0:
%1 = alloc_stack [lexical] $FakeOptional<Klass>
%none = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
store %none to [trivial] %1 : $*FakeOptional<Klass>
dealloc_stack %1 : $*FakeOptional<Klass>
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_store_trivial_none_to_lexical_optional1 : $@convention(thin) () -> () {
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_store_trivial_none_to_lexical_optional1'
sil [ossa] @test_store_trivial_none_to_lexical_optional1 : $@convention(thin) () -> () {
bb0:
%1 = alloc_stack [lexical] $FakeOptional<Klass>
%none = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
store %none to [trivial] %1 : $*FakeOptional<Klass>
%ld = load [take] %1 : $*FakeOptional<Klass>
apply undef(%ld) : $@convention(thin) (@owned FakeOptional<Klass>) -> ()
dealloc_stack %1 : $*FakeOptional<Klass>
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_store_trivial_none_to_lexical_optional2 : $@convention(thin) () -> () {
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_store_trivial_none_to_lexical_optional2'
sil [ossa] @test_store_trivial_none_to_lexical_optional2 : $@convention(thin) () -> () {
bb0:
%1 = alloc_stack [lexical] $FakeOptional<Klass>
%none = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
store %none to [trivial] %1 : $*FakeOptional<Klass>
br bb1
bb1:
%ld = load [take] %1 : $*FakeOptional<Klass>
apply undef(%ld) : $@convention(thin) (@owned FakeOptional<Klass>) -> ()
dealloc_stack %1 : $*FakeOptional<Klass>
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_store_trivial_none_to_lexical_optional3 : $@convention(thin) () -> () {
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_store_trivial_none_to_lexical_optional3'
sil [ossa] @test_store_trivial_none_to_lexical_optional3 : $@convention(thin) () -> () {
bb0:
%1 = alloc_stack [lexical] $FakeOptional<Klass>
%none = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
store %none to [init] %1 : $*FakeOptional<Klass>
%ld = load [take] %1 : $*FakeOptional<Klass>
apply undef(%ld) : $@convention(thin) (@owned FakeOptional<Klass>) -> ()
dealloc_stack %1 : $*FakeOptional<Klass>
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_store_trivial_none_to_lexical_optional4 : {{.*}} {
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_store_trivial_none_to_lexical_optional4'
sil [ossa] @test_store_trivial_none_to_lexical_optional4 : $@convention(thin) () -> () {
bb0:
%1 = alloc_stack [lexical] $FakeOptional<Klass>
%none1 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
store %none1 to [init] %1 : $*FakeOptional<Klass>
%none2 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
store %none2 to [assign] %1 : $*FakeOptional<Klass>
%ld = load [take] %1 : $*FakeOptional<Klass>
apply undef(%ld) : $@convention(thin) (@owned FakeOptional<Klass>) -> ()
dealloc_stack %1 : $*FakeOptional<Klass>
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_store_trivial_none_to_lexical_optional5 : {{.*}} {
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_store_trivial_none_to_lexical_optional5'
sil [ossa] @test_store_trivial_none_to_lexical_optional5 : $@convention(thin) () -> () {
bb0:
%1 = alloc_stack [lexical] $FakeOptional<Klass>
%none = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
store %none to [init] %1 : $*FakeOptional<Klass>
store %none to [assign] %1 : $*FakeOptional<Klass>
%ld = load [take] %1 : $*FakeOptional<Klass>
apply undef(%ld) : $@convention(thin) (@owned FakeOptional<Klass>) -> ()
dealloc_stack %1 : $*FakeOptional<Klass>
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_store_trivial_none_to_lexical_optional6 : {{.*}} {
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_store_trivial_none_to_lexical_optional6'
sil [ossa] @test_store_trivial_none_to_lexical_optional6 : $@convention(thin) () -> () {
bb0:
%1 = alloc_stack [lexical] $FakeOptional<Klass>
%none = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
store %none to [init] %1 : $*FakeOptional<Klass>
destroy_addr %1 : $*FakeOptional<Klass>
store %none to [init] %1 : $*FakeOptional<Klass>
%ld = load [take] %1 : $*FakeOptional<Klass>
apply undef(%ld) : $@convention(thin) (@owned FakeOptional<Klass>) -> ()
dealloc_stack %1 : $*FakeOptional<Klass>
%t = tuple ()
return %t : $()
}
// CHECK-LABEL: sil [ossa] @test_store_trivial_none_to_lexical_optional7 : {{.*}} {
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_store_trivial_none_to_lexical_optional7'
sil [ossa] @test_store_trivial_none_to_lexical_optional7 : $@convention(thin) () -> () {
bb0:
%1 = alloc_stack [lexical] $FakeOptional<Klass>
%none = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br bb1
bb1:
store %none to [init] %1 : $*FakeOptional<Klass>
destroy_addr %1 : $*FakeOptional<Klass>
store %none to [init] %1 : $*FakeOptional<Klass>
%ld = load [take] %1 : $*FakeOptional<Klass>
apply undef(%ld) : $@convention(thin) (@owned FakeOptional<Klass>) -> ()
dealloc_stack %1 : $*FakeOptional<Klass>
%t = tuple ()
return %t : $()
}
sil [ossa] @test_store_trivial_none_to_lexical_optional8 : $@convention(thin) () -> () {
bb0:
%1 = alloc_stack [lexical] $FakeOptional<Klass>
%none = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br bb1
bb1:
store %none to [init] %1 : $*FakeOptional<Klass>
%ld = load [take] %1 : $*FakeOptional<Klass>
apply undef(%ld) : $@convention(thin) (@owned FakeOptional<Klass>) -> ()
dealloc_stack %1 : $*FakeOptional<Klass>
%t = tuple ()
return %t : $()
}
// Ensure no verification failure
sil [ossa] @test_store_enum_value_in_multiple_locs1 : $@convention(thin) () -> () {
bb0:
%0 = function_ref @get : $@convention(thin) () -> @owned FakeOptional<Klass>
%1 = apply %0() : $@convention(thin) () -> @owned FakeOptional<Klass>
%2 = begin_borrow [lexical] %1
cond_br undef, bb2, bb1
bb1:
br bb3
bb2:
%5 = alloc_stack [lexical] $FakeOptional<Klass>
%6 = store_borrow %2 to %5
cond_br undef, bb8, bb9
bb3:
cond_br undef, bb5, bb4
bb4:
end_borrow %2
destroy_value [dead_end] %1
unreachable
bb5:
%11 = alloc_stack $FakeOptional<Klass>
%12 = store_borrow %2 to %11
%14 = load_borrow %12
%15 = begin_borrow [lexical] %14
%16 = alloc_stack $FakeOptional<Klass>
%17 = store_borrow %15 to %16
cond_br undef, bb6, bb7
bb6:
fix_lifetime %17
end_borrow %17
dealloc_stack %16
end_borrow %15
end_borrow %14
end_borrow %12
dealloc_stack %11
end_borrow %2
destroy_value %1
%29 = tuple ()
return %29
bb7:
end_borrow %17
dealloc_stack %16
end_borrow %15
end_borrow %14
end_borrow %12
end_borrow %2
destroy_value [dead_end] %1
unreachable
bb8:
end_borrow %6
dealloc_stack %5
end_borrow %2
destroy_value [dead_end] %1
unreachable
bb9:
end_borrow %6
dealloc_stack %5
br bb3
}
// CHECK-LABEL: sil [ossa] @test_end_lifetime_of_trivial_enum_case :
// CHECK-NOT: alloc_stack
// CHECK: bb2(%{{[0-9]+}} : $Int):
// CHECK: fix_lifetime
// CHECK: end_borrow
// CHECK: end_lifetime %1
// CHECK: bb3:
// CHECK-LABEL: } // end sil function 'test_end_lifetime_of_trivial_enum_case'
sil [ossa] @test_end_lifetime_of_trivial_enum_case : $@convention(thin) (@inout C, @owned Result<C, Int>) -> () {
bb0(%0 : $*C, %1 : @owned $Result<C, Int>):
%2 = alloc_stack $Result<C, Int>
store %1 to [init] %2
%3 = load_borrow %2
switch_enum %3, case #Result.success!enumelt: bb1, case #Result.failure!enumelt: bb2
bb1(%10 : @guaranteed $C):
end_borrow %3
%12 = load [take] %2
%13 = unchecked_enum_data %12 : $Result<C, Int>, #Result.success!enumelt
store %13 to [assign] %0
br bb3
bb2(%20 : $Int):
end_borrow %3
%22 = load_borrow %2
%23 = unchecked_enum_data %22, #Result.failure!enumelt
fix_lifetime %23
end_borrow %22
br bb3
bb3:
dealloc_stack %2
%r = tuple ()
return %r
}
// CHECK-LABEL: sil [ossa] @end_lifetime_at_trivial_case_dealloc_stack : {{.*}} {
// CHECK-NOT: alloc_stack
// CHECK: [[IN:%[^,]+]] = load [copy]
// CHECK: [[IN_BORROW:%[^,]+]] = begin_borrow [[IN]]
// CHECK: switch_enum [[IN_BORROW]], case #Result.success!enumelt: bb1
// CHECK: bb1({{%[^,]+}} : $Int):
// CHECK: end_borrow [[IN_BORROW]]
// CHECK: [[C:%.*]] = copy_value [[IN]]
// CHECK: end_lifetime [[C]]
// CHECK: bb4:
// CHECK-NEXT: destroy_value [[IN]]
// CHECK-LABEL: } // end sil function 'end_lifetime_at_trivial_case_dealloc_stack'
sil [ossa] @end_lifetime_at_trivial_case_dealloc_stack : $@convention(thin) (@in_guaranteed Result<Int, C>) -> () {
entry(%in_addr : $*Result<Int, C>):
%main_addr = alloc_stack $Result<Int, C>
%in = load [copy] %in_addr
store %in to [init] %main_addr
%in_borrow = load_borrow %main_addr
switch_enum %in_borrow,
case #Result.success!enumelt: int,
case #Result.failure!enumelt: full
int(%6 : $Int):
end_borrow %in_borrow
%temp = alloc_stack $Result<Int, C>
%in_copy = load [copy] %main_addr
store %in_copy to [init] %temp
br int2
int2:
dealloc_stack %temp
br exit
full(%13 : @guaranteed $C):
end_borrow %in_borrow
br exit
exit:
destroy_addr %main_addr
dealloc_stack %main_addr
%18 = tuple ()
return %18
}
// CHECK-LABEL: sil [ossa] @end_lifetime_at_trivial_case_dealloc_stack_2 : {{.*}} {
// CHECK: bb0([[IN_ADDR:%[^,]+]] :
// CHECK: [[IN_COPY:%[^,]+]] = load [copy] [[IN_ADDR]]
// CHECK: [[IN_BORROW:%[^,]+]] = begin_borrow [[IN_COPY]]
// CHECK: switch_enum [[IN_BORROW]], case #Result.success!enumelt: bb1
// CHECK: bb1({{%[^,]+}} : $Int):
// CHECK: end_borrow [[IN_BORROW]]
// CHECK: [[C:%.*]] = copy_value [[IN_COPY]]
// CHECK: end_lifetime [[C]]
// CHECK-LABEL: } // end sil function 'end_lifetime_at_trivial_case_dealloc_stack_2'
sil [ossa] @end_lifetime_at_trivial_case_dealloc_stack_2 : $@convention(thin) (@in_guaranteed Result<Int, C>) -> () {
entry(%in_addr : $*Result<Int, C>):
%main_addr = alloc_stack $Result<Int, C>
%temp = alloc_stack $Result<Int, C>
%in = load [copy] %in_addr
store %in to [init] %main_addr
%in_borrow = load_borrow %main_addr
switch_enum %in_borrow,
case #Result.success!enumelt: int,
case #Result.failure!enumelt: x
int(%int : $Int):
end_borrow %in_borrow
%in_copy = load [copy] %main_addr
store %in_copy to [init] %temp
br int2
int2:
br exit
x(%13 : @guaranteed $C):
end_borrow %in_borrow
br exit
exit:
destroy_addr %main_addr
dealloc_stack %temp
dealloc_stack %main_addr
%retval = tuple ()
return %retval
}
// CHECK-LABEL: sil [ossa] @end_lifetime_at_trivial_case_dealloc_stack_3 : {{.*}} {
// CHECK: bb0([[IN_ADDR:%[^,]+]] :
// CHECK: [[IN_BORROW:%[^,]+]] = load_borrow [[IN_ADDR]]
// CHECK: switch_enum [[IN_BORROW]]
// CHECK: case #Result.success!enumelt: [[INT:bb[0-9]+]]
// CHECK: [[INT]]
// CHECK: end_borrow [[IN_BORROW]]
// CHECK: [[IN_COPY:%[^,]+]] = load [copy] [[IN_ADDR]]
// CHECK: end_lifetime [[IN_COPY]]
// CHECK-LABEL: } // end sil function 'end_lifetime_at_trivial_case_dealloc_stack_3'
sil [ossa] @end_lifetime_at_trivial_case_dealloc_stack_3 : $@convention(thin) (@in_guaranteed Result<Int, C>) -> () {
entry(%in_addr : $*Result<Int, C>):
%in_borrow = load_borrow %in_addr
switch_enum %in_borrow,
case #Result.success!enumelt: int,
case #Result.failure!enumelt: x
int(%int : $Int):
end_borrow %in_borrow
%temp = alloc_stack $Result<Int, C>
%in_copy = load [copy] %in_addr
store %in_copy to [init] %temp
dealloc_stack %temp
br int2
int2:
br exit
x(%13 : @guaranteed $C):
end_borrow %in_borrow
br exit
exit:
%retval = tuple ()
return %retval
}
// CHECK-LABEL: sil [ossa] @fd_deinit :
// CHECK-NOT: drop_deinit
// CHECK: end_lifetime %0
// CHECK-NOT: drop_deinit
// CHECK-LABEL: } // end sil function 'fd_deinit'
sil [ossa] @fd_deinit : $@convention(method) (@owned FileDescriptor) -> () {
bb0(%0 : @owned $FileDescriptor):
%1 = alloc_stack $FileDescriptor, let, name "self", argno 1
store %0 to [init] %1
%3 = drop_deinit %1
%4 = tuple ()
dealloc_stack %1
%6 = tuple ()
return %6
}
sil [ossa] @get_owned : $@convention(thin) () -> @owned Klass
sil [ossa] @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
// CHECK-LABEL: sil [ossa] @test_no_storeborrow1 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_no_storeborrow1'
sil [ossa] @test_no_storeborrow1 : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
%stk = alloc_stack $Klass
store %0 to [init] %stk : $*Klass
%ld = load_borrow %stk : $*Klass
%3 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
%4 = apply %3(%ld) : $@convention(thin) (@guaranteed Klass) -> ()
end_borrow %ld : $Klass
destroy_addr %stk : $*Klass
dealloc_stack %stk : $*Klass
%6 = tuple ()
return %6 : $()
}
// CHECK-LABEL: sil [ossa] @test_no_storeborrow2 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_no_storeborrow2'
sil [ossa] @test_no_storeborrow2 : $@convention(method) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
%stk = alloc_stack $Klass
store %0 to [init] %stk : $*Klass
%ld1 = load_borrow %stk : $*Klass
%f = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
apply %f(%ld1) : $@convention(thin) (@guaranteed Klass) -> ()
end_borrow %ld1 : $Klass
cond_br undef, bb3, bb1
bb1:
%ld2 = load_borrow %stk : $*Klass
apply %f(%ld2) : $@convention(thin) (@guaranteed Klass) -> ()
end_borrow %ld2 : $Klass
%tk1 = load [take] %stk : $*Klass
destroy_value %tk1 : $Klass
dealloc_stack %stk : $*Klass
br bb4
bb3:
%tk2 = load [take] %stk : $*Klass
destroy_value %tk2 : $Klass
dealloc_stack %stk : $*Klass
br bb4
bb4:
%ret = tuple ()
return %ret : $()
}
// CHECK-LABEL: sil [ossa] @test_no_storeborrow3 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_no_storeborrow3'
sil [ossa] @test_no_storeborrow3 : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
%1 = alloc_stack $Klass
store %0 to [init] %1 : $*Klass
%2 = load_borrow %1 : $*Klass
%3 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
%4 = apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> ()
end_borrow %2 : $Klass
destroy_addr %1 : $*Klass
dealloc_stack %1 : $*Klass
%6 = tuple ()
return %6 : $()
}
// CHECK-LABEL: sil [ossa] @test_control_flow2 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_control_flow2'
sil [ossa] @test_control_flow2 : $@convention(thin) (@guaranteed Klass, @guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass, %1 : @guaranteed $Klass):
%stk = alloc_stack $Klass
cond_br undef, bb1, bb2
bb1:
%copy1 = copy_value %0 : $Klass
store %copy1 to [init] %stk : $*Klass
br bb3
bb2:
%copy2 = copy_value %1 : $Klass
store %copy2 to [init] %stk : $*Klass
br bb3
bb3:
%2 = load_borrow %stk : $*Klass
%3 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
%4 = apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> ()
end_borrow %2 : $Klass
destroy_addr %stk : $*Klass
dealloc_stack %stk : $*Klass
%8 = tuple ()
return %8 : $()
}
// CHECK-LABEL: sil [ossa] @test_control_flow3 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_control_flow3'
sil [ossa] @test_control_flow3 : $@convention(thin) () -> () {
bb0:
%4 = alloc_stack [lexical] $Klass
%f = function_ref @get_owned : $@convention(thin) () -> @owned Klass
%5 = apply %f() : $@convention(thin) () -> @owned Klass
store %5 to [init] %4 : $*Klass
%7 = load_borrow %4 : $*Klass
end_borrow %7 : $Klass
cond_br undef, bb1, bb2
bb1:
br bb3
bb2:
%28 = load_borrow %4 : $*Klass
end_borrow %28 : $Klass
br bb3
bb3:
destroy_addr %4 : $*Klass
dealloc_stack %4 : $*Klass
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @test_control_flow4 :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'test_control_flow4'
sil [ossa] @test_control_flow4 : $@convention(thin) (@guaranteed Klass, @guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass, %1 : @guaranteed $Klass):
%stk = alloc_stack [lexical] $Klass
cond_br undef, bb1, bb2
bb1:
%copy1 = copy_value %0 : $Klass
store %copy1 to [init] %stk : $*Klass
br bb3
bb2:
%copy2 = copy_value %1 : $Klass
store %copy2 to [init] %stk : $*Klass
br bb3
bb3:
%2 = load_borrow %stk : $*Klass
%3 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
%4 = apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> ()
end_borrow %2 : $Klass
destroy_addr %stk : $*Klass
dealloc_stack %stk : $*Klass
%8 = tuple ()
return %8 : $()
}
// CHECK-LABEL: sil [ossa] @test_load_borrow_with_reborrow :
// CHECK: alloc_stack
// CHECK-LABEL: } // end sil function 'test_load_borrow_with_reborrow'
sil [ossa] @test_load_borrow_with_reborrow : $@convention(thin) () -> () {
bb0:
%owned = apply undef() : $@convention(thin) () -> (@owned Klass)
%stack = alloc_stack [lexical] $Klass
store %owned to [init] %stack : $*Klass
br bb1
bb1:
%ld = load [take] %stack : $*Klass
destroy_value %ld
%owned_other = apply undef() : $@convention(thin) () -> (@owned Klass)
store %owned_other to [init] %stack : $*Klass
%lb = load_borrow %stack
br bb2(%lb)
bb2(%reborrow : @reborrow $Klass):
%bf = borrowed %reborrow from ()
end_borrow %bf : $Klass
destroy_addr %stack : $*Klass
dealloc_stack %stack : $*Klass
%retval = tuple ()
return %retval : $()
}
sil [ossa] @getC : $@convention(thin) () -> @owned C
sil [ossa] @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
sil [ossa] @callee_owned : $@convention(thin) (@owned C) -> ()
sil [ossa] @callee_error_owned : $@convention(thin) (@owned C) -> @error Error
sil [ossa] @callee_void_to_void : $@convention(thin) () -> ()
// basic_N {{ functions consisting of a single block
// An owned instance of C is passed in, stored to the stack, used
// non-consumingly once, and destroyed.
//
// CHECK-LABEL: sil [ossa] @basic_1 : $@convention(thin) (@owned C) -> () {
// CHECK: bb0([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: [[CALLEE:%[^,]+]] = function_ref @callee_guaranteed
// CHECK: [[RETVAL:%[^,]+]] = apply [[CALLEE]]([[INSTANCE]])
// CHECK: destroy_value [[INSTANCE]]
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'basic_1'
sil [ossa] @basic_1 : $(@owned C) -> () {
entry(%instance : @owned $C):
%scope = alloc_stack [lexical] $C
store %instance to [init] %scope : $*C
%thing = load [take] %scope : $*C
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
%res = apply %callee_guaranteed(%thing) : $@convention(thin) (@guaranteed C) -> ()
destroy_value %thing : $C
dealloc_stack %scope : $*C
return %res : $()
}
// A guaranteed instance of C is passed in, copied, stored to the stack, used
// non-consumingly once, and deallocated.
//
// CHECK-LABEL: sil [ossa] @basic_3 : $@convention(thin) (@guaranteed C) -> () {
// CHECK: bb0([[INSTANCE_GUARANTEED:%[^,]+]] : @guaranteed $C):
// CHECK: [[INSTANCE:%[^,]+]] = copy_value [[INSTANCE_GUARANTEED]]
// CHECK: [[CALLEE:%[^,]+]] = function_ref @callee_guaranteed
// CHECK: [[RETVAL:%[^,]+]] = apply [[CALLEE]]([[INSTANCE]])
// CHECK: destroy_value [[INSTANCE]]
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'basic_3'
sil [ossa] @basic_3 : $(@guaranteed C) -> () {
entry(%instance_guaranteed : @guaranteed $C):
%scope = alloc_stack [lexical] $C
%instance = copy_value %instance_guaranteed : $C
store %instance to [init] %scope : $*C
%thing = load [take] %scope : $*C
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
%res = apply %callee_guaranteed(%thing) : $@convention(thin) (@guaranteed C) -> ()
destroy_value %thing : $C
dealloc_stack %scope : $*C
return %res : $()
}
// An owned instance of C is passed in, stored to the stack, and used
// consumingly.
//
// CHECK-LABEL: sil [ossa] @basic_4 : $@convention(thin) (@owned C) -> () {
// CHECK: bb0([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: [[CALLEE:%[^,]+]] = function_ref @callee_owned
// CHECK: [[RETVAL:%[^,]+]] = apply [[CALLEE]]([[INSTANCE]])
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'basic_4'
sil [ossa] @basic_4 : $(@owned C) -> () {
entry(%instance : @owned $C):
%scope = alloc_stack [lexical] $C
store %instance to [init] %scope : $*C
%thing = load [take] %scope : $*C
%callee = function_ref @callee_owned : $@convention(thin) (@owned C) -> ()
%res = apply %callee(%thing) : $@convention(thin) (@owned C) -> ()
dealloc_stack %scope : $*C
return %res : $()
}
// CHECK-LABEL: sil [ossa] @basic_5 : $@convention(thin) (@owned C, @owned C) -> () {
// CHECK: {{bb[^,]+}}([[INSTANCE_1:%[^,]+]] : @owned $C, [[INSTANCE_2:%[^,]+]] : @owned $C):
// CHECK: destroy_value [[INSTANCE_1]]
// CHECK: destroy_value [[INSTANCE_2]]
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'basic_5'
sil [ossa] @basic_5 : $@convention(thin) (@owned C, @owned C) -> () {
entry(%instance_1 : @owned $C, %instance_2 : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance_1 to [init] %addr : $*C
store %instance_2 to [assign] %addr : $*C
destroy_addr %addr : $*C
dealloc_stack %addr : $*C
%retval = tuple ()
return %retval : $()
}
// CHECK-LABEL: sil [ossa] @basic_6 : $@convention(thin) (@owned C, @owned C) -> () {
// CHECK: {{bb[^,]+}}([[INSTANCE_1:%[^,]+]] : @owned $C, [[INSTANCE_2:%[^,]+]] : @owned $C):
// CHECK: br [[WORK:bb[0-9]+]]
// CHECK: [[WORK]]:
// CHECK: destroy_value [[INSTANCE_1]]
// CHECK: destroy_value [[INSTANCE_2]]
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[EXIT]]:
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'basic_6'
sil [ossa] @basic_6 : $@convention(thin) (@owned C, @owned C) -> () {
entry(%instance_1 : @owned $C, %instance_2 : @owned $C):
%addr = alloc_stack [lexical] $C
br work
work:
store %instance_1 to [init] %addr : $*C
store %instance_2 to [assign] %addr : $*C
destroy_addr %addr : $*C
dealloc_stack %addr : $*C
br exit
exit:
%retval = tuple ()
return %retval : $()
}
// CHECK-LABEL: sil [ossa] @basic_7 : $@convention(thin) (@owned C, @owned C) -> () {
// CHECK: {{bb[^,]+}}([[INSTANCE_1:%[^,]+]] : @owned $C, [[INSTANCE_2:%[^,]+]] : @owned $C):
// CHECK: br [[WORK:bb[0-9]+]]
// CHECK: [[WORK]]:
// CHECK: destroy_value [[INSTANCE_1]]
// CHECK: destroy_value [[INSTANCE_2]]
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[EXIT]]:
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'basic_7'
sil [ossa] @basic_7 : $@convention(thin) (@owned C, @owned C) -> () {
entry(%instance_1 : @owned $C, %instance_2 : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance_1 to [init] %addr : $*C
br work
work:
store %instance_2 to [assign] %addr : $*C
destroy_addr %addr : $*C
dealloc_stack %addr : $*C
br exit
exit:
%retval = tuple ()
return %retval : $()
}
// basic_N }}
// after_N {{ uses of the loaded value after dealloc_stack
// CHECK-LABEL: sil [ossa] @after_1 : $@convention(thin) (@owned C) -> @owned C {
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: [[CALLEE_VOID_TO_VOID:%[^,]+]] = function_ref @callee_void_to_void
// CHECK: apply [[CALLEE_VOID_TO_VOID]]
// CHECK: return [[INSTANCE]]
// CHECK-LABEL: } // end sil function 'after_1'
sil [ossa] @after_1 : $@convention(thin) (@owned C) -> @owned C {
bb0(%instance : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance to [init] %addr : $*C
%instance_loaded = load [take] %addr : $*C
dealloc_stack %addr : $*C
%callee_void_to_void = function_ref @callee_void_to_void : $@convention(thin) () -> ()
%ok = apply %callee_void_to_void() : $@convention(thin) () -> ()
return %instance_loaded : $C
}
// CHECK-LABEL: sil [ossa] @after_2 : $@convention(thin) (@owned C, @owned C) -> @owned C {
// CHECK: {{bb[^,]+}}([[INSTANCE_1:%[^,]+]] : @owned $C, [[INSTANCE_2:%[^,]+]] : @owned $C):
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
// CHECK: apply [[CALLEE_GUARANTEED]]([[INSTANCE_2]])
// CHECK: destroy_value [[INSTANCE_2]]
// CHECK: return [[INSTANCE_1]]
// CHECK-LABEL: } // end sil function 'after_2'
sil [ossa] @after_2 : $@convention(thin) (@owned C, @owned C) -> @owned C {
bb0(%instance_1 : @owned $C, %instance_2 : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance_1 to [init] %addr : $*C
%instance_1_loaded = load [take] %addr : $*C
store %instance_2 to [init] %addr : $*C
%instance_2_loaded = load [take] %addr : $*C
dealloc_stack %addr : $*C
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
%ok2 = apply %callee_guaranteed(%instance_2_loaded) : $@convention(thin) (@guaranteed C) -> ()
destroy_value %instance_2_loaded : $C
return %instance_1_loaded : $C
}
// CHECK-LABEL: sil [ossa] @after_3 : $@convention(thin) (@owned C) -> @owned C {
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[EXIT]]:
// CHECK: [[CALLEE_VOID_TO_VOID:%[^,]+]] = function_ref @callee_void_to_void
// CHECK: apply [[CALLEE_VOID_TO_VOID]]()
// CHECK: return [[INSTANCE]]
// CHECK-LABEL: } // end sil function 'after_3'
sil [ossa] @after_3 : $@convention(thin) (@owned C) -> @owned C {
bb0(%instance : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance to [init] %addr : $*C
%instance_loaded = load [take] %addr : $*C
br exit
exit:
dealloc_stack %addr : $*C
%callee_void_to_void = function_ref @callee_void_to_void : $@convention(thin) () -> ()
%ok = apply %callee_void_to_void() : $@convention(thin) () -> ()
return %instance_loaded : $C
}
// CHECK-LABEL: sil [ossa] @after_4 : $@convention(thin) (@owned C) -> @owned C {
// CHECK: bb0([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: br bb1
// CHECK: bb1:
// CHECK: [[CALLEE_VOID_TO_VOID:%[^,]+]] = function_ref @callee_void_to_void
// CHECK: apply [[CALLEE_VOID_TO_VOID]]()
// CHECK: return [[INSTANCE]]
// CHECK-LABEL: } // end sil function 'after_4'
sil [ossa] @after_4 : $@convention(thin) (@owned C) -> @owned C {
bb0(%instance : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance to [init] %addr : $*C
%instance_loaded = load [take] %addr : $*C
br exit
exit:
%callee_void_to_void = function_ref @callee_void_to_void : $@convention(thin) () -> ()
%ok = apply %callee_void_to_void() : $@convention(thin) () -> ()
dealloc_stack %addr : $*C
return %instance_loaded : $C
}
// CHECK-LABEL: sil [ossa] @after_5 : $@convention(thin) (@owned C) -> () {
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[EXIT]]:
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
// CHECK: [[RETVAL:%[^,]+]] = apply [[CALLEE_GUARANTEED]]([[INSTANCE]])
// CHECK: destroy_value [[INSTANCE]]
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'after_5'
sil [ossa] @after_5 : $@convention(thin) (@owned C) -> () {
bb0(%instance : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance to [init] %addr : $*C
%instance_loaded = load [take] %addr : $*C
br exit
exit:
dealloc_stack %addr : $*C
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
%retval = apply %callee_guaranteed(%instance_loaded) : $@convention(thin) (@guaranteed C) -> ()
destroy_value %instance_loaded : $C
return %retval : $()
}
// CHECK-LABEL: sil [ossa] @after_6 : $@convention(thin) (@owned C, @owned C, @owned C) -> @owned C {
// CHECK: {{bb[^,]+}}([[INSTANCE_1:%[^,]+]] : @owned $C, [[INSTANCE_2:%[^,]+]] : @owned $C, [[INSTANCE_3:%[^,]+]] : @owned $C):
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
// CHECK: apply [[CALLEE_GUARANTEED]]([[INSTANCE_2]])
// CHECK: apply [[CALLEE_GUARANTEED]]([[INSTANCE_1]])
// CHECK: destroy_value [[INSTANCE_2]]
// CHECK: destroy_value [[INSTANCE_3]]
// CHECK: return [[INSTANCE_1]]
// CHECK-LABEL: } // end sil function 'after_6'
sil [ossa] @after_6 : $@convention(thin) (@owned C, @owned C, @owned C) -> @owned C {
bb0(%instance_1 : @owned $C, %instance_2 : @owned $C, %instance_3 : @owned $C):
%callee_guaranteed = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
%addr = alloc_stack [lexical] $C
store %instance_1 to [init] %addr : $*C
%instance_1_loaded = load [take] %addr : $*C
store %instance_2 to [init] %addr : $*C
%instance_2_loaded = load [take] %addr : $*C
%ok2 = apply %callee_guaranteed(%instance_2_loaded) : $@convention(thin) (@guaranteed C) -> ()
%ok1 = apply %callee_guaranteed(%instance_1_loaded) : $@convention(thin) (@guaranteed C) -> ()
store %instance_3 to [init] %addr : $*C
%instance_3_loaded = load [take] %addr : $*C
dealloc_stack %addr : $*C
destroy_value %instance_2_loaded : $C
destroy_value %instance_3_loaded : $C
return %instance_1_loaded : $C
}
// CHECK-LABEL: sil [ossa] @after_7 : $@convention(thin) (@owned C) -> @owned C {
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: [[CALLEE_VOID_TO_VOID:%[^,]+]] = function_ref @callee_void_to_void
// CHECK: apply [[CALLEE_VOID_TO_VOID]]()
// CHECK: return [[INSTANCE]]
// CHECK-LABEL: } // end sil function 'after_7'
sil [ossa] @after_7 : $@convention(thin) (@owned C) -> @owned C {
bb0(%instance : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance to [init] %addr : $*C
%instance_loaded = load [take] %addr : $*C
%callee_void_to_void = function_ref @callee_void_to_void : $@convention(thin) () -> ()
%ok = apply %callee_void_to_void() : $@convention(thin) () -> ()
dealloc_stack %addr : $*C
return %instance_loaded : $C
}
// CHECK-LABEL: sil [ossa] @after_8 : $@convention(thin) (@owned C) -> @owned C {
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: [[COPY:%[^,]+]] = copy_value [[INSTANCE]]
// CHECK: destroy_value [[INSTANCE]]
// CHECK: [[CALLEE_VOID_TO_VOID:%[^,]+]] = function_ref @callee_void_to_void
// CHECK: apply [[CALLEE_VOID_TO_VOID]]()
// CHECK: return [[COPY]]
// CHECK-LABEL: } // end sil function 'after_8'
sil [ossa] @after_8 : $@convention(thin) (@owned C) -> @owned C {
bb0(%instance : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance to [init] %addr : $*C
%instance_loaded = load [copy] %addr : $*C
destroy_addr %addr : $*C
%callee_void_to_void = function_ref @callee_void_to_void : $@convention(thin) () -> ()
%ok = apply %callee_void_to_void() : $@convention(thin) () -> ()
dealloc_stack %addr : $*C
return %instance_loaded : $C
}
// CHECK-LABEL: sil [ossa] @after_9 : $@convention(thin) (@owned C, @owned C) -> @owned C {
// CHECK: {{bb[0-9]+}}([[INSTANCE_1:%[^,]+]] : @owned $C, [[INSTANCE_2:%[^,]+]] : @owned $C):
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[EXIT]]:
// CHECK: destroy_value [[INSTANCE_2]]
// CHECK: return [[INSTANCE_1]]
// CHECK-LABEL: } // end sil function 'after_9'
sil [ossa] @after_9 : $@convention(thin) (@owned C, @owned C) -> @owned C {
bb0(%instance_1 : @owned $C, %instance_2 : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance_1 to [init] %addr : $*C
%instance_1_loaded = load [take] %addr : $*C
br exit
exit:
store %instance_2 to [init] %addr : $*C
%instance_2_loaded = load [take] %addr : $*C
dealloc_stack %addr : $*C
destroy_value %instance_2_loaded : $C
return %instance_1_loaded : $C
}
// CHECK-LABEL: sil [ossa] @after_10 : $@convention(thin) (@owned C, @owned C) -> @owned C {
// CHECK: {{bb[^,]+}}([[INSTANCE_1:%[^,]+]] : @owned $C, [[INSTANCE_2:%[^,]+]] : @owned $C):
// CHECK: br [[WORK:bb[0-9]+]]
// CHECK: [[WORK]]:
// CHECK: [[COPY:%[^,]+]] = copy_value [[INSTANCE_1]]
// CHECK: destroy_value [[INSTANCE_1]]
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[EXIT]]:
// CHECK: destroy_value [[INSTANCE_2]]
// CHECK: return [[COPY]]
// CHECK-LABEL: } // end sil function 'after_10'
sil [ossa] @after_10 : $@convention(thin) (@owned C, @owned C) -> @owned C {
bb0(%instance_1 : @owned $C, %instance_2 : @owned $C):
%addr = alloc_stack [lexical] $C
br work
work:
store %instance_1 to [init] %addr : $*C
%instance_1_loaded = load [copy] %addr : $*C
store %instance_2 to [assign] %addr : $*C
%instance_2_loaded = load [take] %addr : $*C
br exit
exit:
dealloc_stack %addr : $*C
destroy_value %instance_2_loaded : $C
return %instance_1_loaded : $C
}
// CHECK-LABEL: sil [ossa] @after_11 : $@convention(thin) (@owned C, @owned C) -> @owned C {
// CHECK: {{bb[^,]+}}([[INSTANCE_1:%[^,]+]] : @owned $C, [[INSTANCE_2:%[^,]+]] : @owned $C):
// CHECK: br [[WORK:bb[0-9]+]]
// CHECK: [[WORK]]:
// CHECK: [[COPY:%[^,]+]] = copy_value [[INSTANCE_1]]
// CHECK: destroy_value [[INSTANCE_1]]
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[EXIT]]:
// CHECK: destroy_value [[INSTANCE_2]]
// CHECK: return [[COPY]]
// CHECK-LABEL: } // end sil function 'after_11'
sil [ossa] @after_11 : $@convention(thin) (@owned C, @owned C) -> @owned C {
bb0(%instance_1 : @owned $C, %instance_2 : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance_1 to [init] %addr : $*C
br work
work:
%instance_1_loaded = load [copy] %addr : $*C
store %instance_2 to [assign] %addr : $*C
%instance_2_loaded = load [take] %addr : $*C
br exit
exit:
dealloc_stack %addr : $*C
destroy_value %instance_2_loaded : $C
return %instance_1_loaded : $C
}
// after_N }}
// deferred_N {{ // scope closure isn't done immediately because it can't be
// Check that an initial store [assign] becomes a scope end.
// CHECK-LABEL: sil [ossa] @deferred_1 : $@convention(thin) (@owned C, @owned C) -> @owned C {
// CHECK: {{bb[^,]+}}([[INSTANCE_1:%[^,]+]] : @owned $C, [[INSTANCE_2:%[^,]+]] : @owned $C):
// CHECK: br [[WORK:bb[0-9]+]]
// CHECK: [[WORK]]:
// CHECK: destroy_value [[INSTANCE_2]]
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[EXIT]]:
// CHECK: return [[INSTANCE_1]]
// CHECK-LABEL: } // end sil function 'deferred_1'
sil [ossa] @deferred_1 : $@convention(thin) (@owned C,@owned C) -> @owned C {
entry(%instance_1 : @owned $C, %instance_2 : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance_2 to [init] %addr : $*C
br work
work:
store %instance_1 to [assign] %addr : $*C
%instance_1_loaded = load [take] %addr : $*C
br exit
exit:
dealloc_stack %addr : $*C
return %instance_1_loaded : $C
}
// Ensure that a store [assign] following an initial load [copy] gets a deferred
// scope end.
// CHECK-LABEL: sil [ossa] @deferred_2 : $@convention(thin) (@owned C, @owned C) -> @owned C {
// CHECK: {{bb[^,]+}}([[INSTANCE_1:%[^,]+]] : @owned $C, [[INSTANCE_2:%[^,]+]] : @owned $C):
// CHECK: br [[WORK:bb[0-9]+]]
// CHECK: [[WORK]]:
// CHECK: [[COPY_2:%[^,]+]] = copy_value [[INSTANCE_2]]
// CHECK: destroy_value [[COPY_2]]
// CHECK: destroy_value [[INSTANCE_2]]
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[EXIT]]:
// CHECK: return [[INSTANCE_1]]
// CHECK-LABEL: } // end sil function 'deferred_2'
sil [ossa] @deferred_2 : $@convention(thin) (@owned C,@owned C) -> @owned C {
entry(%instance_1 : @owned $C, %instance_2 : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance_2 to [init] %addr : $*C
br work
work:
%instance_2_loaded = load [copy] %addr : $*C
destroy_value %instance_2_loaded : $C
store %instance_1 to [assign] %addr : $*C
%instance_1_loaded = load [take] %addr : $*C
br exit
exit:
dealloc_stack %addr : $*C
return %instance_1_loaded : $C
}
// Ensure that an initial deferred destroy_addr becomes a scope end.
// CHECK-LABEL: sil [ossa] @deferred_3 : $@convention(thin) (@owned C, @owned C) -> @owned C {
// CHECK: {{bb[^,]+}}([[INSTANCE_1:%[^,]+]] : @owned $C, [[INSTANCE_2:%[^,]+]] : @owned $C):
// CHECK: br [[WORK:bb[0-9]+]]
// CHECK: [[WORK]]:
// CHECK: destroy_value [[INSTANCE_2]]
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[EXIT]]:
// CHECK: return [[INSTANCE_1]]
// CHECK-LABEL: } // end sil function 'deferred_3'
sil [ossa] @deferred_3 : $@convention(thin) (@owned C,@owned C) -> @owned C {
entry(%instance_1 : @owned $C, %instance_2 : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance_2 to [init] %addr : $*C
br work
work:
destroy_addr %addr : $*C
store %instance_1 to [init] %addr : $*C
%instance_1_loaded = load [take] %addr : $*C
br exit
exit:
dealloc_stack %addr : $*C
return %instance_1_loaded : $C
}
// Ensure that a destroy_addr following an initial load [copy] gets a deferred
// scope end.
// CHECK-LABEL: sil [ossa] @deferred_4 : $@convention(thin) (@owned C, @owned C) -> @owned C {
// CHECK: {{bb[^,]+}}([[INSTANCE_1:%[^,]+]] : @owned $C, [[INSTANCE_2:%[^,]+]] : @owned $C):
// CHECK: br [[WORK:bb[0-9]+]]
// CHECK: [[WORK]]:
// CHECK: [[COPY_2:%[^,]+]] = copy_value [[INSTANCE_2]]
// CHECK: destroy_value [[COPY_2]]
// CHECK: destroy_value [[INSTANCE_2]]
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[EXIT]]:
// CHECK: return [[INSTANCE_1]]
// CHECK-LABEL: } // end sil function 'deferred_4'
sil [ossa] @deferred_4 : $@convention(thin) (@owned C,@owned C) -> @owned C {
entry(%instance_1 : @owned $C, %instance_2 : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance_2 to [init] %addr : $*C
br work
work:
%instance_2_loaded = load [copy] %addr : $*C
destroy_value %instance_2_loaded : $C
destroy_addr %addr : $*C
store %instance_1 to [init] %addr : $*C
%instance_1_loaded = load [take] %addr : $*C
br exit
exit:
dealloc_stack %addr : $*C
return %instance_1_loaded : $C
}
// Ensure that an initial load [take] gets a deferred scope end.
// CHECK-LABEL: sil [ossa] @deferred_5 : $@convention(thin) (@owned C, @owned C) -> @owned C {
// CHECK: {{bb[0-9]+}}([[INSTANCE_1:%[^,]+]] : @owned $C, [[INSTANCE_2:%[^,]+]] : @owned $C):
// CHECK: br [[WORK:bb[0-9]+]]
// CHECK: [[WORK]]:
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[EXIT]]:
// CHECK: destroy_value [[INSTANCE_2]]
// CHECK: return [[INSTANCE_1]]
// CHECK-LABEL: } // end sil function 'deferred_5'
sil [ossa] @deferred_5 : $@convention(thin) (@owned C, @owned C) -> @owned C {
entry(%instance_1 : @owned $C, %instance_2 : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance_1 to [init] %addr : $*C
br work
work:
%instance_1_loaded = load [take] %addr : $*C
store %instance_2 to [init] %addr : $*C
%instance_2_loaded = load [take] %addr : $*C
br exit
exit:
dealloc_stack %addr : $*C
destroy_value %instance_2_loaded : $C
return %instance_1_loaded : $C
}
// Ensure that a load [take] following an initial load [copy] gets a deferred
// scope end.
// CHECK-LABEL: sil [ossa] @deferred_6 : $@convention(thin) (@owned C) -> @owned C {
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: br [[WORK:bb[0-9]+]]
// CHECK: [[WORK]]:
// CHECK: [[COPY:%[^,]+]] = copy_value [[INSTANCE]]
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[EXIT]]:
// CHECK: destroy_value [[COPY]]
// CHECK: return [[INSTANCE]]
// CHECK-LABEL: } // end sil function 'deferred_6'
sil [ossa] @deferred_6 : $@convention(thin) (@owned C) -> @owned C {
entry(%instance_1 : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance_1 to [init] %addr : $*C
br work
work:
%temporary = load [copy] %addr : $*C
%instance_1_loaded = load [take] %addr : $*C
br exit
exit:
dealloc_stack %addr : $*C
destroy_value %temporary : $C
return %instance_1_loaded : $C
}
// CHECK-LABEL: sil [ossa] @deferred_7 : $@convention(thin) (@owned C, @owned C) -> () {
// CHECK: {{bb[^,]+}}([[INSTANCE_1:%[^,]+]] : @owned $C, [[INSTANCE_2:%[^,]+]] : @owned $C):
// CHECK: br [[WORK:bb[0-9]+]]
// CHECK: [[WORK]]:
// CHECK: [[COPY_2:%[^,]+]] = copy_value [[INSTANCE_2]]
// CHECK: destroy_value [[COPY_2]]
// CHECK: destroy_value [[INSTANCE_2]]
// CHECK: destroy_value [[INSTANCE_1]]
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[EXIT]]:
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'deferred_7'
sil [ossa] @deferred_7 : $@convention(thin) (@owned C,@owned C) -> () {
entry(%instance_1 : @owned $C, %instance_2 : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance_2 to [init] %addr : $*C
br work
work:
%instance_2_loaded = load [copy] %addr : $*C
destroy_value %instance_2_loaded : $C
store %instance_1 to [assign] %addr : $*C
%instance_1_loaded = load [take] %addr : $*C
store %instance_1_loaded to [init] %addr : $*C
destroy_addr %addr : $*C
br exit
exit:
dealloc_stack %addr : $*C
%retval = tuple ()
return %retval : $()
}
// deferred_N }}
// term_N {{ the last use of the stored value is a terminator
// CHECK-LABEL: sil [ossa] @term_1 : $@convention(thin) (@owned C) -> @owned C {
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: return [[INSTANCE]]
// CHECK-LABEL: } // end sil function 'term_1'
sil [ossa] @term_1 : $@convention(thin) (@owned C) -> @owned C {
entry(%instance : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance to [init] %addr : $*C
%result = load [take] %addr : $*C
dealloc_stack %addr : $*C
return %result : $C
}
// CHECK-LABEL: sil [ossa] @term_2 : $@convention(thin) (@owned C) -> @owned C {
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: br [[EXIT:bb[^,]+]]([[INSTANCE_1]])
// CHECK: [[EXIT]]([[OUTSTANCE:%[^,]+]] : @owned $C):
// CHECK: return [[OUTSTANCE]]
// CHECK-LABEL: } // end sil function 'term_2'
sil [ossa] @term_2 : $@convention(thin) (@owned C) -> @owned C {
entry(%instance : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance to [init] %addr : $*C
%result = load [take] %addr : $*C
br exit(%result : $C)
exit(%outstance : @owned $C):
dealloc_stack %addr : $*C
return %outstance : $C
}
// CHECK-LABEL: sil [ossa] @term_3 : $@convention(thin) (@owned E) -> @owned C {
// CHECK: {{bb[^,]+}}([[EITHER:%[^,]+]] : @owned $E):
// CHECK: switch_enum [[INSTANCE]], case #E.one!enumelt: [[EXIT:bb[0-9]+]]
// CHECK: [[EXIT]]([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: return [[INSTANCE]]
// CHECK-LABEL: } // end sil function 'term_3'
sil [ossa] @term_3 : $@convention(thin) (@owned E) -> @owned C {
entry(%either : @owned $E):
%addr = alloc_stack [lexical] $E
store %either to [init] %addr : $*E
%either2 = load [take] %addr : $*E
dealloc_stack %addr : $*E
switch_enum %either2 : $E, case #E.one!enumelt: one
one(%instance : @owned $C):
return %instance : $C
}
// CHECK-LABEL: sil [ossa] @term_4 : $@convention(thin) (@owned C, @owned D) -> @owned D {
// CHECK: {{bb[^,]+}}([[SUPER_IN:%[^,]+]] : @owned $C, [[SUB_IN:%[^,]+]] : @owned $D):
// CHECK: checked_cast_br C in [[SUPER_IN]] to D, [[SUPER_IS_SUB:bb[^,]+]], [[SUPER_IS_SUPER:bb[0-9]+]]
// CHECK: [[SUPER_IS_SUB]]([[SUPER_AS_SUB:%[^,]+]] : @owned $D):
// CHECK: destroy_value [[SUB_IN]]
// CHECK: br [[EXIT:bb[^,]+]]([[SUPER_AS_SUB]])
// CHECK: [[SUPER_IS_SUPER]]([[SUPER_AS_SUPER:%[^,]+]] : @owned $C):
// CHECK: destroy_value [[SUPER_AS_SUPER]]
// CHECK: br [[EXIT]]([[SUB_IN]])
// CHECK: [[EXIT]]([[SUB_OUT:%[^,]+]] : @owned $D):
// CHECK: return [[SUB_OUT]]
// CHECK-LABEL: } // end sil function 'term_4'
sil [ossa] @term_4 : $@convention(thin) (@owned C, @owned D) -> @owned D {
bb0(%super_in : @owned $C, %sub_in : @owned $D):
%addr = alloc_stack [lexical] $C
store %super_in to [init] %addr : $*C
%super_load = load [take] %addr : $*C
checked_cast_br C in %super_load : $C to D, super_is_sub, super_is_super
super_is_sub(%super_as_sub : @owned $D):
destroy_value %sub_in : $D
br exit(%super_as_sub : $D)
super_is_super(%super_as_super : @owned $C):
destroy_value %super_as_super : $C
br exit(%sub_in : $D)
exit(%sub_out : @owned $D):
dealloc_stack %addr : $*C
return %sub_out : $D
}
// CHECK-LABEL: sil hidden [ossa] @term_5 : $@convention(thin) (@owned C) -> @error any Error {
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: [[CALLEE_ERROR_OWNED:%[^,]+]] = function_ref @callee_error_owned
// CHECK: try_apply [[CALLEE_ERROR_OWNED]]([[INSTANCE]]) : $@convention(thin) (@owned C) -> @error any Error, normal [[REGULAR_BLOCK:bb[^,]+]], error [[THROW_BLOCK:bb[0-9]+]]
// CHECK: [[REGULAR_BLOCK]]({{%[^,]+}} : $()):
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[THROW_BLOCK]]([[ERROR:%[^,]+]] : @owned $any Error):
// CHECK: destroy_value [[ERROR]]
// CHECK: br [[EXIT]]
// CHECK: [[EXIT]]:
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'term_5'
sil hidden [ossa] @term_5 : $@convention(thin) (@owned C) -> @error Error {
bb0(%instance : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance to [init] %addr : $*C
%instance_load = load [take] %addr : $*C
%callee_error_owned = function_ref @callee_error_owned : $@convention(thin) (@owned C) -> @error Error
try_apply %callee_error_owned(%instance_load) : $@convention(thin) (@owned C) -> @error Error, normal regular_block, error throw_block
regular_block(%7 : $()):
br exit
throw_block(%error : @owned $Error):
destroy_value %error : $Error
br exit
exit:
dealloc_stack %addr : $*C
%retval = tuple ()
return %retval : $()
}
// CHECK-LABEL: sil [ossa] @term_6 : $@yield_once @convention(method) (@owned C) -> @yields C {
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: yield [[INSTANCE]], resume [[RESUME_BLOCK:bb[^,]+]], unwind [[UNWIND_BLOCK:bb[0-9]+]]
// CHECK: [[RESUME_BLOCK]]:
// CHECK: destroy_value [[INSTANCE]]
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
// CHECK: return [[RETVAL]]
// CHECK: [[UNWIND_BLOCK]]:
// CHECK: destroy_value [[INSTANCE]]
// CHECK: unwind
// CHECK-LABEL: } // end sil function 'term_6'
sil [ossa] @term_6 : $@yield_once @convention(method) (@owned C) -> @yields C {
entry(%instance : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance to [init] %addr : $*C
%instance_load = load [take] %addr : $*C
yield %instance_load : $C, resume resume_block, unwind unwind_block
resume_block:
destroy_value %instance_load : $C
dealloc_stack %addr : $*C
%result = tuple ()
return %result : $()
unwind_block:
destroy_value %instance_load : $C
dealloc_stack %addr : $*C
unwind
}
// CHECK-LABEL: sil [ossa] @term_7 : $@convention(thin) (@owned C) -> @error C {
// CHECK: bb0([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: cond_br undef, [[THROW_BLOCK:bb[^,]+]], [[REGULAR_BLOCK:bb[0-9]+]]
// CHECK: [[THROW_BLOCK]]:
// CHECK: throw [[INSTANCE]]
// CHECK: [[REGULAR_BLOCK]]:
// CHECK: destroy_value [[INSTANCE]]
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'term_7'
sil [ossa] @term_7 : $@convention(thin) (@owned C) -> @error C {
bb0(%instance : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance to [init] %addr : $*C
%instance_load = load [take] %addr : $*C
cond_br undef, bb1, bb2
bb1:
dealloc_stack %addr : $*C
throw %instance_load : $C
bb2:
destroy_value %instance_load : $C
dealloc_stack %addr : $*C
%18 = tuple ()
return %18 : $()
}
// term_N }}
// unreachable_N {{ ending of scopes in blocks that terminate in unreachable
// CHECK-LABEL: sil [ossa] @unreachable_1 : $@convention(thin) (@owned C, @owned C) -> () {
// CHECK: {{bb[^,]+}}([[INSTANCE_1:%[^,]+]] : @owned $C, [[INSTANCE_2:%[^,]+]] : @owned $C):
// CHECK: br [[DIE:bb[0-9]+]]
// CHECK: [[DIE]]:
// CHECK: destroy_value [[INSTANCE_1]]
// CHECK: unreachable
// CHECK-LABEL: } // end sil function 'unreachable_1'
sil [ossa] @unreachable_1 : $@convention(thin) (@owned C, @owned C) -> () {
entry(%one : @owned $C, %two : @owned $C):
%addr = alloc_stack [lexical] $C
store %one to [init] %addr : $*C
br work
work:
%one_loaded = load [take] %addr : $*C
destroy_value %one_loaded : $C
store %two to [init] %addr : $*C
unreachable
}
// CHECK-LABEL: sil [ossa] @unreachable_2 : $@convention(thin) (@owned C) -> () {
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: unreachable
// CHECK-LABEL: } // end sil function 'unreachable_2'
sil [ossa] @unreachable_2 : $@convention(thin) (@owned C) -> () {
entry(%instance : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance to [init] %addr : $*C
unreachable
}
// CHECK-LABEL: sil [ossa] @unreachable_3 : $@convention(thin) (@owned C) -> () {
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: unreachable
// CHECK-LABEL: } // end sil function 'unreachable_3'
sil [ossa] @unreachable_3 : $@convention(thin) (@owned C) -> () {
entry(%instance : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance to [init] %addr : $*C
%instance_loaded = load [take] %addr : $*C
destroy_value [dead_end] %instance_loaded
unreachable
}
// CHECK-LABEL: sil [ossa] @unreachable_4 : $@convention(thin) (@owned C) -> () {
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: unreachable
// CHECK-LABEL: } // end sil function 'unreachable_4'
sil [ossa] @unreachable_4 : $@convention(thin) (@owned C) -> () {
entry(%instance : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance to [init] %addr : $*C
%instance_loaded = load [take] %addr : $*C
store %instance_loaded to [init] %addr : $*C
unreachable
}
// End lifetime before unreachable inst.
// CHECK-LABEL: sil [ossa] @unreachable_5 : $@convention(thin) (@owned C) -> () {
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[EXIT]]:
// CHECK: unreachable
// CHECK-LABEL: } // end sil function 'unreachable_5'
sil [ossa] @unreachable_5 : $@convention(thin) (@owned C) -> () {
entry(%instance_1 : @owned $C):
%addr = alloc_stack [lexical] $C
store %instance_1 to [init] %addr :$*C
br exit
exit:
unreachable
}
// Bail out if alloc_stack is in unreachable block.
// CHECK-LABEL: sil @unreachable_6 : $@convention(thin) (@owned C) -> () {
// CHECK: alloc_stack [lexical]
// CHECK-LABEL: } // end sil function 'unreachable_6'
sil @unreachable_6 : $@convention(thin) (@owned C) -> () {
entry(%instance_1 : $C):
br exit
unr:
%addr = alloc_stack [lexical] $C
store %instance_1 to %addr :$*C
br die
die:
unreachable
exit:
%res = tuple ()
return %res : $()
}
// Bail out if alloc_stack is in unreachable block.
// CHECK-LABEL: sil @unreachable_7 : $@convention(thin) (@owned C) -> () {
// CHECK: alloc_stack [lexical]
// CHECK-LABEL: } // end sil function 'unreachable_7'
sil @unreachable_7 : $@convention(thin) (@owned C) -> () {
entry(%instance_1 : $C):
cond_br undef, exit, die_later
unr:
%addr = alloc_stack [lexical] $C
store %instance_1 to %addr :$*C
br die_later_2
die_later_2:
br die
die_later:
br die
die:
unreachable
exit:
%res = tuple ()
return %res : $()
}
// Bail out if alloc_stack is in unreachable block.
// CHECK-LABEL: sil @unreachable_8 : $@convention(thin) (@owned C) -> () {
// CHECK: alloc_stack [lexical]
// CHECK-LABEL: } // end sil function 'unreachable_8'
sil @unreachable_8 : $@convention(thin) (@owned C) -> () {
entry(%instance_1 : $C):
cond_br undef, exit, die_later
unr:
%addr = alloc_stack [lexical] $C
store %instance_1 to %addr : $*C
cond_br undef, die_later_2_a, die_later_2_b
die_later_2_a:
br die_later_2
die_later_2_b:
br die_later_2
die_later_2:
br die
die_later:
br die
die:
unreachable
exit:
%res = tuple ()
return %res : $()
}
// End lifetime after loop which is followed by unreachable.
// CHECK-LABEL: sil [ossa] @unreachable_loop_1 : $@convention(thin) () -> () {
// CHECK: {{bb[0-9]+}}:
// CHECK: [[GET_C:%[^,]+]] = function_ref @getC : $@convention(thin) () -> @owned C
// CHECK: [[INSTANCE:%[^,]+]] = apply [[GET_C]]() : $@convention(thin) () -> @owned C
// CHECK: br [[LOOP_HEADER:bb[0-9]+]]
// CHECK: [[LOOP_HEADER]]:
// CHECK: br [[LOOP_BODY:bb[0-9]+]]
// CHECK: [[LOOP_BODY]]:
// CHECK: br [[LOOP_EXIT:bb[0-9]+]]
// CHECK: [[LOOP_EXIT]]:
// CHECK: cond_br undef, [[LOOP_BACKEDGE:bb[0-9]+]], [[DIE:bb[0-9]+]]
// CHECK: [[LOOP_BACKEDGE]]:
// CHECK: br [[LOOP_HEADER]]
// CHECK: [[DIE]]:
// CHECK: unreachable
// CHECK-LABEL: } // end sil function 'unreachable_loop_1'
sil [ossa] @unreachable_loop_1 : $@convention(thin) () -> () {
entry:
%delegate_var = alloc_stack [lexical] $C
%getC = function_ref @getC : $@convention(thin) () -> @owned C
%delegate = apply %getC() : $@convention(thin) () -> @owned C
store %delegate to [init] %delegate_var : $*C
br loop_header
loop_header:
br loop_body
loop_body:
br loop_exit
loop_exit:
cond_br undef, loop_backedge, die
loop_backedge:
br loop_header
die:
unreachable
}
// Bail out if alloc_stack is in unreachable block.
// CHECK-LABEL: sil @unreachable_loop_2 : $@convention(thin) () -> () {
// CHECK: alloc_stack [lexical]
// CHECK-LABEL: } // end sil function 'unreachable_loop_2'
sil @unreachable_loop_2 : $@convention(thin) () -> () {
entry:
br loop_header
unr:
%delegate_var = alloc_stack [lexical] $C
%getC = function_ref @getC : $@convention(thin) () -> @owned C
%delegate = apply %getC() : $@convention(thin) () -> @owned C
store %delegate to %delegate_var : $*C
br loop_header
loop_header:
br loop_body
loop_body:
br loop_exit
loop_exit:
cond_br undef, loop_backedge, die
loop_backedge:
br loop_header
die:
unreachable
}
// Bail out if alloc_stack is in unreachable block.
// CHECK-LABEL: sil @unreachable_loop_3 : $@convention(thin) () -> () {
// CHECK: alloc_stack [lexical]
// CHECK-LABEL: } // end sil function 'unreachable_loop_3'
sil @unreachable_loop_3 : $@convention(thin) () -> () {
entry:
br die_entry
die_entry:
br die
unr:
%delegate_var = alloc_stack [lexical] $C
%getC = function_ref @getC : $@convention(thin) () -> @owned C
%delegate = apply %getC() : $@convention(thin) () -> @owned C
store %delegate to %delegate_var : $*C
br loop_header
loop_header:
br loop_body
loop_body:
br loop_exit
loop_exit:
cond_br undef, loop_backedge, die_loop
loop_backedge:
br loop_header
die_loop:
br die
die:
unreachable
}
// }} unreachable_N
// diamond_N {{ the usages of the alloc_stack occur over a diamond of blocks
// CHECK-LABEL: sil [ossa] @diamond_1 : $@convention(thin) (@owned C, @owned C) -> () {
// CHECK: {{bb[^,]+}}([[INSTANCE_1:%[^,]+]] : @owned $C, [[INSTANCE_2:%[^,]+]] : @owned $C):
// CHECK: cond_br undef, [[LEFT:bb[^,]+]], [[RIGHT:bb[0-9]+]]
// CHECK: [[LEFT]]:
// CHECK: destroy_value [[INSTANCE_2]]
// CHECK: br [[EXIT:bb[^,]+]]([[INSTANCE_1]])
// CHECK: [[RIGHT]]:
// CHECK: br [[EXIT]]([[INSTANCE_2]])
// CHECK: [[EXIT]]([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
// CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[INSTANCE]])
// CHECK: destroy_value [[INSTANCE]]
// CHECK: [[RESULT:%[^,]+]] = tuple ()
// CHECK: return [[RESULT]]
// CHECK-LABEL: } // end sil function 'diamond_1'
sil [ossa] @diamond_1 : $@convention(thin) (@owned C, @owned C) -> () {
entry(%one : @owned $C, %two : @owned $C):
%addr = alloc_stack [lexical] $C
cond_br undef, left, right
left:
destroy_value %two : $C
store %one to [init] %addr : $*C
br exit
right:
destroy_value %one : $C
store %two to [init] %addr : $*C
br exit
exit:
%value = load [take] %addr : $*C
%callee = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
%_ = apply %callee(%value) : $@convention(thin) (@guaranteed C) -> ()
destroy_value %value : $C
dealloc_stack %addr : $*C
%result = tuple ()
return %result : $()
}
// Store and load the value to the alloc stack only on one branch.
//
// CHECK-LABEL: sil [ossa] @diamond_2 : $@convention(thin) (@owned C, @owned C) -> () {
// CHECK: {{bb[^,]+}}([[INSTANCE_0:%[^,]+]] : @owned $C, [[INSTANCE_1:%[^,]+]] : @owned $C):
// CHECK: cond_br undef, [[LEFT:bb[^,]+]], [[RIGHT:bb[0-9]+]]
// CHECK: [[LEFT]]:
// CHECK: destroy_value [[INSTANCE_0]]
// CHECK: destroy_value [[INSTANCE_1]]
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[RIGHT]]:
// CHECK: destroy_value [[INSTANCE_0]]
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
// CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[INSTANCE_1]])
// CHECK: destroy_value [[INSTANCE_1]]
// CHECK: br [[EXIT]]
// CHECK: [[EXIT]]:
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'diamond_2'
sil [ossa] @diamond_2 : $@convention(thin) (@owned C, @owned C) -> () {
entry(%one : @owned $C, %two : @owned $C):
%addr = alloc_stack [lexical] $C
cond_br undef, left, right
left:
destroy_value %one : $C
destroy_value %two : $C
br exit
right:
destroy_value %one : $C
store %two to [init] %addr : $*C
%value = load [take] %addr : $*C
%callee = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
%_ = apply %callee(%value) : $@convention(thin) (@guaranteed C) -> ()
destroy_value %value : $C
br exit
exit:
dealloc_stack %addr : $*C
%result = tuple ()
return %result : $()
}
// Ensure that the lifetime is extended to the final destroy_addr even when
// there are no uses after the middle blocks.
//
// CHECK-LABEL: sil [ossa] @diamond_3 : $@convention(thin) (@owned C, @owned C) -> () {
// CHECK: {{bb[^,]+}}([[ONE:%[^,]+]] : @owned $C, [[TWO:%[^,]+]] : @owned $C):
// CHECK: cond_br undef, [[LEFT:bb[^,]+]], [[RIGHT:bb[0-9]+]]
// CHECK: [[LEFT]]:
// CHECK: destroy_value [[TWO]]
// CHECK: br [[EXIT:bb[^,]+]]([[ONE]])
// CHECK: [[RIGHT]]:
// CHECK: destroy_value [[ONE]]
// CHECK: br [[EXIT]]([[TWO]])
// CHECK: [[EXIT]]([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: destroy_value [[INSTANCE]]
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'diamond_3'
sil [ossa] @diamond_3 : $@convention(thin) (@owned C, @owned C) -> () {
entry(%one : @owned $C, %two : @owned $C):
%addr = alloc_stack [lexical] $C
cond_br undef, left, right
left:
destroy_value %two : $C
store %one to [init] %addr : $*C
br exit
right:
destroy_value %one : $C
store %two to [init] %addr : $*C
br exit
exit:
destroy_addr %addr : $*C
dealloc_stack %addr : $*C
%result = tuple ()
return %result : $()
}
// Ensure that the value stored to the alloc_stack is kept alive until the
// destroy_addr in a subsequent block even when there are no uses.
//
// CHECK-LABEL: sil [ossa] @diamond_4 : $@convention(thin) (@owned C, @owned C) -> () {
// CHECK: {{bb[^,]+}}([[ONE:%[^,]+]] : @owned $C, [[TWO:%[^,]+]] : @owned $C):
// CHECK: cond_br undef, [[LEFT:bb[^,]+]], [[RIGHT:bb[0-9]+]]
// CHECK: [[LEFT]]:
// CHECK: destroy_value [[TWO]]
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[RIGHT]]:
// CHECK: destroy_value [[ONE]]
// CHECK: unreachable
// CHECK: [[EXIT]]:
// CHECK: destroy_value [[ONE]]
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'diamond_4'
sil [ossa] @diamond_4 : $@convention(thin) (@owned C, @owned C) -> () {
entry(%one : @owned $C, %two : @owned $C):
%addr = alloc_stack [lexical] $C
cond_br undef, left, right
left:
destroy_value %two : $C
store %one to [init] %addr : $*C
br exit
right:
destroy_value %one : $C
store %two to [init] %addr : $*C
unreachable
exit:
destroy_addr %addr : $*C
dealloc_stack %addr : $*C
%result = tuple ()
return %result : $()
}
// CHECK-LABEL: sil [ossa] @diamond_5 : $@convention(thin) (@owned C, @owned C) -> () {
// CHECK: {{bb[^,]+}}([[ONE:%[^,]+]] : @owned $C, [[TWO:%[^,]+]] : @owned $C):
// CHECK: cond_br undef, [[LEFT:bb[^,]+]], [[RIGHT:bb[0-9]+]]
// CHECK: [[LEFT]]:
// CHECK: destroy_value [[TWO]]
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[RIGHT]]:
// CHECK: destroy_value [[ONE]]
// CHECK: unreachable
// CHECK: [[EXIT]]:
// CHECK: destroy_value [[ONE]]
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'diamond_5'
sil [ossa] @diamond_5 : $@convention(thin) (@owned C, @owned C) -> () {
entry(%one : @owned $C, %two : @owned $C):
%addr = alloc_stack [lexical] $C
cond_br undef, left, right
left:
destroy_value %two : $C
store %one to [init] %addr : $*C
br exit
right:
destroy_value %one : $C
store %two to [init] %addr : $*C
unreachable
exit:
destroy_addr %addr : $*C
dealloc_stack %addr : $*C
%result = tuple ()
return %result : $()
}
// Verify that a dead-end which succeeds the introduction of a borrow_scope ends
// the borrow scope before the unreachable.
// CHECK-LABEL: sil [ossa] @diamond_6 : $@convention(thin) (@owned C) -> () {
// CHECK: {{bb[^,]+}}([[ORIGINAL:%[^,]+]] : @owned $C):
// CHECK: cond_br undef, [[THROW_BLOCK:bb[^,]+]], [[REGULAR_BLOCK:bb[0-9]+]]
// CHECK: [[THROW_BLOCK]]:
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[REGULAR_BLOCK]]:
// CHECK: unreachable
// CHECK: [[EXIT:bb[^,]+]]:
// CHECK: destroy_value [[ORIGINAL]]
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'diamond_6'
sil [ossa] @diamond_6 : $@convention(thin) (@owned C) -> () {
entry(%original : @owned $C):
%addr = alloc_stack [lexical] $C
store %original to [init] %addr : $*C
cond_br undef, left, right
left:
br exit
right:
unreachable
exit:
destroy_addr %addr : $*C
dealloc_stack %addr : $*C
%result = tuple ()
return %result : $()
}
// CHECK-LABEL: sil [ossa] @diamond_7 : $@convention(thin) (@owned C) -> () {
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: [[COPY:%[^,]+]] = copy_value [[INSTANCE]]
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
// CHECK: apply [[CALLEE_GUARANTEED]]([[COPY]])
// CHECK: destroy_value [[COPY]]
// CHECK: destroy_value [[INSTANCE]]
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
// CHECK: [[LEFT]]:
// CHECK: unreachable
// CHECK: [[RIGHT]]:
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'diamond_7'
sil [ossa] @diamond_7 : $@convention(thin) (@owned C) -> () {
entry(%one : @owned $C):
%addr = alloc_stack [lexical] $C
store %one to [init] %addr : $*C
%value2 = load [copy] %addr : $*C
%callee2 = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
%_2 = apply %callee2(%value2) : $@convention(thin) (@guaranteed C) -> ()
destroy_value %value2 : $C
destroy_addr %addr : $*C
cond_br undef, left, right
left:
unreachable
right:
dealloc_stack %addr : $*C
%result = tuple ()
return %result : $()
}
// CHECK-LABEL: sil [ossa] @diamond_8 : $@convention(thin) (@owned C) -> () {
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: [[COPY:%[^,]+]] = copy_value [[INSTANCE]]
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
// CHECK: apply [[CALLEE_GUARANTEED]]([[COPY]])
// CHECK: destroy_value [[COPY]]
// CHECK: cond_br undef, [[DIE:bb[0-9]+]], [[EXIT:bb[0-9]+]]
// CHECK: [[DIE]]:
// CHECK: unreachable
// CHECK: [[EXIT]]:
// CHECK: destroy_value [[INSTANCE]]
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
// CHECK: return [[RETVAL]]
// CHECK-LABEL: } // end sil function 'diamond_8'
sil [ossa] @diamond_8 : $@convention(thin) (@owned C) -> () {
entry(%one : @owned $C):
%addr = alloc_stack [lexical] $C
store %one to [init] %addr : $*C
%value2 = load [copy] %addr : $*C
%callee2 = function_ref @callee_guaranteed : $@convention(thin) (@guaranteed C) -> ()
%_2 = apply %callee2(%value2) : $@convention(thin) (@guaranteed C) -> ()
destroy_value %value2 : $C
cond_br undef, left, right
left:
unreachable
right:
destroy_addr %addr : $*C
dealloc_stack %addr : $*C
%result = tuple ()
return %result : $()
}
// CHECK-LABEL: sil [ossa] @diamond_9 : $@convention(thin) (@owned C) -> () {
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @owned $C):
// CHECK: cond_br undef, [[BB1:bb[0-9]+]], [[BB4:bb[0-9]+]]
// CHECK: [[BB1]]:
// CHECK: cond_br undef, [[BB2:bb[0-9]+]], [[BB3:bb[0-9]+]]
// CHECK: [[BB2]]:
// CHECK: destroy_value [[INSTANCE]]
// CHECK: br [[BB5:bb[0-9]+]]
// CHECK: [[BB3]]:
// CHECK: br [[BB5]]
// CHECK: [[BB4]]:
// CHECK: br [[BB5]]
// CHECK: [[BB5]]:
// CHECK: unreachable
// CHECK-LABEL: } // end sil function 'diamond_9'
sil [ossa] @diamond_9 : $@convention(thin) (@owned C) -> () {
bb0(%instance : @owned $C):
%addr = alloc_stack [lexical] $C
cond_br undef, bb1, bb4
bb1:
store %instance to [init] %addr : $*C
cond_br undef, bb2, bb3
bb2:
destroy_addr %addr : $*C
br bb5
bb3:
destroy_addr %addr : $*C
br bb5
bb4:
destroy_value [dead_end] %instance
br bb5
bb5:
unreachable
}
// diamond_N }}
// CHECK-LABEL: sil [ossa] @test_no_storeborrow4 :
// CHECK-NOT: alloc_stack [lexical]
// CHECK-LABEL: } // end sil function 'test_no_storeborrow4'
sil [ossa] @test_no_storeborrow4 : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
%1 = alloc_stack [lexical] $Klass
store %0 to [init] %1 : $*Klass
%2 = load_borrow %1 : $*Klass
%3 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
%4 = apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> ()
end_borrow %2 : $Klass
destroy_addr %1 : $*Klass
dealloc_stack %1 : $*Klass
%6 = tuple ()
return %6 : $()
}
// CHECK-LABEL: sil [ossa] @test_control_flow5 :
// CHECK-NOT: alloc_stack [lexical]
// CHECK-LABEL: } // end sil function 'test_control_flow5'
sil [ossa] @test_control_flow5 : $@convention(thin) (@guaranteed Klass, @guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass, %1 : @guaranteed $Klass):
%stk = alloc_stack [lexical] $Klass
cond_br undef, bb1, bb2
bb1:
%copy1 = copy_value %0 : $Klass
store %copy1 to [init] %stk : $*Klass
br bb3
bb2:
%copy2 = copy_value %1 : $Klass
store %copy2 to [init] %stk : $*Klass
br bb3
bb3:
%2 = load_borrow %stk : $*Klass
%3 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
%4 = apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> ()
end_borrow %2 : $Klass
destroy_addr %stk : $*Klass
dealloc_stack %stk : $*Klass
%8 = tuple ()
return %8 : $()
}
sil [ossa] @use_owned : $@convention(thin) (@owned Klass) -> ()
// Test no ownership verifier error
// CHECK-LABEL: sil [ossa] @test_control_flow6 :
// CHECK-NOT: alloc_stack [lexical]
// CHECK-LABEL: } // end sil function 'test_control_flow6'
sil [ossa] @test_control_flow6 : $@convention(thin) () -> () {
bb0:
%0 = function_ref @get_owned : $@convention(thin) () -> @owned Klass
%1 = alloc_stack [lexical] $Klass
%2 = apply %0() : $@convention(thin) () -> @owned Klass
store %2 to [init] %1 : $*Klass
cond_br undef, bb1, bb2
bb1:
%5 = apply %0() : $@convention(thin) () -> @owned Klass
store %5 to [assign] %1 : $*Klass
br bb3
bb2:
br bb3
bb3:
%9 = load_borrow %1 : $*Klass
end_borrow %9 : $Klass
br bb4
bb4:
cond_br undef, bb8, bb9
bb8:
br bb4
bb9:
cond_br undef, bb10, bb11
bb10:
br bb12
bb11:
%19 = load [copy] %1 : $*Klass
%20 = function_ref @use_owned : $@convention(thin) (@owned Klass) -> ()
%21 = apply %20(%19) : $@convention(thin) (@owned Klass) -> ()
br bb12
bb12:
%23 = apply %0() : $@convention(thin) () -> @owned Klass
store %23 to [assign] %1 : $*Klass
cond_br undef, bb13, bb14
bb13:
%26 = load [take] %1 : $*Klass
destroy_value %26 : $Klass
dealloc_stack %1 : $*Klass
%29 = tuple ()
return %29 : $()
bb14:
unreachable
}
// CHECK-LABEL: sil [ossa] @test_control_flow7 :
// CHECK-NOT: alloc_stack [lexical]
// CHECK-LABEL: } // end sil function 'test_control_flow7'
sil [ossa] @test_control_flow7 : $@convention(thin) () -> () {
bb0:
%4 = alloc_stack [lexical] $Klass
%f = function_ref @get_owned : $@convention(thin) () -> @owned Klass
%5 = apply %f() : $@convention(thin) () -> @owned Klass
store %5 to [init] %4 : $*Klass
%7 = load_borrow %4 : $*Klass
end_borrow %7 : $Klass
cond_br undef, bb1, bb2
bb1:
br bb3
bb2:
%28 = load_borrow %4 : $*Klass
end_borrow %28 : $Klass
br bb3
bb3:
destroy_addr %4 : $*Klass
dealloc_stack %4 : $*Klass
%r = tuple ()
return %r : $()
}
sil [ossa] @printC : $@convention(thin) (@guaranteed C) -> ()
// CHECK-LABEL: sil [ossa] @liveness0 :
// CHECK-NOT: alloc_stack
sil [ossa] @liveness0 : $@convention(thin) (@owned C, @owned C, @owned C, @owned C) -> () {
bb0(%instance_1 : @owned $C, %instance_2 : @owned $C, %instance_3 : @owned $C, %instance_4 : @owned $C):
%addr_x = alloc_stack [lexical] $C
store %instance_1 to [init] %addr_x : $*C
cond_br undef, bb1, bb5
bb1:
%addr_y = alloc_stack [lexical] $C
store %instance_2 to [init] %addr_y : $*C
cond_br undef, bb2, bb3
bb2:
destroy_value %instance_4 : $C
store %instance_3 to [assign] %addr_y : $*C
br bb4
bb3:
destroy_value %instance_3 : $C
store %instance_4 to [assign] %addr_y : $*C
br bb4
bb4:
%print = function_ref @printC : $@convention(thin) (@guaranteed C) -> ()
%26 = load [take] %addr_y : $*C
%36 = apply %print(%26) : $@convention(thin) (@guaranteed C) -> ()
destroy_value %26 : $C
dealloc_stack %addr_y : $*C
br bb6
bb5:
destroy_value %instance_2 : $C
destroy_value %instance_3 : $C
destroy_value %instance_4 : $C
br bb6
// We don't need a PHI node here because the value is dead!
// CHECK: bb5:
bb6:
destroy_addr %addr_x : $*C
dealloc_stack %addr_x : $*C
%40 = tuple ()
return %40 : $()
}
// CHECK-LABEL: } // end sil function 'liveness0'
// CHECK-LABEL: sil [ossa] @liveness1 :
// CHECK-NOT: alloc_stack
sil [ossa] @liveness1 : $@convention(thin) (Int64) -> () {
bb0(%0 : $Int64):
%1 = alloc_stack $Int64, var, name "x"
store %0 to [trivial] %1 : $*Int64
%3 = integer_literal $Builtin.Int64, 10
%5 = struct_extract %0 : $Int64, #Int64._value
%6 = builtin "cmp_eq_Int64"(%5 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
cond_br %6, bb1, bb5
bb1:
%8 = alloc_stack $Int64, var, name "y"
%9 = integer_literal $Builtin.Int64, 20
%10 = struct $Int64 (%9 : $Builtin.Int64)
store %10 to [trivial] %8 : $*Int64
%12 = integer_literal $Builtin.Int64, 3
%14 = struct_extract %0 : $Int64, #Int64._value
%15 = builtin "cmp_sgt_Int64"(%14 : $Builtin.Int64, %12 : $Builtin.Int64) : $Builtin.Int1
cond_br %15, bb2, bb3
bb2:
%17 = integer_literal $Builtin.Int64, 0
%18 = struct $Int64 (%17 : $Builtin.Int64)
store %18 to [trivial] %8 : $*Int64
br bb4
bb3:
%21 = integer_literal $Builtin.Int64, 2
%22 = struct $Int64 (%21 : $Builtin.Int64)
store %22 to [trivial] %8 : $*Int64
br bb4
bb4:
// function_ref
%25 = function_ref @_Ts5printFT3valSi_T_ : $@convention(thin) (Int64) -> ()
%26 = load [trivial] %8 : $*Int64
%27 = integer_literal $Builtin.Int64, 2
%28 = integer_literal $Builtin.Int1, -1
%30 = struct_extract %26 : $Int64, #Int64._value
%31 = builtin "sadd_with_overflow_Int64"(%30 : $Builtin.Int64, %27 : $Builtin.Int64, %28 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
%32 = tuple_extract %31 : $(Builtin.Int64, Builtin.Int1), 0
%33 = tuple_extract %31 : $(Builtin.Int64, Builtin.Int1), 1
%34 = struct $Int64 (%32 : $Builtin.Int64)
cond_fail %33 : $Builtin.Int1
%36 = apply %25(%34) : $@convention(thin) (Int64) -> ()
dealloc_stack %8 : $*Int64
br bb6
bb5:
br bb6
// We don't need a PHI node here because the value is dead!
// CHECK: bb5:
bb6:
dealloc_stack %1 : $*Int64
%40 = tuple ()
return %40 : $()
}
// CHECK-LABEL: } // end sil function 'liveness1'
// func foo(v : Int) -> Int {
// var x : Int = 0
// if v == 3 { x = 3 } else {
// if (v == 2) { x = 2 }
// }
// var i : Int = 0
// while (i < 10) { i = i+1 }
// return x
// }
// CHECK: sil [ossa] @place_phi :
// CHECK-NOT: alloc_stack
sil [ossa] @place_phi : $@convention(thin) (Int64) -> Int64 {
bb0(%0 : $Int64):
%1 = alloc_stack $Int64, var, name "v"
store %0 to [trivial] %1 : $*Int64
%3 = alloc_stack $Int64, var, name "x"
%4 = integer_literal $Builtin.Int64, 0
%5 = struct $Int64 (%4 : $Builtin.Int64)
store %5 to [trivial] %3 : $*Int64
%7 = integer_literal $Builtin.Int64, 3
%9 = struct_extract %0 : $Int64, #Int64._value
%10 = builtin "cmp_eq_Int64"(%9 : $Builtin.Int64, %7 : $Builtin.Int64) : $Builtin.Int1
cond_br %10, bb1, bb2
bb1:
%12 = struct $Int64 (%7 : $Builtin.Int64)
store %12 to [trivial] %3 : $*Int64
br bb6
bb2:
%15 = integer_literal $Builtin.Int64, 2
%16 = builtin "cmp_eq_Int64"(%9 : $Builtin.Int64, %15 : $Builtin.Int64) : $Builtin.Int1
cond_br %16, bb3, bb4
bb3:
%18 = struct $Int64 (%15 : $Builtin.Int64)
store %18 to [trivial] %3 : $*Int64
br bb5
bb4:
br bb5
bb5:
br bb6
// CHECK: bb6([[PHI:%[0-9]+]] : $Int64):
// CHECK-NOT: alloc_stack
bb6:
%22 = alloc_stack $Int64, var, name "i"
store %5 to [trivial] %22 : $*Int64
br bb7
// CHECK: bb7([[PHI2:%[0-9]+]] : $Int64):
bb7:
// CHECK: struct_extract [[PHI2]]
%25 = struct_element_addr %22 : $*Int64, #Int64._value
%26 = load [trivial] %25 : $*Builtin.Int64
%27 = integer_literal $Builtin.Int64, 10
%29 = builtin "cmp_slt_Int64"(%26 : $Builtin.Int64, %27 : $Builtin.Int64) : $Builtin.Int1
cond_br %29, bb8, bb9
bb8:
// CHECK: struct_extract [[PHI2]]
%31 = struct_element_addr %22 : $*Int64, #Int64._value
%32 = load [trivial] %31 : $*Builtin.Int64
%33 = integer_literal $Builtin.Int64, 1
%35 = builtin "sadd_with_overflow_Int64"(%32 : $Builtin.Int64, %33 : $Builtin.Int64, %29 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
%36 = tuple_extract %35 : $(Builtin.Int64, Builtin.Int1), 0
%37 = tuple_extract %35 : $(Builtin.Int64, Builtin.Int1), 1
%38 = struct $Int64 (%36 : $Builtin.Int64)
cond_fail %37 : $Builtin.Int1
store %38 to [trivial] %22 : $*Int64
br bb7
bb9:
%42 = load [trivial] %3 : $*Int64
dealloc_stack %22 : $*Int64
dealloc_stack %3 : $*Int64
dealloc_stack %1 : $*Int64
return %42 : $Int64
}
// CHECK-LABEL: } // end sil function 'place_phi'
// func loop(c : Int) -> Int {
// var x : Int = 0
// while (x < c) { x = x + 1 }
// return x
// }
// CHECK: sil [ossa] @func_loop :
// CHECK-NOT: alloc_stack
sil [ossa] @func_loop: $@convention(thin) (Int64) -> Int64 {
bb0(%0 : $Int64):
%1 = alloc_stack $Int64, var, name "c"
store %0 to [trivial] %1 : $*Int64
%3 = alloc_stack $Int64, var, name "x"
%4 = integer_literal $Builtin.Int64, 0
%5 = struct $Int64 (%4 : $Builtin.Int64)
store %5 to [trivial] %3 : $*Int64
br bb1
// CHECK: bb1([[VAR:%[0-9]+]] : $Int64):
bb1:
%8 = load [trivial] %3 : $*Int64
%10 = struct_extract %8 : $Int64, #Int64._value
%11 = struct_extract %0 : $Int64, #Int64._value
%12 = builtin "cmp_slt_Int64"(%10 : $Builtin.Int64, %11 : $Builtin.Int64) : $Builtin.Int1
cond_br %12, bb2, bb3
bb2:
%14 = load [trivial] %3 : $*Int64
%15 = integer_literal $Builtin.Int64, 1
%16 = integer_literal $Builtin.Int1, -1
%18 = struct_extract %14 : $Int64, #Int64._value
%19 = builtin "sadd_with_overflow_Int64"(%18 : $Builtin.Int64, %15 : $Builtin.Int64, %16 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
%20 = tuple_extract %19 : $(Builtin.Int64, Builtin.Int1), 0
%21 = tuple_extract %19 : $(Builtin.Int64, Builtin.Int1), 1
%22 = struct $Int64 (%20 : $Builtin.Int64)
cond_fail %21 : $Builtin.Int1
store %22 to [trivial] %3 : $*Int64
br bb1
bb3:
%26 = load [trivial] %3 : $*Int64
dealloc_stack %3 : $*Int64
dealloc_stack %1 : $*Int64
// CHECK-NOT: dealloc_stack
return %26 : $Int64
}
// CHECK-LABEL: } // end sil function 'func_loop'
// func nest(c : Int) -> Int {
// var x : Int = 0
// if (c > 1) { if (c > 2) { if (c > 3) { if (c > 4) {
// if (c > 5) { if (c > 6) { if (c > 7) { if (c > 8) {
// if (c > 9) { if (c > 10) { if (c > 11) { if (c > 12) {
// if (c > 13) { if (c > 14) { if (c > 15) { if (c > 16) {
// if (c > 17) { x = 7 }}}}}}}}}}}}}}}}} return x
// }
// This test should kill exponential algorithms.
// CHECK: sil [ossa] @high_nest :
// CHECK-NOT: alloc_stack
// CHECK-NOT: dealloc_stack
// CHECK-LABEL: } // end sil function 'high_nest'
sil [ossa] @high_nest : $@convention(thin) (Int64) -> Int64 {
bb0(%0 : $Int64):
%1 = alloc_stack $Int64, var, name "c"
store %0 to [trivial] %1 : $*Int64
%3 = alloc_stack $Int64, var, name "x"
%4 = integer_literal $Builtin.Int64, 0
%5 = struct $Int64 (%4 : $Builtin.Int64)
store %5 to [trivial] %3 : $*Int64
%7 = integer_literal $Builtin.Int64, 1
%9 = struct_extract %0 : $Int64, #Int64._value
%10 = builtin "cmp_sgt_Int64"(%9 : $Builtin.Int64, %7 : $Builtin.Int64) : $Builtin.Int1
cond_br %10, bb1, bb34
bb1:
%12 = integer_literal $Builtin.Int64, 2
%14 = struct_extract %0 : $Int64, #Int64._value
%15 = builtin "cmp_sgt_Int64"(%14 : $Builtin.Int64, %12 : $Builtin.Int64) : $Builtin.Int1
cond_br %15, bb2, bb33
bb2:
%17 = integer_literal $Builtin.Int64, 3
%19 = struct_extract %0 : $Int64, #Int64._value
%20 = builtin "cmp_sgt_Int64"(%19 : $Builtin.Int64, %17 : $Builtin.Int64) : $Builtin.Int1
cond_br %20, bb3, bb32
bb3:
%22 = integer_literal $Builtin.Int64, 4
%24 = struct_extract %0 : $Int64, #Int64._value
%25 = builtin "cmp_sgt_Int64"(%24 : $Builtin.Int64, %22 : $Builtin.Int64) : $Builtin.Int1
cond_br %25, bb4, bb31
bb4:
%27 = integer_literal $Builtin.Int64, 5
%29 = struct_extract %0 : $Int64, #Int64._value
%30 = builtin "cmp_sgt_Int64"(%29 : $Builtin.Int64, %27 : $Builtin.Int64) : $Builtin.Int1
cond_br %30, bb5, bb30
bb5:
%32 = integer_literal $Builtin.Int64, 6
%34 = struct_extract %0 : $Int64, #Int64._value
%35 = builtin "cmp_sgt_Int64"(%34 : $Builtin.Int64, %32 : $Builtin.Int64) : $Builtin.Int1
cond_br %35, bb6, bb29
bb6:
%37 = integer_literal $Builtin.Int64, 7
%39 = struct_extract %0 : $Int64, #Int64._value
%40 = builtin "cmp_sgt_Int64"(%39 : $Builtin.Int64, %37 : $Builtin.Int64) : $Builtin.Int1
cond_br %40, bb7, bb28
bb7:
%42 = integer_literal $Builtin.Int64, 8
%44 = struct_extract %0 : $Int64, #Int64._value
%45 = builtin "cmp_sgt_Int64"(%44 : $Builtin.Int64, %42 : $Builtin.Int64) : $Builtin.Int1
cond_br %45, bb8, bb27
bb8:
%47 = integer_literal $Builtin.Int64, 9
%49 = struct_extract %0 : $Int64, #Int64._value
%50 = builtin "cmp_sgt_Int64"(%49 : $Builtin.Int64, %47 : $Builtin.Int64) : $Builtin.Int1
cond_br %50, bb9, bb26
bb9:
%52 = integer_literal $Builtin.Int64, 10
%54 = struct_extract %0 : $Int64, #Int64._value
%55 = builtin "cmp_sgt_Int64"(%54 : $Builtin.Int64, %52 : $Builtin.Int64) : $Builtin.Int1
cond_br %55, bb10, bb25
bb10:
%57 = integer_literal $Builtin.Int64, 11
%59 = struct_extract %0 : $Int64, #Int64._value
%60 = builtin "cmp_sgt_Int64"(%59 : $Builtin.Int64, %57 : $Builtin.Int64) : $Builtin.Int1
cond_br %60, bb11, bb24
bb11:
%62 = integer_literal $Builtin.Int64, 12
%64 = struct_extract %0 : $Int64, #Int64._value
%65 = builtin "cmp_sgt_Int64"(%64 : $Builtin.Int64, %62 : $Builtin.Int64) : $Builtin.Int1
cond_br %65, bb12, bb23
bb12:
%67 = integer_literal $Builtin.Int64, 13
%69 = struct_extract %0 : $Int64, #Int64._value
%70 = builtin "cmp_sgt_Int64"(%69 : $Builtin.Int64, %67 : $Builtin.Int64) : $Builtin.Int1
cond_br %70, bb13, bb22
bb13:
%72 = integer_literal $Builtin.Int64, 14
%74 = struct_extract %0 : $Int64, #Int64._value
%75 = builtin "cmp_sgt_Int64"(%74 : $Builtin.Int64, %72 : $Builtin.Int64) : $Builtin.Int1
cond_br %75, bb14, bb21
bb14:
%77 = integer_literal $Builtin.Int64, 15
%79 = struct_extract %0 : $Int64, #Int64._value
%80 = builtin "cmp_sgt_Int64"(%79 : $Builtin.Int64, %77 : $Builtin.Int64) : $Builtin.Int1
cond_br %80, bb15, bb20
bb15:
%82 = integer_literal $Builtin.Int64, 16
%84 = struct_extract %0 : $Int64, #Int64._value
%85 = builtin "cmp_sgt_Int64"(%84 : $Builtin.Int64, %82 : $Builtin.Int64) : $Builtin.Int1
cond_br %85, bb16, bb19
bb16:
%87 = integer_literal $Builtin.Int64, 17
%89 = struct_extract %0 : $Int64, #Int64._value
%90 = builtin "cmp_sgt_Int64"(%89 : $Builtin.Int64, %87 : $Builtin.Int64) : $Builtin.Int1
cond_br %90, bb17, bb18
bb17:
%92 = integer_literal $Builtin.Int64, 7
%93 = struct $Int64 (%92 : $Builtin.Int64)
store %93 to [trivial] %3 : $*Int64
br bb35
bb18:
br bb35
bb35:
br bb36
bb19:
br bb36
bb36:
br bb37
bb20:
br bb37
bb37:
br bb38
bb21:
br bb38
bb38:
br bb39
bb22:
br bb39
bb39:
br bb40
bb23:
br bb40
bb40:
br bb41
bb24:
br bb41
bb41:
br bb42
bb25:
br bb42
bb42:
br bb43
bb26:
br bb43
bb43:
br bb44
bb27:
br bb44
bb44:
br bb45
bb28:
br bb45
bb45:
br bb46
bb29:
br bb46
bb46:
br bb47
bb30:
br bb47
bb47:
br bb48
bb31:
br bb48
bb48:
br bb49
bb32:
br bb49
bb49:
br bb50
bb33:
br bb50
bb50:
br bb51
bb34:
br bb51
bb51:
%112 = load [trivial] %3 : $*Int64
dealloc_stack %3 : $*Int64
dealloc_stack %1 : $*Int64
return %112 : $Int64
}
// CHECK-LABEL: sil [ossa] @simple_if :
// CHECK-NOT: alloc_stack
sil [ossa] @simple_if : $@convention(thin) (Int64) -> Int64 {
bb0(%0 : $Int64):
%1 = alloc_stack $Int64, var, name "c"
store %0 to [trivial] %1 : $*Int64
%3 = alloc_stack $Int64, var, name "x"
%4 = integer_literal $Builtin.Int64, 0
// CHECK: [[INIT:%[0-9]+]] = struct $Int64
%5 = struct $Int64 (%4 : $Builtin.Int64)
store %5 to [trivial] %3 : $*Int64
%8 = struct_extract %0 : $Int64, #Int64._value
%9 = builtin "cmp_sgt_Int64"(%4 : $Builtin.Int64, %8 : $Builtin.Int64) : $Builtin.Int1
cond_br %9, bb1, bb2
bb1:
%11 = integer_literal $Builtin.Int64, 2
// CHECK: [[INIT2:%[0-9]+]] = struct $Int64
%12 = struct $Int64 (%11 : $Builtin.Int64)
store %12 to [trivial] %3 : $*Int64
// CHECK: br bb3([[INIT2]])
br bb3
bb2:
// CHECK: br bb3([[INIT]])
br bb3
bb3:
%15 = load [trivial] %3 : $*Int64
dealloc_stack %3 : $*Int64
dealloc_stack %1 : $*Int64
return %15 : $Int64
}
// CHECK-LABEL: } // end sil function 'simple_if'
enum E3 {
case One
case Two
case Three
}
// CHECK-LABEL: sil [ossa] @test_switch :
// CHECK-NOT: alloc_stack
// CHECK-NOT: dealloc_stack
sil [ossa] @test_switch: $@convention(thin) (Int64, E3) -> Int64 {
bb0(%0 : $Int64, %1 : $E3):
%2 = alloc_stack $Int64, var, name "xi"
%3 = alloc_stack $E3, var, name "c"
store %0 to [trivial] %2 : $*Int64
store %1 to [trivial] %3 : $*E3
%6 = alloc_stack $Int64, var, name "x"
store %0 to [trivial] %6 : $*Int64
%8 = tuple ()
switch_enum %1 : $E3, case #E3.One!enumelt: bb1, case #E3.Two!enumelt: bb3, case #E3.Three!enumelt: bb5
bb1:
br bb2
bb2:
%11 = integer_literal $Builtin.Int64, 3
%12 = struct $Int64 (%11 : $Builtin.Int64)
store %12 to [trivial] %6 : $*Int64
br bb7
bb3:
br bb4
bb4:
%16 = integer_literal $Builtin.Int64, 2
%17 = struct $Int64 (%16 : $Builtin.Int64)
store %17 to [trivial] %6 : $*Int64
br bb7
bb5:
br bb6
bb6:
%21 = integer_literal $Builtin.Int64, 1
%22 = struct $Int64 (%21 : $Builtin.Int64)
store %22 to [trivial] %6 : $*Int64
br bb7
bb7:
%25 = load [trivial] %6 : $*Int64
dealloc_stack %6 : $*Int64
dealloc_stack %3 : $*E3
dealloc_stack %2 : $*Int64
return %25 : $Int64
}
// CHECK-LABEL: } // end sil function 'test_switch'
// CHECK-LABEL: sil [ossa] @non_materializable_load_projection :
// CHECK: alloc_stack
// CHECK-LABEL: } // end sil function 'non_materializable_load_projection'
sil [ossa] @non_materializable_load_projection : $@convention(thin) (FakeOptional<Int>) -> Int {
bb0(%0 : $FakeOptional<Int>):
%1 = alloc_stack $FakeOptional<Int>
store %0 to [trivial] %1
%2 = unchecked_inplace_enum_data_addr %1, #FakeOptional.some!enumelt
%3 = load [trivial] %2
dealloc_stack %1
return %3
}
// CHECK-LABEL: sil [ossa] @mark_dependence :
// CHECK: %1 = apply undef()
// CHECK: %2 = mark_dependence %1 on %0
// CHECK-LABEL: } // end sil function 'mark_dependence'
sil [ossa] @mark_dependence : $@convention(thin) (Builtin.RawPointer) -> @owned C {
bb0(%0 : $Builtin.RawPointer):
%1 = alloc_stack $Builtin.RawPointer
store %0 to [trivial] %1
%3 = apply undef() : $@convention(thin) () -> @owned C
%4 = mark_dependence %3 on %1
dealloc_stack %1
return %4
}
// CHECK-LABEL: sil [ossa] @mark_dependence_value :
// CHECK: %2 = mark_dependence %0 on %1
// CHECK-NEXT: return %2
// CHECK-LABEL: } // end sil function 'mark_dependence_value'
sil [ossa] @mark_dependence_value : $@convention(thin) (Builtin.RawPointer, @guaranteed Kl) -> Builtin.RawPointer {
bb0(%0 : $Builtin.RawPointer, %1 : @guaranteed $Kl):
%2 = alloc_stack $Builtin.RawPointer
store %0 to [trivial] %2
%3 = mark_dependence %2 on %1
%4 = load [trivial] %3
dealloc_stack %2
return %4
}
// CHECK-LABEL: sil [ossa] @mark_dependence_base_and_value :
// CHECK: %1 = mark_dependence %0 on %0
// CHECK-NEXT: return %1
// CHECK-LABEL: } // end sil function 'mark_dependence_base_and_value'
sil [ossa] @mark_dependence_base_and_value : $@convention(thin) (Builtin.RawPointer) -> Builtin.RawPointer {
bb0(%0 : $Builtin.RawPointer):
%1 = alloc_stack $Builtin.RawPointer
store %0 to [trivial] %1
%3 = mark_dependence %1 on %1
%4 = load [trivial] %3
dealloc_stack %1
return %4
}
// CHECK-LABEL: sil [ossa] @mark_dependence_addr :
// CHECK: %1 = alloc_stack $C
// CHECK: %2 = apply undef(%1)
// CHECK: mark_dependence_addr %1 on %0
// CHECK-LABEL: } // end sil function 'mark_dependence_addr'
sil [ossa] @mark_dependence_addr : $@convention(thin) (Builtin.RawPointer) -> @owned C {
bb0(%0 : $Builtin.RawPointer):
%1 = alloc_stack $C
%2 = alloc_stack $Builtin.RawPointer
store %0 to [trivial] %2
%4 = apply undef(%1) : $@convention(thin) () -> @out C
mark_dependence_addr %1 on %2
dealloc_stack %2
%7 = load [take] %1
dealloc_stack %1
return %7
}
// CHECK-LABEL: sil [ossa] @raw_layout :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'raw_layout'
sil [ossa] @raw_layout : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%1 = alloc_stack [lexical] $RawLayoutStruct
%2 = builtin "prepareInitialization"(%1) : $()
%3 = builtin "addressOfRawLayout"<RawLayoutStruct>(%1) : $Builtin.RawPointer
%4 = pointer_to_address %3 to [strict] $*Int
store %0 to [trivial] %4
%6 = drop_deinit %1
dealloc_stack %1
%9 = tuple ()
return %9
}
// CHECK-LABEL: sil [ossa] @type_dependenct_operand :
// CHECK: alloc_stack
// CHECK: witness_method
// CHECK: apply
// CHECK-LABEL: } // end sil function 'type_dependenct_operand'
sil [ossa] @type_dependenct_operand : $@convention(thin) (SP2) -> () {
bb0(%0 : $SP2):
%1 = alloc_stack [lexical] $any P2
%3 = init_existential_addr %1, $SP2
store %0 to [trivial] %3
%6 = open_existential_addr immutable_access %1 to $*@opened("80B3AD40-58F1-11F1-8742-0EA13E3AABB3", any P2) Self
%19 = witness_method $@opened("80B3AD40-58F1-11F1-8742-0EA13E3AABB3", any P2) Self, #P2.bar : <Self where Self : P2> (Self) -> () -> (), %6 : $*@opened("80B3AD40-58F1-11F1-8742-0EA13E3AABB3", any P2) Self : $@convention(witness_method: P2) (@in_guaranteed @opened("80B3AD40-58F1-11F1-8742-0EA13E3AABB3", any P2) Self) -> ()
%20 = apply %19(undef) : $@convention(witness_method: P2) (@in_guaranteed @opened("80B3AD40-58F1-11F1-8742-0EA13E3AABB3", any P2) Self) -> ()
destroy_addr %1
dealloc_stack %1
%25 = tuple ()
return %25
}
// CHECK-LABEL: sil [ossa] @load_take :
// CHECK: (%1, %2, %3) = destructure_struct %0
// CHECK-NOT: alloc_stack
// CHECK: destroy_value %1
// CHECK-NEXT: destroy_value
// CHECK-NEXT: destroy_value
// CHECK-NEXT: destroy_value
// CHECK-LABEL: } // end sil function 'load_take'
sil [ossa] @load_take : $@convention(thin) (@owned S3) -> () {
bb0(%0 : @owned $S3):
%1 = alloc_stack [lexical] $S3
store %0 to [init] %1
%3 = struct_element_addr %1, #S3.v1
%4 = load [take] %3
%5 = struct_element_addr %1, #S3.v2
%5a = tuple_element_addr %5, 0
%6a = load [take] %5a
%5b = tuple_element_addr %5, 1
%6b = load [take] %5b
%7 = struct_element_addr %1, #S3.v3
%8 = load [take] %7
dealloc_stack %1
destroy_value %4
destroy_value %6a
destroy_value %6b
destroy_value %8
%t = tuple ()
return %t
}
// CHECK-LABEL: sil [ossa] @mismatching_existential_type_borrow :
// Currently not optimized
// CHECK-LABEL: } // end sil function 'mismatching_existential_type_borrow'
sil [ossa] @mismatching_existential_type_borrow : $@convention(thin) (@owned D) -> () {
bb0(%0 : @owned $D):
%1 = alloc_stack [lexical] $any P
%2 = init_existential_addr %1, $D
store %0 to [init] %2
%4 = open_existential_addr immutable_access %1 to $*@opened("592F4C30-5E4F-11F1-B22D-0EA13E3AABB3", any P) Self
%5 = unchecked_addr_cast %4 to $*C
%6 = load_borrow %5
%7 = apply undef(%6) : $@convention(method) (@guaranteed C) -> ()
end_borrow %6
destroy_addr %1
dealloc_stack %1
%r = tuple ()
return %r
}
// CHECK-LABEL: sil [ossa] @split_store :
// CHECK: ({{.*}}, [[V2A:%.*]]) = destructure_struct undef
// CHECK: [[S1:%.*]] = struct $Sy (%0, [[V2A]])
// CHECK: ([[V1B:%.*]], [[V2B:%.*]]) = destructure_struct [[S1]]
// CHECK: [[S2:%.*]] = struct $Sy ([[V1B]], %1)
// CHECK: end_lifetime [[V2B]]
// CHECK: return [[S2]]
// CHECK-LABEL: } // end sil function 'split_store'
sil [ossa] @split_store : $@convention(thin) (@owned AnyObject, @owned AnyObject) -> @owned Sy {
bb0(%0 : @owned $AnyObject, %1 : @owned $AnyObject):
%2 = alloc_stack $Sy
%3 = struct_element_addr %2, #Sy.v1
store %0 to [init] %3
%5 = struct_element_addr %2, #Sy.v2
store %1 to [init] %5
%7 = load [take] %2
dealloc_stack %2
return %7
}
// CHECK-LABEL: sil [ossa] @split_store_with_phi_argument :
// CHECK: bb1:
// CHECK: ({{.*}}, [[V2A:%.*]]) = destructure_struct undef
// CHECK: [[S1:%.*]] = struct $Sy (%0, [[V2A]])
// CHECK: ([[V1B:%.*]], [[V2B:%.*]]) = destructure_struct [[S1]]
// CHECK: [[S2A:%.*]] = struct $Sy ([[V1B]], %1)
// CHECK: end_lifetime [[V2B]]
// CHECK: br bb3([[S2A]])
// CHECK: bb2:
// CHECK: [[S2B:%.*]] = struct $Sy (%0, %1)
// CHECK: br bb3([[S2B]])
// CHECK: bb3([[PHI:%.*]] : @owned $Sy):
// CHECK: return [[PHI]]
// CHECK-LABEL: } // end sil function 'split_store_with_phi_argument'
sil [ossa] @split_store_with_phi_argument : $@convention(thin) (@owned AnyObject, @owned AnyObject) -> @owned Sy {
bb0(%0 : @owned $AnyObject, %1 : @owned $AnyObject):
%2 = alloc_stack $Sy
cond_br undef, bb1, bb2
bb1:
%3 = struct_element_addr %2, #Sy.v1
store %0 to [init] %3
%5 = struct_element_addr %2, #Sy.v2
store %1 to [init] %5
br bb3
bb2:
%8 = struct $Sy (%0, %1)
store %8 to [init] %2
br bb3
bb3:
%11 = load [take] %2
dealloc_stack %2
return %11
}
// CHECK-LABEL: sil [ossa] @destroy_trivial1 :
// CHECK-NOT: alloc_stack
// CHECK: return %0
// CHECK-LABEL: } // end sil function 'destroy_trivial1'
sil [ossa] @destroy_trivial1 : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
%1 = alloc_stack $Int
store %0 to [trivial] %1
%3 = load [trivial] %1
destroy_addr %1
dealloc_stack %1
return %3
}
// CHECK-LABEL: sil [ossa] @destroy_trivial2 :
// CHECK-NOT: alloc_stack
// CHECK: (%1, %2) = destructure_struct %0
// CHECK: destroy_value %1
// CHECK-LABEL: } // end sil function 'destroy_trivial2'
sil [ossa] @destroy_trivial2 : $@convention(thin) (@owned Pair) -> () {
bb0(%0 : @owned $Pair):
%1 = alloc_stack $Pair
store %0 to [init] %1
%3 = struct_element_addr %1, #Pair.o
destroy_addr %3
%5 = struct_element_addr %1, #Pair.i
destroy_addr %5
dealloc_stack %1
%r = tuple ()
return %r
}
// CHECK-LABEL: sil [ossa] @triple_stores :
// CHECK: bb1:
// CHECK: [[T1:%.*]] = struct $Triple (%0
// CHECK-NEXT: br bb3([[T1]])
// CHECK: bb2:
// CHECK: [[T2:%.*]] = struct $Triple (%0
// CHECK-NEXT: br bb3([[T2]])
// CHECK: bb3([[P:%.*]] : @owned $Triple):
// CHECK: ([[A1:%.*]], [[B1:%.*]], [[C1:%.*]]) = destructure_struct [[P]]
// CHECK: [[R1:%.*]] = struct $Triple ([[A1]], %1, [[C1]])
// CHECK: end_lifetime [[B1]]
// CHECK: ([[A2:%.*]], [[B2:%.*]], [[C2:%.*]]) = destructure_struct [[R1]]
// CHECK: [[R2:%.*]] = struct $Triple ([[A2]], [[B2]], %2)
// CHECK: end_lifetime [[C2]]
// CHECK: return [[R2]]
// CHECK-LABEL: } // end sil function 'triple_stores'
sil [ossa] @triple_stores : $@convention(thin) (@owned AnyObject, @owned AnyObject, @owned AnyObject) -> @owned Triple {
bb0(%0 : @owned $AnyObject, %1 : @owned $AnyObject, %2 : @owned $AnyObject):
%3 = alloc_stack $Triple
%4 = struct_element_addr %3, #Triple.a
cond_br undef, bb1, bb2
bb1:
store %0 to [init] %4
br bb3
bb2:
store %0 to [init] %4
br bb3
bb3:
%6 = struct_element_addr %3, #Triple.b
store %1 to [init] %6
%8 = struct_element_addr %3, #Triple.c
store %2 to [init] %8
%10 = load [take] %3
dealloc_stack %3
return %10
}
// CHECK-LABEL: sil [ossa] @incomplete_tuple_element_lifetime :
// CHECK-NOT: alloc_stack
// CHECK-LABEL: } // end sil function 'incomplete_tuple_element_lifetime'
sil [ossa] @incomplete_tuple_element_lifetime : $@convention(thin) (@owned FakeOptional<Kl>, @owned FakeOptional<Kl>) -> () {
bb0(%0 : @owned $FakeOptional<Kl>, %1 : @owned $FakeOptional<Kl>):
%2 = alloc_stack $(FakeOptional<Kl>, FakeOptional<Kl>)
%3 = tuple_element_addr %2, 0
store %0 to [init] %3
%5 = tuple_element_addr %2, 1
store %1 to [init] %5
cond_br undef, bb1, bb2
bb1:
%8 = load [take] %2
destroy_value %8
br bb3
bb2:
%11 = load [take] %3
destroy_value %11
br bb3
bb3:
dealloc_stack %2
%r = tuple ()
return %r
}
// Dynamic begin_access on an alloc_stack address prevents elimination.
//
// CHECK-LABEL: sil [ossa] @begin_access_dynamic_bailout :
// CHECK: alloc_stack
// CHECK-LABEL: } // end sil function 'begin_access_dynamic_bailout'
sil [ossa] @begin_access_dynamic_bailout : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
%stk = alloc_stack $Klass
store %0 to [init] %stk : $*Klass
%access = begin_access [modify] [dynamic] %stk : $*Klass
end_access %access : $*Klass
destroy_addr %stk : $*Klass
dealloc_stack %stk : $*Klass
%r = tuple ()
return %r : $()
}
// Store to the root path, then overwrite one field via struct_element_addr, then
// load the whole struct. The old field value is destroyed and the result is
// rebuilt with the new field value.
//
// CHECK-LABEL: sil [ossa] @root_store_field_override :
// CHECK: bb0(%0 : @owned $Sy, %1 : @owned $AnyObject):
// CHECK-NOT: alloc_stack
// CHECK: ([[V1:%.*]], [[OLD_V2:%.*]]) = destructure_struct %0
// CHECK: [[RESULT:%.*]] = struct $Sy ([[V1]], %1)
// CHECK: destroy_value [[OLD_V2]]
// CHECK: return [[RESULT]]
// CHECK-LABEL: } // end sil function 'root_store_field_override'
sil [ossa] @root_store_field_override : $@convention(thin) (@owned Sy, @owned AnyObject) -> @owned Sy {
bb0(%0 : @owned $Sy, %1 : @owned $AnyObject):
%stk = alloc_stack $Sy
store %0 to [init] %stk : $*Sy
%v2_addr = struct_element_addr %stk : $*Sy, #Sy.v2
store %1 to [assign] %v2_addr : $*AnyObject
%result = load [take] %stk : $*Sy
dealloc_stack %stk : $*Sy
return %result : $Sy
}
// CHECK-LABEL: sil [ossa] @projected_load_borrow_overlap :
// Currently not optimized
// CHECK-LABEL: } // end sil function 'projected_load_borrow_overlap'
sil [ossa] @projected_load_borrow_overlap : $@convention(thin) (@owned Kl, @owned Kl) -> () {
bb0(%0 : @owned $Kl, %1 : @owned $Kl):
%2 = alloc_stack $(Kl, Kl)
%3 = tuple_element_addr %2, 0
store %0 to [init] %3
%5 = tuple_element_addr %2, 1
store %1 to [init] %5
cond_br undef, bb1, bb2
bb1:
%8 = load [take] %2
destroy_value %8
br bb3
bb2:
%10 = load_borrow %5
%11 = load [take] %3
destroy_value %11
end_borrow %10
%14 = load [take] %5
destroy_value %14
br bb3
bb3:
dealloc_stack %2
%r = tuple ()
return %r
}
// CHECK-LABEL: sil [ossa] @enum_with_empty_payload :
// Currently not optimized
// CHECK-NOT: switch_enum undef
// CHECK-LABEL: } // end sil function 'enum_with_empty_payload'
sil [ossa] @enum_with_empty_payload : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $FakeOptional<()>
inject_enum_addr %0, #FakeOptional.some!enumelt
%2 = load [trivial] %0
switch_enum %2, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb1(%99 : $()):
br bb3
bb2:
br bb3
bb3:
dealloc_stack %0
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @dealloc_partial_ref :
// CHECK-NOT: alloc_ref
// CHECK: destroy_value %0
// CHECK-LABEL: } // end sil function 'dealloc_partial_ref'
sil [ossa] @dealloc_partial_ref : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = alloc_ref $TrivialDestructor
%2 = begin_borrow %1
%3 = ref_element_addr %2, #TrivialDestructor.ptr
store %0 to [init] %3
end_borrow %2
%4 = metatype $@thick TrivialDestructor.Type
dealloc_partial_ref %1, %4
%r = tuple()
return %r
}