// RUN: %target-sil-opt -sil-print-types -wmo -stack-protection -enable-sil-verify-all %s | %FileCheck %s --check-prefix=CHECK --check-prefix=MODULE // RUN: %target-sil-opt -sil-print-types -function-stack-protection -enable-sil-verify-all %s | %FileCheck %s --check-prefix=CHECK --check-prefix=FUNCTION // RUN: %target-sil-opt -sil-print-types -wmo -stack-protection -enable-move-inout-stack-protector -enable-sil-verify-all %s | %FileCheck %s --check-prefix=CHECK --check-prefix=MOVE // REQUIRES: swift_in_compiler sil_stage canonical import Builtin import Swift class C { @_hasStorage var i: Int64 @_hasStorage var j: Int64 @_hasStorage var s: S } struct S { @_hasStorage var a: Int64 @_hasStorage var b: Int64 } sil @unknown : $@convention(thin) (Builtin.RawPointer) -> () sil @unknown_addr : $@convention(thin) (@in Int64) -> () // CHECK-LABEL: sil [stack_protection] @function_local_stack // CHECK-NOT: copy_addr // CHECK: } // end sil function 'function_local_stack' sil @function_local_stack : $@convention(thin) (Int64) -> () { bb0(%0 : $Int64): %1 = alloc_stack $Int64 %2 = address_to_pointer [stack_protection] %1 : $*Int64 to $Builtin.RawPointer %3 = pointer_to_address %2 : $Builtin.RawPointer to $*Int64 store %0 to %3 : $*Int64 dealloc_stack %1 : $*Int64 %r = tuple () return %r : $() } // CHECK-LABEL: sil @only_loads // CHECK-NOT: copy_addr // CHECK: } // end sil function 'only_loads' sil @only_loads : $@convention(thin) () -> Int64 { bb0: %1 = alloc_stack $Int64 %2 = address_to_pointer [stack_protection] %1 : $*Int64 to $Builtin.RawPointer %3 = pointer_to_address %2 : $Builtin.RawPointer to $*Int64 %4 = load %3 : $*Int64 dealloc_stack %1 : $*Int64 return %4 : $Int64 } // CHECK-LABEL: sil @copy_addr_src // CHECK: } // end sil function 'copy_addr_src' sil @copy_addr_src : $@convention(thin) () -> @out Int64 { bb0(%0 : $*Int64): %1 = alloc_stack $Int64 %2 = address_to_pointer [stack_protection] %1 : $*Int64 to $Builtin.RawPointer %3 = pointer_to_address %2 : $Builtin.RawPointer to $*Int64 copy_addr %3 to %0 : $*Int64 dealloc_stack %1 : $*Int64 %r = tuple () return %r : $() } // CHECK-LABEL: sil [stack_protection] @copy_addr_dst // CHECK: } // end sil function 'copy_addr_dst' sil @copy_addr_dst : $@convention(thin) (@in Int64) -> () { bb0(%0 : $*Int64): %1 = alloc_stack $Int64 %2 = address_to_pointer [stack_protection] %1 : $*Int64 to $Builtin.RawPointer %3 = pointer_to_address %2 : $Builtin.RawPointer to $*Int64 copy_addr %0 to %3 : $*Int64 dealloc_stack %1 : $*Int64 %r = tuple () return %r : $() } // CHECK-LABEL: sil [stack_protection] @escaping_pointer // CHECK-NOT: copy_addr // CHECK: } // end sil function 'escaping_pointer' sil @escaping_pointer : $@convention(thin) () -> () { bb0: %1 = alloc_stack $Int64 %2 = address_to_pointer [stack_protection] %1 : $*Int64 to $Builtin.RawPointer %3 = function_ref @unknown : $@convention(thin) (Builtin.RawPointer) -> () apply %3(%2) : $@convention(thin) (Builtin.RawPointer) -> () dealloc_stack %1 : $*Int64 %r = tuple () return %r : $() } // CHECK-LABEL: sil @no_stack_protection_for_index_addr // CHECK-NOT: copy_addr // CHECK: } // end sil function 'no_stack_protection_for_index_addr' sil @no_stack_protection_for_index_addr : $@convention(thin) () -> () { bb0: %0 = alloc_stack $Int64 %1 = address_to_pointer %0 : $*Int64 to $Builtin.RawPointer %2 = integer_literal $Builtin.Word, 1 %3 = index_addr %0 : $*Int64, %2 : $Builtin.Word %4 = function_ref @unknown_addr : $@convention(thin) (@in Int64) -> () apply %4(%3) : $@convention(thin) (@in Int64) -> () dealloc_stack %0 : $*Int64 %r = tuple () return %r : $() } // CHECK-LABEL: sil [stack_protection] @stack_protection_for_index_addr // CHECK-NOT: copy_addr // CHECK: } // end sil function 'stack_protection_for_index_addr' sil @stack_protection_for_index_addr : $@convention(thin) () -> () { bb0: %0 = alloc_stack $Int64 %1 = address_to_pointer %0 : $*Int64 to $Builtin.RawPointer %2 = integer_literal $Builtin.Word, 1 %3 = index_addr [stack_protection] %0 : $*Int64, %2 : $Builtin.Word %4 = function_ref @unknown_addr : $@convention(thin) (@in Int64) -> () apply %4(%3) : $@convention(thin) (@in Int64) -> () dealloc_stack %0 : $*Int64 %r = tuple () return %r : $() } // CHECK-LABEL: sil @index_addr_with_only_loads // CHECK-NOT: copy_addr // CHECK: } // end sil function 'index_addr_with_only_loads' sil @index_addr_with_only_loads : $@convention(thin) () -> Int64 { bb0: %0 = alloc_stack $Int64 %1 = address_to_pointer %0 : $*Int64 to $Builtin.RawPointer %2 = integer_literal $Builtin.Word, 1 %3 = index_addr [stack_protection] %0 : $*Int64, %2 : $Builtin.Word %4 = load %3 : $*Int64 dealloc_stack %0 : $*Int64 return %4 : $Int64 } // CHECK-LABEL: sil [stack_protection] @stack_alloc_builtin // CHECK-NOT: copy_addr // CHECK: } // end sil function 'stack_alloc_builtin' sil @stack_alloc_builtin: $@convention(thin) () -> () { bb0: %0 = integer_literal $Builtin.Word, 8 %1 = builtin "stackAlloc"(%0 : $Builtin.Word, %0 : $Builtin.Word, %0 : $Builtin.Word) : $Builtin.RawPointer %2 = builtin "stackDealloc"(%1 : $Builtin.RawPointer) : $() %r = tuple () return %r : $() } // CHECK-LABEL: sil @unprotected_stack_alloc_builtin // CHECK-NOT: copy_addr // CHECK: } // end sil function 'unprotected_stack_alloc_builtin' sil @unprotected_stack_alloc_builtin: $@convention(thin) () -> () { bb0: %0 = integer_literal $Builtin.Word, 8 %1 = integer_literal $Builtin.Int1, 0 %2 = builtin "unprotectedStackAlloc"(%0 : $Builtin.Word, %0 : $Builtin.Word, %0 : $Builtin.Word, %1 : $Builtin.Int1) : $Builtin.RawPointer %3 = builtin "stackDealloc"(%2 : $Builtin.RawPointer) : $() %r = tuple () return %r : $() } // CHECK-LABEL: sil [stack_protection] @function_local_stack_obj // CHECK-NOT: copy_addr // CHECK: } // end sil function 'function_local_stack_obj' sil @function_local_stack_obj : $@convention(thin) () -> () { bb0: %0 = alloc_ref [stack] $C %1 = ref_element_addr %0 : $C, #C.i %2 = begin_access [modify] [static] %1 : $*Int64 %3 = address_to_pointer [stack_protection] %2 : $*Int64 to $Builtin.RawPointer %4 = function_ref @unknown : $@convention(thin) (Builtin.RawPointer) -> () apply %4(%3) : $@convention(thin) (Builtin.RawPointer) -> () end_access %2 : $*Int64 dealloc_stack_ref %0 : $C %r = tuple () return %r : $() } // CHECK-LABEL: sil @function_local_obj // CHECK-NOT: copy_addr // CHECK: } // end sil function 'function_local_obj' sil @function_local_obj : $@convention(thin) () -> () { bb0: %0 = alloc_ref $C %1 = ref_element_addr %0 : $C, #C.i %2 = begin_access [modify] [static] %1 : $*Int64 %3 = address_to_pointer [stack_protection] %2 : $*Int64 to $Builtin.RawPointer %4 = function_ref @unknown : $@convention(thin) (Builtin.RawPointer) -> () apply %4(%3) : $@convention(thin) (Builtin.RawPointer) -> () end_access %2 : $*Int64 strong_release %0 : $C %r = tuple () return %r : $() } // MOVE-LABEL: sil [stack_protection] @inout_with_unknown_callers1 // MODULE-LABEL: sil @inout_with_unknown_callers1 // MOVE: [[T:%[0-9]+]] = alloc_stack $Int64 // MOVE: copy_addr [take] %0 to [init] [[T]] : $*Int64 // MOVE: address_to_pointer [stack_protection] [[T]] // MOVE: copy_addr [take] [[T]] to [init] %0 : $*Int64 // MOVE: dealloc_stack [[T]] : $*Int64 // MODULE-NOT: alloc_stack // MODULE-NOT: copy_addr // CHECK-MODULE: address_to_pointer [stack_protection] %0 // CHECK: } // end sil function 'inout_with_unknown_callers1' sil @inout_with_unknown_callers1 : $@convention(thin) (@inout Int64) -> () { bb0(%0 : $*Int64): %1 = address_to_pointer [stack_protection] %0 : $*Int64 to $Builtin.RawPointer %2 = function_ref @unknown : $@convention(thin) (Builtin.RawPointer) -> () apply %2(%1) : $@convention(thin) (Builtin.RawPointer) -> () %r = tuple () return %r : $() } // CHECK-LABEL: sil @in_with_unknown_callers // CHECK: address_to_pointer [stack_protection] %0 // CHECK-NOT: copy_addr // CHECK: } // end sil function 'in_with_unknown_callers' sil @in_with_unknown_callers : $@convention(thin) (@in_guaranteed Int64) -> () { bb0(%0 : $*Int64): %1 = address_to_pointer [stack_protection] %0 : $*Int64 to $Builtin.RawPointer %2 = function_ref @unknown : $@convention(thin) (Builtin.RawPointer) -> () apply %2(%1) : $@convention(thin) (Builtin.RawPointer) -> () %r = tuple () return %r : $() } // MOVE-LABEL: sil [stack_protection] @inout_with_modify_access // MODULE-LABEL: sil @inout_with_modify_access // MOVE: [[A:%[0-9]+]] = begin_access [modify] [dynamic] %0 : $*Int64 // MOVE: [[T:%[0-9]+]] = alloc_stack $Int64 // MOVE: copy_addr [take] [[A]] to [init] [[T]] : $*Int64 // MOVE: address_to_pointer [stack_protection] [[T]] // MOVE: copy_addr [take] [[T]] to [init] [[A]] : $*Int64 // MOVE: dealloc_stack [[T]] : $*Int64 // MODULE-NOT: alloc_stack // MODULE-NOT: copy_addr // CHECK-MODULE: address_to_pointer [stack_protection] %0 // CHECK: } // end sil function 'inout_with_modify_access' sil @inout_with_modify_access : $@convention(thin) (@inout Int64) -> () { bb0(%0 : $*Int64): %1 = begin_access [modify] [dynamic] %0 : $*Int64 %2 = address_to_pointer [stack_protection] %1 : $*Int64 to $Builtin.RawPointer %3 = function_ref @unknown : $@convention(thin) (Builtin.RawPointer) -> () apply %3(%2) : $@convention(thin) (Builtin.RawPointer) -> () end_access %1 : $*Int64 %r = tuple () return %r : $() } // CHECK-LABEL: sil @inout_with_read_access // CHECK: [[A:%[0-9]+]] = begin_access [read] [dynamic] %0 : $*Int64 // CHECK: address_to_pointer [stack_protection] [[A]] // CHECK-NOT: copy_addr // CHECK: } // end sil function 'inout_with_read_access' sil @inout_with_read_access : $@convention(thin) (@inout Int64) -> () { bb0(%0 : $*Int64): %1 = begin_access [read] [dynamic] %0 : $*Int64 %2 = address_to_pointer [stack_protection] %1 : $*Int64 to $Builtin.RawPointer %3 = function_ref @unknown : $@convention(thin) (Builtin.RawPointer) -> () apply %3(%2) : $@convention(thin) (Builtin.RawPointer) -> () end_access %1 : $*Int64 %r = tuple () return %r : $() } // MOVE-LABEL: sil [stack_protection] @inout_with_unknown_callers2 // MODULE-LABEL: sil @inout_with_unknown_callers2 // MOVE: [[T:%[0-9]+]] = alloc_stack $S // MOVE: copy_addr [take] %0 to [init] [[T]] : $*S // MOVE: [[A:%[0-9]+]] = struct_element_addr [[T]] : $*S, #S.a // MOVE: address_to_pointer [stack_protection] [[A]] // MOVE: [[B:%[0-9]+]] = struct_element_addr [[T]] : $*S, #S.b // MOVE: address_to_pointer [stack_protection] [[B]] // MOVE: copy_addr [take] [[T]] to [init] %0 : $*S // MOVE: dealloc_stack [[T]] : $*S // MODULE-NOT: alloc_stack // MODULE-NOT: copy_addr // CHECK: } // end sil function 'inout_with_unknown_callers2' sil @inout_with_unknown_callers2 : $@convention(thin) (@inout S) -> () { bb0(%0 : $*S): %1 = struct_element_addr %0 : $*S, #S.a %2 = address_to_pointer [stack_protection] %1 : $*Int64 to $Builtin.RawPointer %3 = function_ref @unknown : $@convention(thin) (Builtin.RawPointer) -> () apply %3(%2) : $@convention(thin) (Builtin.RawPointer) -> () %5 = struct_element_addr %0 : $*S, #S.b %6 = address_to_pointer [stack_protection] %5 : $*Int64 to $Builtin.RawPointer apply %3(%6) : $@convention(thin) (Builtin.RawPointer) -> () %r = tuple () return %r : $() } // MOVE-LABEL: sil [stack_protection] @object_with_unknown_callers1 // MODULE-LABEL: sil @object_with_unknown_callers1 // MOVE: [[I:%[0-9]+]] = ref_element_addr %0 : $C, #C.i // MOVE: [[A:%[0-9]+]] = begin_access [modify] [static] [[I]] : $*Int64 // MOVE: [[T:%[0-9]+]] = alloc_stack $Int64 // MOVE: copy_addr [take] [[A]] to [init] [[T]] : $*Int64 // MOVE: address_to_pointer [stack_protection] [[T]] // MOVE: copy_addr [take] [[T]] to [init] [[A]] : $*Int64 // MOVE: dealloc_stack [[T]] : $*Int64 // MOVE: end_access [[A]] : $*Int64 // MODULE-NOT: alloc_stack // MODULE-NOT: copy_addr // CHECK: } // end sil function 'object_with_unknown_callers1' sil @object_with_unknown_callers1 : $@convention(thin) (@guaranteed C) -> () { bb0(%0 : $C): %1 = ref_element_addr %0 : $C, #C.i %2 = begin_access [modify] [static] %1 : $*Int64 %3 = address_to_pointer [stack_protection] %2 : $*Int64 to $Builtin.RawPointer %4 = function_ref @unknown : $@convention(thin) (Builtin.RawPointer) -> () apply %4(%3) : $@convention(thin) (Builtin.RawPointer) -> () end_access %2 : $*Int64 %r = tuple () return %r : $() } // MOVE-LABEL: sil [stack_protection] @object_with_unknown_callers2 // MODULE-LABEL: sil @object_with_unknown_callers2 // MOVE: [[I:%[0-9]+]] = ref_element_addr %0 : $C, #C.i // MOVE: [[A:%[0-9]+]] = begin_access [modify] [static] [[I]] : $*Int64 // MOVE: [[T:%[0-9]+]] = alloc_stack $Int64 // MOVE: copy_addr [take] [[A]] to [init] [[T]] : $*Int64 // MOVE: address_to_pointer [stack_protection] [[T]] // MOVE: address_to_pointer [stack_protection] [[T]] // MOVE: copy_addr [take] [[T]] to [init] [[A]] : $*Int64 // MOVE: dealloc_stack [[T]] : $*Int64 // MOVE: end_access [[A]] : $*Int64 // MODULE-NOT: alloc_stack // MODULE-NOT: copy_addr // CHECK: } // end sil function 'object_with_unknown_callers2' sil @object_with_unknown_callers2 : $@convention(thin) (@guaranteed C) -> () { bb0(%0 : $C): %1 = ref_element_addr %0 : $C, #C.i %2 = begin_access [modify] [static] %1 : $*Int64 %3 = address_to_pointer [stack_protection] %2 : $*Int64 to $Builtin.RawPointer %4 = function_ref @unknown : $@convention(thin) (Builtin.RawPointer) -> () apply %4(%3) : $@convention(thin) (Builtin.RawPointer) -> () %6 = address_to_pointer [stack_protection] %2 : $*Int64 to $Builtin.RawPointer apply %4(%6) : $@convention(thin) (Builtin.RawPointer) -> () end_access %2 : $*Int64 %r = tuple () return %r : $() } // MOVE-LABEL: sil [stack_protection] @object_with_unknown_callers3 // MODULE-LABEL: sil @object_with_unknown_callers3 // MOVE: [[I:%[0-9]+]] = ref_element_addr %0 : $C, #C.i // MOVE: [[AI:%[0-9]+]] = begin_access [modify] [static] [[I]] : $*Int64 // MOVE: [[TI:%[0-9]+]] = alloc_stack $Int64 // MOVE: copy_addr [take] [[AI]] to [init] [[TI]] : $*Int64 // MOVE: address_to_pointer [stack_protection] [[TI]] // MOVE: [[J:%[0-9]+]] = ref_element_addr %0 : $C, #C.j // MOVE: [[AJ:%[0-9]+]] = begin_access [modify] [static] [[J]] : $*Int64 // MOVE: [[TJ:%[0-9]+]] = alloc_stack $Int64 // MOVE: copy_addr [take] [[AJ]] to [init] [[TJ]] : $*Int64 // MOVE: copy_addr [take] [[TI]] to [init] [[AI]] : $*Int64 // MOVE: end_access [[AI]] : $*Int64 // MOVE: address_to_pointer [stack_protection] [[TJ]] // MOVE: copy_addr [take] [[TJ]] to [init] [[AJ]] : $*Int64 // MOVE: dealloc_stack [[TJ]] : $*Int64 // MOVE: dealloc_stack [[TI]] : $*Int64 // MOVE: end_access [[AJ]] : $*Int64 // MODULE-NOT: alloc_stack // MODULE-NOT: copy_addr // CHECK: } // end sil function 'object_with_unknown_callers3' sil @object_with_unknown_callers3 : $@convention(thin) (@guaranteed C) -> () { bb0(%0 : $C): %1 = ref_element_addr %0 : $C, #C.i // Accesses don't need to be properly nested. %2 = begin_access [modify] [static] %1 : $*Int64 %3 = address_to_pointer [stack_protection] %2 : $*Int64 to $Builtin.RawPointer %4 = function_ref @unknown : $@convention(thin) (Builtin.RawPointer) -> () apply %4(%3) : $@convention(thin) (Builtin.RawPointer) -> () %6 = ref_element_addr %0 : $C, #C.j %7 = begin_access [modify] [static] %6 : $*Int64 end_access %2 : $*Int64 %9 = address_to_pointer [stack_protection] %7 : $*Int64 to $Builtin.RawPointer apply %4(%9) : $@convention(thin) (Builtin.RawPointer) -> () end_access %7 : $*Int64 %r = tuple () return %r : $() } // CHECK-LABEL: sil @object_with_read_access // CHECK: [[I:%[0-9]+]] = ref_element_addr %0 : $C, #C.i // CHECK: [[A:%[0-9]+]] = begin_access [read] [static] [[I]] : $*Int64 // CHECK: address_to_pointer [stack_protection] [[A]] // CHECK-NOT: copy_addr // CHECK: end_access [[A]] : $*Int64 // CHECK: } // end sil function 'object_with_read_access' sil @object_with_read_access : $@convention(thin) (@guaranteed C) -> () { bb0(%0 : $C): %1 = ref_element_addr %0 : $C, #C.i %2 = begin_access [read] [static] %1 : $*Int64 %3 = address_to_pointer [stack_protection] %2 : $*Int64 to $Builtin.RawPointer %4 = function_ref @unknown : $@convention(thin) (Builtin.RawPointer) -> () apply %4(%3) : $@convention(thin) (Builtin.RawPointer) -> () end_access %2 : $*Int64 %r = tuple () return %r : $() } // CHECK-LABEL: sil hidden @known_callers_inout // CHECK-NOT: copy_addr // CHECK: } // end sil function 'known_callers_inout' sil hidden @known_callers_inout : $@convention(thin) (@inout Int64) -> () { bb0(%0 : $*Int64): %2 = integer_literal $Builtin.Int64, 2 %3 = struct $Int64 (%2 : $Builtin.Int64) %4 = integer_literal $Builtin.Word, 1 %5 = index_addr [stack_protection] %0 : $*Int64, %4 : $Builtin.Word store %3 to %5 : $*Int64 %7 = tuple () return %7 : $() } // MODULE-LABEL: sil [stack_protection] @call_internal_with_inout1 // FUNCTION-LABEL: sil @call_internal_with_inout1 // CHECK-NOT: copy_addr // CHECK: } // end sil function 'call_internal_with_inout1' sil @call_internal_with_inout1 : $@convention(thin) () -> () { bb0: %0 = alloc_stack [lexical] $Int64 %1 = function_ref @known_callers_inout : $@convention(thin) (@inout Int64) -> () %2 = apply %1(%0) : $@convention(thin) (@inout Int64) -> () dealloc_stack %0 : $*Int64 // Introduce a cycle in the call graph. %f = function_ref @call_internal_with_inout2 : $@convention(thin) () -> () %a = apply %f() : $@convention(thin) () -> () %4 = tuple () return %4 : $() } // MODULE-LABEL: sil [stack_protection] @call_internal_with_inout2 // FUNCTION-LABEL: sil @call_internal_with_inout2 // CHECK-NOT: copy_addr // CHECK: } // end sil function 'call_internal_with_inout2' sil @call_internal_with_inout2 : $@convention(thin) () -> () { bb0: %0 = alloc_stack [lexical] $Int64 %1 = function_ref @known_callers_inout : $@convention(thin) (@inout Int64) -> () %2 = apply %1(%0) : $@convention(thin) (@inout Int64) -> () dealloc_stack %0 : $*Int64 cond_br undef, bb1, bb2 bb1: // Introduce a cycle in the call graph. %f = function_ref @call_internal_with_inout1 : $@convention(thin) () -> () %a = apply %f() : $@convention(thin) () -> () br bb3 bb2: br bb3 bb3: %4 = tuple () return %4 : $() } // MOVE-LABEL: sil hidden [stack_protection] @unknown_callers // MODULE-LABEL: sil hidden @unknown_callers // MOVE: copy_addr // MOVE: copy_addr // MODULE-NOT: copy_addr // CHECK: } // end sil function 'unknown_callers' sil hidden @unknown_callers : $@convention(thin) (@inout Int64) -> () { bb0(%0 : $*Int64): %2 = integer_literal $Builtin.Int64, 2 %3 = struct $Int64 (%2 : $Builtin.Int64) %4 = integer_literal $Builtin.Word, 1 %5 = index_addr [stack_protection] %0 : $*Int64, %4 : $Builtin.Word store %3 to %5 : $*Int64 %7 = tuple () return %7 : $() } // CHECK-LABEL: sil @call_unknown_callers // CHECK-NOT: copy_addr // CHECK: } // end sil function 'call_unknown_callers' sil @call_unknown_callers : $@convention(thin) (@inout Int64) -> () { bb0(%0 : $*Int64): %1 = function_ref @unknown_callers : $@convention(thin) (@inout Int64) -> () %2 = apply %1(%0) : $@convention(thin) (@inout Int64) -> () %4 = tuple () return %4 : $() } // MOVE-LABEL: sil [stack_protection] @partially_known_callers // MODULE-LABEL: sil @partially_known_callers // MOVE: copy_addr // MOVE: copy_addr // MODULE-NOT: copy_addr // CHECK: } // end sil function 'partially_known_callers' sil @partially_known_callers : $@convention(thin) (@inout Int64) -> () { bb0(%0 : $*Int64): %1 = address_to_pointer [stack_protection] %0 : $*Int64 to $Builtin.RawPointer %2 = function_ref @unknown : $@convention(thin) (Builtin.RawPointer) -> () apply %2(%1) : $@convention(thin) (Builtin.RawPointer) -> () %4 = tuple () return %4 : $() } // MOVE-LABEL: sil @call_partially_known_callers // MODULE-LABEL: sil [stack_protection] @call_partially_known_callers // CHECK-NOT: copy_addr // CHECK: } // end sil function 'call_partially_known_callers' sil @call_partially_known_callers : $@convention(thin) () -> () { bb0: %0 = alloc_stack $Int64 %1 = function_ref @partially_known_callers : $@convention(thin) (@inout Int64) -> () %2 = apply %1(%0) : $@convention(thin) (@inout Int64) -> () dealloc_stack %0 : $*Int64 %4 = tuple () return %4 : $() } // CHECK-LABEL: sil hidden @known_callers_obj1 // CHECK-NOT: copy_addr // CHECK: } // end sil function 'known_callers_obj1' sil hidden @known_callers_obj1 : $@convention(thin) (@guaranteed C) -> () { bb0(%0 : $C): %1 = ref_element_addr %0 : $C, #C.i %2 = begin_access [modify] [static] %1 : $*Int64 %3 = address_to_pointer [stack_protection] %2 : $*Int64 to $Builtin.RawPointer %4 = function_ref @unknown : $@convention(thin) (Builtin.RawPointer) -> () apply %4(%3) : $@convention(thin) (Builtin.RawPointer) -> () end_access %2 : $*Int64 %7 = tuple () return %7 : $() } // MODULE-LABEL: sil [stack_protection] @call_internal_with_stack_obj // FUNCTION-LABEL: sil @call_internal_with_stack_obj // CHECK-NOT: copy_addr // CHECK: } // end sil function 'call_internal_with_stack_obj' sil @call_internal_with_stack_obj : $@convention(thin) () -> () { bb0: %0 = alloc_ref [stack] $C %1 = function_ref @known_callers_obj1 : $@convention(thin) (@guaranteed C) -> () %2 = apply %1(%0) : $@convention(thin) (@guaranteed C) -> () dealloc_stack_ref %0 : $C %4 = tuple () return %4 : $() } // CHECK-LABEL: sil @call_internal_with_heap_obj // CHECK-NOT: copy_addr // CHECK: } // end sil function 'call_internal_with_heap_obj' sil @call_internal_with_heap_obj : $@convention(thin) () -> () { bb0: cond_br undef, bb1, bb2 bb1: %0 = alloc_ref $C br bb3(%0 : $C) bb2: %2 = alloc_ref $C br bb3(%2 : $C) bb3(%5 : $C): %6 = function_ref @known_callers_obj1 : $@convention(thin) (@guaranteed C) -> () %7 = apply %6(%5) : $@convention(thin) (@guaranteed C) -> () strong_release %5 : $C %r = tuple () return %r : $() } // MOVE-LABEL: sil hidden [stack_protection] @known_callers_obj2 // MODULE-LABEL: sil hidden @known_callers_obj2 // MOVE: alloc_stack // MOVE: copy_addr // MOVE: copy_addr // MODULE-NOT: copy_addr // CHECK: } // end sil function 'known_callers_obj2' sil hidden @known_callers_obj2 : $@convention(thin) (@guaranteed C) -> () { bb0(%0 : $C): %1 = ref_element_addr %0 : $C, #C.i %2 = begin_access [modify] [static] %1 : $*Int64 %3 = address_to_pointer [stack_protection] %2 : $*Int64 to $Builtin.RawPointer %4 = function_ref @unknown : $@convention(thin) (Builtin.RawPointer) -> () apply %4(%3) : $@convention(thin) (Builtin.RawPointer) -> () end_access %2 : $*Int64 %7 = tuple () return %7 : $() } sil @create_obj : $@convention(thin) () -> @owned C // CHECK-LABEL: sil @call_known_callers_obj2 // CHECK-NOT: copy_addr // CHECK: } // end sil function 'call_known_callers_obj2' sil @call_known_callers_obj2 : $@convention(thin) () -> () { bb0: cond_br undef, bb1, bb2 bb1: %0 = alloc_ref $C br bb3(%0 : $C) bb2: %2 = function_ref @create_obj : $@convention(thin) () -> @owned C %3 = apply %2() : $@convention(thin) () -> @owned C br bb3(%3 : $C) bb3(%5 : $C): %6 = function_ref @known_callers_obj2 : $@convention(thin) (@guaranteed C) -> () %7 = apply %6(%5) : $@convention(thin) (@guaranteed C) -> () strong_release %5 : $C %r = tuple () return %r : $() } // CHECK-LABEL: sil private @closure_with_inout_capture // CHECK-NOT: copy_addr // CHECK: } // end sil function 'closure_with_inout_capture' sil private @closure_with_inout_capture : $@convention(thin) (@inout_aliasable Int64) -> () { bb0(%0 : $*Int64): %1 = address_to_pointer [stack_protection] %0 : $*Int64 to $Builtin.RawPointer %2 = function_ref @unknown : $@convention(thin) (Builtin.RawPointer) -> () apply %2(%1) : $@convention(thin) (Builtin.RawPointer) -> () %r = tuple () return %r : $() } sil @call_closure : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> () // MODULE-LABEL: sil [stack_protection] @test_closure_with_inout_capture // FUNCTION-LABEL: sil @test_closure_with_inout_capture // CHECK-NOT: copy_addr // CHECK: } // end sil function 'test_closure_with_inout_capture' sil @test_closure_with_inout_capture : $@convention(thin) () -> () { bb0: %2 = alloc_stack [lexical] $Int64 %3 = integer_literal $Builtin.Int64, 2 %4 = struct $Int64 (%3 : $Builtin.Int64) store %4 to %2 : $*Int64 %6 = function_ref @closure_with_inout_capture : $@convention(thin) (@inout_aliasable Int64) -> () %7 = partial_apply [callee_guaranteed] [on_stack] %6(%2) : $@convention(thin) (@inout_aliasable Int64) -> () %8 = function_ref @call_closure : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> () %9 = apply %8(%7) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> () dealloc_stack %7 : $@noescape @callee_guaranteed () -> () dealloc_stack %2 : $*Int64 %12 = tuple () return %12 : $() } // MOVE-LABEL: sil private [stack_protection] @closure_with_inout_arg // MODULE-LABEL: sil private @closure_with_inout_arg // MOVE: alloc_stack // MOVE: copy_addr // MOVE: copy_addr // MODULE-NOT: copy_addr // CHECK: } // end sil function 'closure_with_inout_arg' sil private @closure_with_inout_arg : $@convention(thin) (@inout Int64) -> () { bb0(%0 : $*Int64): %1 = address_to_pointer [stack_protection] %0 : $*Int64 to $Builtin.RawPointer %2 = function_ref @unknown : $@convention(thin) (Builtin.RawPointer) -> () apply %2(%1) : $@convention(thin) (Builtin.RawPointer) -> () %r = tuple () return %r : $() } sil @call_closure_with_arg : $@convention(thin) (@noescape @callee_guaranteed (@inout Int64) -> ()) -> () // CHECK-LABEL: sil @test_closure_with_inout_arg // CHECK-NOT: copy_addr // CHECK: } // end sil function 'test_closure_with_inout_arg' sil @test_closure_with_inout_arg : $@convention(thin) () -> () { bb0: %6 = function_ref @closure_with_inout_arg : $@convention(thin) (@inout Int64) -> () %7 = partial_apply [callee_guaranteed] [on_stack] %6() : $@convention(thin) (@inout Int64) -> () %8 = function_ref @call_closure_with_arg : $@convention(thin) (@noescape @callee_guaranteed (@inout Int64) -> ()) -> () %9 = apply %8(%7) : $@convention(thin) (@noescape @callee_guaranteed (@inout Int64) -> ()) -> () dealloc_stack %7 : $@noescape @callee_guaranteed (@inout Int64) -> () %12 = tuple () return %12 : $() } // CHECK-LABEL: sil @test_mem_intrinsics // CHECK-NOT: copy_addr // CHECK: } // end sil function 'test_mem_intrinsics' sil @test_mem_intrinsics : $@convention(thin) (Builtin.RawPointer, Int64) -> () { bb0(%0 : $Builtin.RawPointer, %1: $Int64): %2 = alloc_stack $Int64 store %1 to %2 : $*Int64 %4 = address_to_pointer [stack_protection] %2 : $*Int64 to $Builtin.RawPointer %5 = integer_literal $Builtin.Int64, 8 %6 = integer_literal $Builtin.Int1, 0 %7 = builtin "int_memcpy_RawPointer_RawPointer_Int64"(%0 : $Builtin.RawPointer, %4 : $Builtin.RawPointer, %5 : $Builtin.Int64, %6 : $Builtin.Int1) : $() %8 = builtin "int_memmove_RawPointer_RawPointer_Int64"(%0 : $Builtin.RawPointer, %4 : $Builtin.RawPointer, %5 : $Builtin.Int64, %6 : $Builtin.Int1) : $() dealloc_stack %2 : $*Int64 %10 = tuple () return %10 : $() }