mirror of
https://github.com/apple/swift.git
synced 2026-02-27 18:26:24 +01:00
Even if an indirect argument is unused, pretend that the function reads from it. If the unused argument is passed to another generic function and that function is specialized, the argument may be re-abstracted and the specializer inserts a load from the indirect argument. Therefore we must be prepared that unused indirect argument might get loaded from at some time. Fixes a compiler crash rdar://168623362
702 lines
23 KiB
Plaintext
702 lines
23 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all %s -temp-lvalue-elimination | %FileCheck %s
|
|
|
|
// REQUIRES: swift_in_compiler
|
|
|
|
import Swift
|
|
import Builtin
|
|
import SwiftShims
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_enum_with_initialize :
|
|
// CHECK: bb0(%0 : $*Optional<Any>, %1 : $*Any):
|
|
// CHECK-NEXT: [[E:%[0-9]+]] = init_enum_data_addr %0
|
|
// CHECK-NEXT: copy_addr [take] %1 to [init] [[E]]
|
|
// CHECK-NEXT: inject_enum_addr %0 : $*Optional<Any>, #Optional.some!enumelt
|
|
// CHECK-NOT: copy_addr
|
|
// CHECK: } // end sil function 'test_enum_with_initialize'
|
|
sil [ossa] @test_enum_with_initialize : $@convention(thin) (@in Any) -> @out Optional<Any> {
|
|
bb0(%0 : $*Optional<Any>, %1 : $*Any):
|
|
%2 = alloc_stack $Optional<Any>
|
|
%3 = init_enum_data_addr %2 : $*Optional<Any>, #Optional.some!enumelt
|
|
copy_addr [take] %1 to [init] %3 : $*Any
|
|
inject_enum_addr %2 : $*Optional<Any>, #Optional.some!enumelt
|
|
copy_addr [take] %2 to [init] %0 : $*Optional<Any>
|
|
dealloc_stack %2 : $*Optional<Any>
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_enum_without_initialize :
|
|
// CHECK: bb0(%0 : $*Optional<Any>, %1 : $*Any):
|
|
// CHECK-NEXT: destroy_addr %0
|
|
// CHECK-NEXT: [[E:%[0-9]+]] = init_enum_data_addr %0
|
|
// CHECK-NEXT: copy_addr [take] %1 to [init] [[E]]
|
|
// CHECK-NEXT: inject_enum_addr %0 : $*Optional<Any>, #Optional.some!enumelt
|
|
// CHECK-NOT: copy_addr
|
|
// CHECK: } // end sil function 'test_enum_without_initialize'
|
|
sil [ossa] @test_enum_without_initialize : $@convention(thin) (@inout Optional<Any>, @in Any) -> () {
|
|
bb0(%0 : $*Optional<Any>, %1 : $*Any):
|
|
%2 = alloc_stack $Optional<Any>
|
|
%3 = init_enum_data_addr %2 : $*Optional<Any>, #Optional.some!enumelt
|
|
copy_addr [take] %1 to [init] %3 : $*Any
|
|
inject_enum_addr %2 : $*Optional<Any>, #Optional.some!enumelt
|
|
copy_addr [take] %2 to %0 : $*Optional<Any>
|
|
dealloc_stack %2 : $*Optional<Any>
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
protocol Proto {}
|
|
|
|
struct ConformingStruct : Proto {
|
|
@_hasStorage let a: Any
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_existential :
|
|
// CHECK: bb0(%0 : $*any Proto, %1 : $*ConformingStruct):
|
|
// CHECK-NEXT: [[E:%[0-9]+]] = init_existential_addr %0
|
|
// CHECK-NEXT: copy_addr [take] %1 to [init] [[E]]
|
|
// CHECK-NOT: copy_addr
|
|
// CHECK: } // end sil function 'test_existential'
|
|
sil [ossa] @test_existential : $@convention(thin) (@in ConformingStruct) -> @out Proto {
|
|
bb0(%0 : $*Proto, %1 : $*ConformingStruct):
|
|
%2 = alloc_stack $Proto
|
|
%3 = init_existential_addr %2 : $*Proto, $ConformingStruct
|
|
copy_addr [take] %1 to [init] %3 : $*ConformingStruct
|
|
copy_addr [take] %2 to [init] %0 : $*Proto
|
|
dealloc_stack %2 : $*Proto
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
enum Either<Left, Right> {
|
|
case left(Left), right(Right)
|
|
}
|
|
|
|
public struct TestStruct {
|
|
@_hasStorage var e: Either<AddressOnlyPayload, Int>
|
|
}
|
|
|
|
struct AddressOnlyPayload {
|
|
@_hasStorage let a: Any
|
|
@_hasStorage let i: Int
|
|
}
|
|
|
|
// There should only be a single copy_addr after optimization.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @test_initialize_struct :
|
|
// CHECK: bb0(%0 : $*TestStruct, %1 : $*Any, %2 : $Int):
|
|
// CHECK-NEXT: [[E:%[0-9]+]] = struct_element_addr %0
|
|
// CHECK-NEXT: [[LEFT:%[0-9]+]] = init_enum_data_addr [[E]]
|
|
// CHECK-NEXT: [[A:%[0-9]+]] = struct_element_addr [[LEFT]]
|
|
// CHECK-NEXT: copy_addr [take] %1 to [init] [[A]]
|
|
// CHECK-NEXT: [[I:%[0-9]+]] = struct_element_addr [[LEFT]]
|
|
// CHECK-NEXT: store %2 to [trivial] [[I]]
|
|
// CHECK-NEXT: inject_enum_addr [[E]]
|
|
// CHECK-NOT: copy_addr
|
|
// CHECK: } // end sil function 'test_initialize_struct'
|
|
sil [ossa] @test_initialize_struct : $@convention(method) (@in Any, Int) -> @out TestStruct {
|
|
bb0(%0 : $*TestStruct, %1 : $*Any, %2 : $Int):
|
|
%3 = alloc_stack $TestStruct
|
|
%4 = alloc_stack $Either<AddressOnlyPayload, Int>
|
|
%5 = alloc_stack $AddressOnlyPayload
|
|
%6 = struct_element_addr %5 : $*AddressOnlyPayload, #AddressOnlyPayload.a
|
|
copy_addr [take] %1 to [init] %6 : $*Any
|
|
%8 = struct_element_addr %5 : $*AddressOnlyPayload, #AddressOnlyPayload.i
|
|
store %2 to [trivial] %8 : $*Int
|
|
%10 = init_enum_data_addr %4 : $*Either<AddressOnlyPayload, Int>, #Either.left!enumelt
|
|
copy_addr [take] %5 to [init] %10 : $*AddressOnlyPayload
|
|
inject_enum_addr %4 : $*Either<AddressOnlyPayload, Int>, #Either.left!enumelt
|
|
dealloc_stack %5 : $*AddressOnlyPayload
|
|
%14 = struct_element_addr %3 : $*TestStruct, #TestStruct.e
|
|
copy_addr [take] %4 to [init] %14 : $*Either<AddressOnlyPayload, Int>
|
|
dealloc_stack %4 : $*Either<AddressOnlyPayload, Int>
|
|
copy_addr %3 to [init] %0 : $*TestStruct
|
|
destroy_addr %3 : $*TestStruct
|
|
dealloc_stack %3 : $*TestStruct
|
|
%20 = tuple ()
|
|
return %20 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @bail_on_write_to_dest :
|
|
// CHECK: alloc_stack
|
|
// CHECK: copy_addr
|
|
// CHECK: copy_addr
|
|
// CHECK: } // end sil function 'bail_on_write_to_dest'
|
|
sil [ossa] @bail_on_write_to_dest : $@convention(thin) (@inout Optional<Any>, @in Any) -> () {
|
|
bb0(%0 : $*Optional<Any>, %1 : $*Any):
|
|
%2 = alloc_stack $Optional<Any>
|
|
%3 = init_enum_data_addr %2 : $*Optional<Any>, #Optional.some!enumelt
|
|
copy_addr [take] %1 to [init] %3 : $*Any
|
|
inject_enum_addr %2 : $*Optional<Any>, #Optional.some!enumelt
|
|
destroy_addr %0 : $*Optional<Any>
|
|
copy_addr [take] %2 to [init] %0 : $*Optional<Any>
|
|
dealloc_stack %2 : $*Optional<Any>
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @write_to_dest_ok_if_before_liverange :
|
|
// CHECK: bb0(%0 : $*Optional<Any>, %1 : $*Any):
|
|
// CHECK-NEXT: destroy_addr
|
|
// CHECK-NEXT: init_enum_data_addr
|
|
// CHECK-NEXT: copy_addr
|
|
// CHECK-NEXT: inject_enum_addr
|
|
// CHECK-NOT: copy_addr
|
|
// CHECK: } // end sil function 'write_to_dest_ok_if_before_liverange'
|
|
sil [ossa] @write_to_dest_ok_if_before_liverange : $@convention(thin) (@inout Optional<Any>, @in Any) -> () {
|
|
bb0(%0 : $*Optional<Any>, %1 : $*Any):
|
|
%2 = alloc_stack $Optional<Any>
|
|
destroy_addr %0 : $*Optional<Any>
|
|
%3 = init_enum_data_addr %2 : $*Optional<Any>, #Optional.some!enumelt
|
|
copy_addr [take] %1 to [init] %3 : $*Any
|
|
inject_enum_addr %2 : $*Optional<Any>, #Optional.some!enumelt
|
|
copy_addr [take] %2 to [init] %0 : $*Optional<Any>
|
|
dealloc_stack %2 : $*Optional<Any>
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
enum Enum {
|
|
case A(Optional<Any>), B
|
|
}
|
|
|
|
struct StructWithEnum : Proto {
|
|
@_hasStorage let e: Enum
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @move_projections :
|
|
// CHECK: bb0(%0 : $*any Proto, %1 : $*Any):
|
|
// CHECK-NEXT: [[S:%[0-9]+]] = init_existential_addr %0 : $*any Proto, $StructWithEnum
|
|
// CHECK-NEXT: [[E:%[0-9]+]] = struct_element_addr [[S]] : $*StructWithEnum, #StructWithEnum.e
|
|
// CHECK-NEXT: [[ENUMA:%[0-9]+]] = init_enum_data_addr [[E]] : $*Enum, #Enum.A!enumelt
|
|
// CHECK-NEXT: [[OPTIONAL:%[0-9]+]] = init_enum_data_addr [[ENUMA]] : $*Optional<Any>, #Optional.some!enumelt
|
|
// CHECK-NEXT: copy_addr [take] %1 to [init] [[OPTIONAL]] : $*Any
|
|
// CHECK-NEXT: inject_enum_addr [[ENUMA]] : $*Optional<Any>, #Optional.some!enumelt
|
|
// CHECK-NEXT: inject_enum_addr [[E]] : $*Enum, #Enum.A!enumelt
|
|
// CHECK-NOT: copy_addr
|
|
// CHECK: } // end sil function 'move_projections'
|
|
sil [ossa] @move_projections : $@convention(thin) (@in Any) -> @out Proto {
|
|
bb0(%0 : $*Proto, %1 : $*Any):
|
|
%2 = alloc_stack $Optional<Any>
|
|
%3 = init_enum_data_addr %2 : $*Optional<Any>, #Optional.some!enumelt
|
|
copy_addr [take] %1 to [init] %3 : $*Any
|
|
inject_enum_addr %2 : $*Optional<Any>, #Optional.some!enumelt
|
|
%4 = init_existential_addr %0 : $*Proto, $StructWithEnum
|
|
%5 = struct_element_addr %4 : $*StructWithEnum, #StructWithEnum.e
|
|
%6 = init_enum_data_addr %5 : $*Enum, #Enum.A!enumelt
|
|
copy_addr [take] %2 to [init] %6 : $*Optional<Any>
|
|
inject_enum_addr %5 : $*Enum, #Enum.A!enumelt
|
|
dealloc_stack %2 : $*Optional<Any>
|
|
%10 = tuple ()
|
|
return %10 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @cant_move_projections :
|
|
// CHECK: alloc_stack
|
|
// CHECK: copy_addr
|
|
// CHECK: load
|
|
// CHECK: copy_addr
|
|
// CHECK: } // end sil function 'cant_move_projections'
|
|
sil [ossa] @cant_move_projections : $@convention(thin) (@in Any, @in_guaranteed Builtin.RawPointer) -> () {
|
|
bb0(%0 : $*Any, %1 : $*Builtin.RawPointer):
|
|
%2 = alloc_stack $Optional<Any>
|
|
%3 = init_enum_data_addr %2 : $*Optional<Any>, #Optional.some!enumelt
|
|
copy_addr [take] %0 to [init] %3 : $*Any
|
|
inject_enum_addr %2 : $*Optional<Any>, #Optional.some!enumelt
|
|
%4 = load [trivial] %1 : $*Builtin.RawPointer
|
|
%5 = pointer_to_address %4 : $Builtin.RawPointer to $*Optional<Any>
|
|
copy_addr [take] %2 to [init] %5 : $*Optional<Any>
|
|
dealloc_stack %2 : $*Optional<Any>
|
|
%10 = tuple ()
|
|
return %10 : $()
|
|
}
|
|
|
|
sil [ossa] @init_optional : $@convention(thin) () -> @out Optional<Any>
|
|
|
|
// CHECK-LABEL: sil [ossa] @instructions_after_copy_addr :
|
|
// CHECK: alloc_stack
|
|
// CHECK: copy_addr
|
|
// CHECK: copy_addr
|
|
// CHECK: apply
|
|
// CHECK: } // end sil function 'instructions_after_copy_addr'
|
|
sil [ossa] @instructions_after_copy_addr : $@convention(thin) (@in Any) -> @out Optional<Any> {
|
|
bb0(%0 : $*Optional<Any>, %1 : $*Any):
|
|
%2 = alloc_stack $Optional<Any>
|
|
%3 = init_enum_data_addr %2 : $*Optional<Any>, #Optional.some!enumelt
|
|
copy_addr [take] %1 to [init] %3 : $*Any
|
|
inject_enum_addr %2 : $*Optional<Any>, #Optional.some!enumelt
|
|
copy_addr [take] %2 to [init] %0 : $*Optional<Any>
|
|
%4 = function_ref @init_optional : $@convention(thin) () -> @out Optional<Any>
|
|
%5 = apply %4(%2) : $@convention(thin) () -> @out Optional<Any>
|
|
destroy_addr %2 : $*Optional<Any>
|
|
dealloc_stack %2 : $*Optional<Any>
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_optimize_swap :
|
|
// CHECK: alloc_stack
|
|
// CHECK: copy_addr
|
|
// CHECK: copy_addr
|
|
// CHECK: copy_addr
|
|
// CHECK: dealloc_stack
|
|
// CHECK: } // end sil function 'dont_optimize_swap'
|
|
sil [ossa] @dont_optimize_swap : $@convention(thin) <T> (@inout T, @inout T) -> () {
|
|
bb0(%0 : $*T, %1 : $*T):
|
|
%2 = alloc_stack $T
|
|
copy_addr [take] %0 to [init] %2 : $*T
|
|
copy_addr [take] %1 to [init] %0 : $*T
|
|
copy_addr [take] %2 to [init] %1 : $*T
|
|
dealloc_stack %2 : $*T
|
|
%78 = tuple ()
|
|
return %78 : $()
|
|
}
|
|
|
|
class Child { }
|
|
|
|
struct Parent {
|
|
var c : Child
|
|
}
|
|
|
|
sil @gen_child : $@convention(thin) () -> @out Child
|
|
|
|
// Check that alias analysis is invalidated correctly and that the pass does
|
|
// not produce invalid SIL (which would trigger a MemoryLifetime failure).
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @invalidateAliasAnalysis :
|
|
// CHECK: copy_addr
|
|
// CHECK: } // end sil function 'invalidateAliasAnalysis'
|
|
sil [ossa] @invalidateAliasAnalysis : $@convention(thin) (@owned Child) -> () {
|
|
bb0(%0 :@owned $Child):
|
|
%2 = alloc_stack $Parent
|
|
%4 = alloc_stack $Child
|
|
store %0 to [init] %4 : $*Child
|
|
%7 = alloc_stack $Child
|
|
%func = function_ref @gen_child : $@convention(thin) () -> @out Child
|
|
%10 = apply %func(%7) : $@convention(thin)() -> @out Child
|
|
%11 = struct_element_addr %2 : $*Parent, #Parent.c
|
|
copy_addr [take] %7 to [init] %11 : $*Child
|
|
dealloc_stack %7 : $*Child
|
|
copy_addr [take] %4 to %11 : $*Child
|
|
%17 = tuple ()
|
|
dealloc_stack %4 : $*Child
|
|
destroy_addr %2 : $*Parent
|
|
dealloc_stack %2 : $*Parent
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @cleanup_debuginsts :
|
|
// CHECK: copy_addr [take]
|
|
// CHECK-NOT: debug_value {{.*}} expr op_deref
|
|
// CHECK-LABEL: } // end sil function 'cleanup_debuginsts'
|
|
sil [ossa] @cleanup_debuginsts : $@convention(thin) <T> (@in T) -> () {
|
|
bb0(%0 : $*T):
|
|
%2 = alloc_stack $T
|
|
debug_value %0 : $*T, expr op_deref
|
|
copy_addr %0 to [init] %2 : $*T
|
|
debug_value %0 : $*T, expr op_deref
|
|
destroy_addr %0 : $*T
|
|
destroy_addr %2 : $*T
|
|
dealloc_stack %2 : $*T
|
|
%78 = tuple ()
|
|
return %78 : $()
|
|
}
|
|
|
|
sil @createAny : $@convention(thin) () -> @out Any
|
|
sil @createAny_no_barrier : $@convention(thin) () -> @out Any {
|
|
[global:]
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_deinit_barrier :
|
|
// CHECK: copy_addr [take]
|
|
// CHECK-LABEL: } // end sil function 'test_deinit_barrier'
|
|
sil [ossa] @test_deinit_barrier : $@convention(thin) (@guaranteed Any, @inout Any) -> () {
|
|
bb0(%0 : @guaranteed $Any, %1 : $*Any):
|
|
%2 = alloc_stack $Any
|
|
%4 = function_ref @createAny : $@convention(thin) () -> @out Any
|
|
%5 = apply %4(%2) : $@convention(thin) () -> @out Any
|
|
copy_addr [take] %2 to %1 : $*Any
|
|
dealloc_stack %2 : $*Any
|
|
%11 = tuple ()
|
|
return %11 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_no_deinit_barrier :
|
|
// CHECK-NOT: copy_addr
|
|
// CHECK-LABEL: } // end sil function 'test_no_deinit_barrier'
|
|
sil [ossa] @test_no_deinit_barrier : $@convention(thin) (@guaranteed Any, @inout Any) -> () {
|
|
bb0(%0 : @guaranteed $Any, %1 : $*Any):
|
|
%2 = alloc_stack $Any
|
|
%4 = function_ref @createAny_no_barrier : $@convention(thin) () -> @out Any
|
|
%5 = apply %4(%2) : $@convention(thin) () -> @out Any
|
|
copy_addr [take] %2 to %1 : $*Any
|
|
dealloc_stack %2 : $*Any
|
|
%11 = tuple ()
|
|
return %11 : $()
|
|
}
|
|
|
|
sil [readnone] @createAny_effects : $@convention(thin) () -> @out Any
|
|
sil [readnone] @createAny_no_barrier_effects : $@convention(thin) () -> @out Any {
|
|
[global:]
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_deinit_barrier_effects :
|
|
// CHECK: copy_addr [take]
|
|
// CHECK-LABEL: } // end sil function 'test_deinit_barrier_effects'
|
|
sil [ossa] @test_deinit_barrier_effects : $@convention(thin) (@guaranteed Any, @inout Any) -> () {
|
|
bb0(%0 : @guaranteed $Any, %1 : $*Any):
|
|
%2 = alloc_stack $Any
|
|
%4 = function_ref @createAny_effects : $@convention(thin) () -> @out Any
|
|
%5 = apply %4(%2) : $@convention(thin) () -> @out Any
|
|
copy_addr [take] %2 to %1 : $*Any
|
|
dealloc_stack %2 : $*Any
|
|
%11 = tuple ()
|
|
return %11 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_no_deinit_barrier_effects :
|
|
// CHECK-NOT: copy_addr
|
|
// CHECK-LABEL: } // end sil function 'test_no_deinit_barrier_effects'
|
|
sil [ossa] @test_no_deinit_barrier_effects : $@convention(thin) (@guaranteed Any, @inout Any) -> () {
|
|
bb0(%0 : @guaranteed $Any, %1 : $*Any):
|
|
%2 = alloc_stack $Any
|
|
%4 = function_ref @createAny_no_barrier_effects : $@convention(thin) () -> @out Any
|
|
%5 = apply %4(%2) : $@convention(thin) () -> @out Any
|
|
copy_addr [take] %2 to %1 : $*Any
|
|
dealloc_stack %2 : $*Any
|
|
%11 = tuple ()
|
|
return %11 : $()
|
|
}
|
|
|
|
struct TwoFields {
|
|
var a: Child
|
|
var b: Child
|
|
}
|
|
|
|
sil @no_read : $@convention(thin) (@in_guaranteed TwoFields) -> @out Child {
|
|
[%0: write v**]
|
|
[global: ]
|
|
}
|
|
sil @no_reads : $@convention(thin) (@in_guaranteed Child, @in_guaranteed TwoFields) -> () {
|
|
[global: ]
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @argument_aliasing :
|
|
// CHECK: %1 = alloc_stack
|
|
// CHECK: apply %{{[0-9]+}}(%1, %0)
|
|
// CHECK-LABEL: } // end sil function 'argument_aliasing'
|
|
sil [ossa] @argument_aliasing : $@convention(thin) (@inout TwoFields) -> () {
|
|
bb0(%0 : $*TwoFields):
|
|
%1 = alloc_stack $Child
|
|
%2 = function_ref @no_read : $@convention(thin) (@in_guaranteed TwoFields) -> @out Child
|
|
%3 = apply %2(%1, %0) : $@convention(thin) (@in_guaranteed TwoFields) -> @out Child
|
|
%4 = struct_element_addr %0, #TwoFields.a
|
|
copy_addr [take] %1 to %4
|
|
dealloc_stack %1
|
|
%7 = tuple ()
|
|
return %7
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @no_argument_aliasing :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK: [[A:%.*]] = struct_element_addr %0 : $*TwoFields, #TwoFields.a
|
|
// CHECK-NEXT: destroy_addr [[A]]
|
|
// CHECK: apply %{{[0-9]+}}([[A]], %1)
|
|
// CHECK-NOT: copy_addr
|
|
// CHECK-LABEL: } // end sil function 'no_argument_aliasing'
|
|
sil [ossa] @no_argument_aliasing : $@convention(thin) (@inout TwoFields, @inout TwoFields) -> () {
|
|
bb0(%0 : $*TwoFields, %1 : $*TwoFields):
|
|
%2 = alloc_stack $Child
|
|
%3 = function_ref @no_read : $@convention(thin) (@in_guaranteed TwoFields) -> @out Child
|
|
%4 = apply %3(%2, %1) : $@convention(thin) (@in_guaranteed TwoFields) -> @out Child
|
|
%5 = struct_element_addr %0, #TwoFields.a
|
|
copy_addr [take] %2 to %5
|
|
dealloc_stack %2
|
|
%8 = tuple ()
|
|
return %8
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @guaranteed_argument_aliasing :
|
|
// CHECK: alloc_stack
|
|
// CHECK: copy_addr
|
|
// CHECK-LABEL: } // end sil function 'guaranteed_argument_aliasing'
|
|
sil [ossa] @guaranteed_argument_aliasing : $@convention(thin) (@inout TwoFields, @owned Child) -> () {
|
|
bb0(%0 : $*TwoFields, %1 : @owned $Child):
|
|
%2 = alloc_stack $Child
|
|
store %1 to [init] %2
|
|
%3 = function_ref @no_reads : $@convention(thin) (@in_guaranteed Child, @in_guaranteed TwoFields) -> ()
|
|
%4 = apply %3(%2, %0) : $@convention(thin) (@in_guaranteed Child, @in_guaranteed TwoFields) -> ()
|
|
%5 = struct_element_addr %0, #TwoFields.a
|
|
copy_addr [take] %2 to %5
|
|
dealloc_stack %2
|
|
%8 = tuple ()
|
|
return %8
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @multi_block :
|
|
// CHECK: bb0({{.*}}):
|
|
// CHECK-NEXT: [[SA:%.*]] = struct_element_addr %0
|
|
// CHECK-NEXT: destroy_addr [[SA]]
|
|
// CHECK-NEXT: cond_br
|
|
// CHECK: bb1:
|
|
// CHECK: store {{.*}} to [init] [[SA]]
|
|
// CHECK: bb2:
|
|
// CHECK: store {{.*}} to [init] [[SA]]
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
// CHECK-LABEL: } // end sil function 'multi_block'
|
|
sil [ossa] @multi_block : $@convention(thin) (@inout TwoFields, @guaranteed Child, @guaranteed Child) -> () {
|
|
bb0(%0 : $*TwoFields, %1 : @guaranteed $Child, %2 : @guaranteed $Child):
|
|
%3 = alloc_stack $Child
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%5 = copy_value %1
|
|
store %5 to [init] %3
|
|
br bb3
|
|
|
|
bb2:
|
|
%8 = copy_value %2
|
|
store %8 to [init] %3
|
|
br bb3
|
|
|
|
bb3:
|
|
%11 = struct_element_addr %0, #TwoFields.a
|
|
copy_addr [take] %3 to %11
|
|
dealloc_stack %3
|
|
%14 = tuple ()
|
|
return %14
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @multi_block_with_mutation :
|
|
// CHECK: bb0({{.*}}):
|
|
// CHECK-NEXT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'multi_block_with_mutation'
|
|
sil [ossa] @multi_block_with_mutation : $@convention(thin) (@inout TwoFields, @guaranteed Child, @guaranteed Child) -> () {
|
|
bb0(%0 : $*TwoFields, %1 : @guaranteed $Child, %2 : @guaranteed $Child):
|
|
%3 = alloc_stack $Child
|
|
%4 = struct_element_addr %0, #TwoFields.a
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%5 = copy_value %1
|
|
store %5 to [init] %3
|
|
br bb3
|
|
|
|
bb2:
|
|
%8 = copy_value %2
|
|
store %8 to [init] %3
|
|
%10 = copy_value %2
|
|
store %10 to [assign] %4
|
|
br bb3
|
|
|
|
bb3:
|
|
copy_addr [take] %3 to %4
|
|
dealloc_stack %3
|
|
%14 = tuple ()
|
|
return %14
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @multi_block_with_multiple_deallocs :
|
|
// CHECK: bb0({{.*}}):
|
|
// CHECK-NEXT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'multi_block_with_multiple_deallocs'
|
|
sil [ossa] @multi_block_with_multiple_deallocs : $@convention(thin) (@inout TwoFields, @guaranteed Child, @guaranteed Child) -> () {
|
|
bb0(%0 : $*TwoFields, %1 : @guaranteed $Child, %2 : @guaranteed $Child):
|
|
%3 = alloc_stack $Child
|
|
%4 = struct_element_addr %0, #TwoFields.a
|
|
%5 = struct_element_addr %0, #TwoFields.b
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%6 = copy_value %1
|
|
store %6 to [init] %3
|
|
copy_addr [take] %3 to %4
|
|
dealloc_stack %3
|
|
br bb3
|
|
|
|
bb2:
|
|
%8 = copy_value %2
|
|
store %8 to [init] %3
|
|
copy_addr [take] %3 to %5
|
|
dealloc_stack %3
|
|
br bb3
|
|
|
|
bb3:
|
|
%14 = tuple ()
|
|
return %14
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @copy_addr_not_in_dealloc_block :
|
|
// CHECK: bb0({{.*}}):
|
|
// CHECK-NEXT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'copy_addr_not_in_dealloc_block'
|
|
sil [ossa] @copy_addr_not_in_dealloc_block : $@convention(thin) (@inout TwoFields, @guaranteed Child, @guaranteed Child) -> () {
|
|
bb0(%0 : $*TwoFields, %1 : @guaranteed $Child, %2 : @guaranteed $Child):
|
|
%3 = alloc_stack $Child
|
|
%4 = struct_element_addr %0, #TwoFields.a
|
|
%5 = struct_element_addr %0, #TwoFields.b
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%6 = copy_value %1
|
|
store %6 to [init] %3
|
|
copy_addr [take] %3 to %4
|
|
br bb3
|
|
|
|
bb2:
|
|
%8 = copy_value %2
|
|
store %8 to [init] %3
|
|
copy_addr [take] %3 to %5
|
|
br bb3
|
|
|
|
bb3:
|
|
dealloc_stack %3
|
|
%14 = tuple ()
|
|
return %14
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @empty :
|
|
// CHECK: bb0({{.*}}):
|
|
// CHECK-NEXT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'empty'
|
|
sil [ossa] @empty : $@convention(thin) () -> @out () {
|
|
bb0(%0 : $*()):
|
|
%1 = alloc_stack $()
|
|
copy_addr [take] %1 to %0
|
|
dealloc_stack %1
|
|
%4 = tuple ()
|
|
return %4
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @load_store :
|
|
// CHECK: bb0({{.*}}):
|
|
// CHECK-NEXT: [[A:%.*]] = struct_element_addr %0 : $*TwoFields, #TwoFields.a
|
|
// CHECK-NEXT: destroy_addr [[A]]
|
|
// CHECK-NEXT: store %1 to [init] [[A]]
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
// CHECK-LABEL: } // end sil function 'load_store'
|
|
sil [ossa] @load_store : $@convention(thin) (@inout TwoFields, @owned Child) -> () {
|
|
bb0(%0 : $*TwoFields, %1 : @owned $Child):
|
|
%2 = alloc_stack $Child
|
|
store %1 to [init] %2
|
|
%4 = load [take] %2
|
|
dealloc_stack %2
|
|
%6 = struct_element_addr %0, #TwoFields.a
|
|
store %4 to [assign] %6
|
|
%8 = tuple ()
|
|
return %8
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @load_store_with_mutation :
|
|
// CHECK: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'load_store_with_mutation'
|
|
sil [ossa] @load_store_with_mutation : $@convention(thin) (@inout TwoFields, @owned Child, @owned TwoFields) -> () {
|
|
bb0(%0 : $*TwoFields, %1 : @owned $Child, %2 : @owned $TwoFields):
|
|
%3 = alloc_stack $Child
|
|
store %1 to [init] %3
|
|
%4 = load [take] %3
|
|
dealloc_stack %3
|
|
%6 = struct_element_addr %0, #TwoFields.a
|
|
store %2 to [assign] %0
|
|
store %4 to [assign] %6
|
|
%8 = tuple ()
|
|
return %8
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @load_store_trivial :
|
|
// CHECK: bb0({{.*}}):
|
|
// CHECK-NEXT: store %1 to [trivial] %0
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
// CHECK-LABEL: } // end sil function 'load_store_trivial'
|
|
sil [ossa] @load_store_trivial : $@convention(thin) (@inout Int, Int) -> () {
|
|
bb0(%0 : $*Int, %1 : $Int):
|
|
%2 = alloc_stack $Int
|
|
store %1 to [trivial] %2
|
|
%4 = load [trivial] %2
|
|
dealloc_stack %2
|
|
store %4 to [trivial] %0
|
|
%8 = tuple ()
|
|
return %8
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @copy_addr_trivial :
|
|
// CHECK: bb0({{.*}}):
|
|
// CHECK-NEXT: store %1 to [trivial] %0
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
// CHECK-LABEL: } // end sil function 'copy_addr_trivial'
|
|
sil [ossa] @copy_addr_trivial : $@convention(thin) (@inout Int, Int) -> () {
|
|
bb0(%0 : $*Int, %1 : $Int):
|
|
%2 = alloc_stack $Int
|
|
store %1 to [trivial] %2
|
|
copy_addr %2 to %0
|
|
dealloc_stack %2
|
|
%8 = tuple ()
|
|
return %8
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @projections_outside_liverange :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'projections_outside_liverange'
|
|
sil [ossa] @projections_outside_liverange : $@convention(thin) (@guaranteed __ContiguousArrayStorageBase) -> () {
|
|
bb0(%0 : @guaranteed $__ContiguousArrayStorageBase):
|
|
%1 = alloc_stack $Int
|
|
%2 = ref_element_addr %0, #__ContiguousArrayStorageBase.countAndCapacity
|
|
%3 = struct_element_addr %2, #_ArrayBody._storage
|
|
%4 = struct_element_addr %3, #_SwiftArrayBodyStorage.count
|
|
%5 = struct_element_addr %4, #Int._value
|
|
%6 = load [trivial] %5
|
|
%7 = struct $Int (%6)
|
|
store %7 to [trivial] %1
|
|
%9 = load [trivial] %1
|
|
store %9 to [trivial] %4
|
|
dealloc_stack %1
|
|
%12 = tuple ()
|
|
return %12
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @destroy_before_copy :
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: destroy_addr
|
|
// CHECK-LABEL: } // end sil function 'destroy_before_copy'
|
|
sil [ossa] @destroy_before_copy : $@convention(thin) (@in_guaranteed Child) -> @out Child {
|
|
bb0(%0 : $*Child, %1 : $*Child):
|
|
%2 = alloc_stack $Child
|
|
copy_addr %1 to [init] %2
|
|
br bb1
|
|
|
|
bb1:
|
|
destroy_addr %2
|
|
copy_addr %1 to [init] %2
|
|
copy_addr %2 to [init] %0
|
|
br bb2
|
|
|
|
bb2:
|
|
copy_addr [take] %2 to %0
|
|
dealloc_stack %2
|
|
%r = tuple ()
|
|
return %r
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_propagate_with_access_scope :
|
|
// CHECK: alloc_stack
|
|
// CHECK: copy_addr
|
|
// CHECK-LABEL: } // end sil function 'dont_propagate_with_access_scope'
|
|
sil [ossa] @dont_propagate_with_access_scope : $@convention(thin) (@inout Int, Int) -> () {
|
|
bb0(%0 : $*Int, %1 : $Int):
|
|
%2 = alloc_stack $Int
|
|
%3 = begin_access [modify] [dynamic] %2
|
|
store %1 to [trivial] %3
|
|
end_access %3
|
|
copy_addr %2 to %0
|
|
dealloc_stack %2
|
|
%8 = tuple ()
|
|
return %8
|
|
}
|
|
|