// RUN: %target-sil-opt -enable-sil-verify-all %s -allocbox-to-stack -enable-copy-propagation=requested-passes-only | %FileCheck %s sil_stage raw import Builtin import Swift struct NonTrivialStruct: ~Copyable { var i: Builtin.Int32 } sil @use_nontrivialstruct : $@convention(thin) (@guaranteed NonTrivialStruct) -> () sil @consume_nontrivialstruct : $@convention(thin) (@owned NonTrivialStruct) -> () sil @get_nontrivialstruct : $@convention(thin) () -> @owned NonTrivialStruct sil [ossa] @host_markmustcheck_closure : $@convention(thin) (@guaranteed { var NonTrivialStruct }) -> () { bb0(%0 : @closureCapture @guaranteed ${ var NonTrivialStruct }): %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [ossa] @hoist_markmustcheck : $@convention(thin) (@owned NonTrivialStruct) -> () { // CHECK: bb0([[ARG:%.*]] : @owned // CHECK-NEXT: [[STACK1:%.*]] = alloc_stack $NonTrivialStruct // CHECK-NEXT: [[MARKED1:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[STACK1]] // CHECK-NEXT: store [[ARG]] to [init] [[MARKED1]] // CHECK-NEXT: [[LOADED_VALUE:%.*]] = load [take] [[MARKED1]] // CHECK-NEXT: [[STACK2:%.*]] = alloc_stack $NonTrivialStruct // CHECK-NEXT: [[MARKED2:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[STACK2]] // CHECK-NEXT: store [[LOADED_VALUE]] to [init] [[MARKED2]] // CHECK-NEXT: // function_ref // CHECK-NEXT: [[FUNC:%.*]] = function_ref @$s26host_markmustcheck_closureTf0s_n : $@convention(thin) (@inout_aliasable NonTrivialStruct) -> () // CHECK-NEXT: [[PA:%.*]] = partial_apply [callee_guaranteed] [[FUNC]]([[MARKED2]]) : $@convention(thin) (@inout_aliasable NonTrivialStruct) -> () // CHECK-NEXT: apply [[PA]]() // CHECK-NEXT: destroy_value [[PA]] // CHECK-NEXT: destroy_addr [[MARKED2]] // CHECK-NEXT: dealloc_stack [[STACK2]] // CHECK-NEXT: dealloc_stack [[STACK1]] // CHECK-NEXT: tuple () // CHECK-NEXT: return // CHECK: } // end sil function 'hoist_markmustcheck' sil [ossa] @hoist_markmustcheck : $@convention(thin) (@owned NonTrivialStruct) -> () { bb0(%0 : @owned $NonTrivialStruct): %1 = alloc_box ${ var NonTrivialStruct } %2 = project_box %1 : ${ var NonTrivialStruct }, 0 store %0 to [init] %2 : $*NonTrivialStruct %3 = project_box %1 : ${ var NonTrivialStruct }, 0 %3a = mark_unresolved_non_copyable_value [assignable_but_not_consumable] %3 : $*NonTrivialStruct %3b = load [take] %3a : $*NonTrivialStruct %4 = alloc_box ${ var NonTrivialStruct } %4a = project_box %4 : ${ var NonTrivialStruct }, 0 %4b = mark_unresolved_non_copyable_value [assignable_but_not_consumable] %4a : $*NonTrivialStruct store %3b to [init] %4b : $*NonTrivialStruct %f = function_ref @host_markmustcheck_closure : $@convention(thin) (@guaranteed { var NonTrivialStruct }) -> () %5c = copy_value %4 : ${ var NonTrivialStruct } %g = partial_apply [callee_guaranteed] %f(%5c) : $@convention(thin) (@guaranteed { var NonTrivialStruct }) -> () apply %g() : $@callee_guaranteed () -> () destroy_value %g : $@callee_guaranteed () -> () destroy_value %4 : ${ var NonTrivialStruct } dealloc_box %1 : ${ var NonTrivialStruct } %9999 = tuple() return %9999 : $() } // MARK: Test that we properly handle let alloc_box. // // CHECK-LABEL: sil hidden [ossa] @captured_let_allocstack_caller : $@convention(thin) () -> () { // CHECK: bb0: // CHECK: [[STACK:%.*]] = alloc_stack // CHECK: [[MARK:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[STACK]] // CHECK: partial_apply [callee_guaranteed] {{%.*}}([[MARK]]) : $@convention(thin) (@inout_aliasable NonTrivialStruct) -> () // CHECK: } // end sil function 'captured_let_allocstack_caller' // CHECK-LABEL: sil private [ossa] @$s31captured_let_allocstack_closureTf0s_n : $@convention(thin) (@inout_aliasable NonTrivialStruct) -> () { // CHECK: // [[ARG:.*]]{{ .*}}// user: [[MARK:%[0-9][0-9]*]] // CHECK: bb0([[ARG]] : @closureCapture $*NonTrivialStruct): // CHECK: [[MARK]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[ARG]] // CHECK: [[LOAD:%.*]] = load [copy] [[MARK]] // CHECK: [[VALUE:%.*]] = move_value [[LOAD]] // CHECK: destroy_value [[VALUE]] // CHECK: [[LOAD:%.*]] = load [copy] [[MARK]] // CHECK: [[VALUE:%.*]] = move_value [[LOAD]] // CHECK: destroy_value [[VALUE]] // CHECK: cond_br undef, [[LHS:bb[0-9]+]], [[RHS:bb[0-9]+]] // // CHECK: [[LHS]]: // CHECK: [[VALUE:%.*]] = load [copy] [[MARK]] // CHECK: apply {{%.*}}([[VALUE]]) : $@convention(thin) (@owned NonTrivialStruct) -> () // CHECK: [[VALUE:%.*]] = load_borrow [[MARK]] // CHECK: apply {{%.*}}([[VALUE]]) : $@convention(thin) (@guaranteed NonTrivialStruct) -> () // CHECK: } // end sil function 'captured_let_allocstack_closure' sil hidden [ossa] @captured_let_allocstack_caller : $@convention(thin) () -> () { bb0: %0 = alloc_box ${ let NonTrivialStruct }, let, name "x" %2 = function_ref @get_nontrivialstruct : $@convention(thin) () -> @owned NonTrivialStruct %3 = apply %2() : $@convention(thin) () -> @owned NonTrivialStruct %4 = project_box %0 : ${ let NonTrivialStruct }, 0 store %3 to [init] %4 : $*NonTrivialStruct %6 = function_ref @captured_let_allocstack_closure : $@convention(thin) (@guaranteed { let NonTrivialStruct }) -> () %7 = project_box %0 : ${ let NonTrivialStruct }, 0 %8 = copy_value %0 : ${ let NonTrivialStruct } mark_function_escape %7 : $*NonTrivialStruct %10 = partial_apply [callee_guaranteed] %6(%8) : $@convention(thin) (@guaranteed { let NonTrivialStruct }) -> () %11 = begin_borrow [lexical] %10 : $@callee_guaranteed () -> () debug_value %11 : $@callee_guaranteed () -> (), let, name "f" %13 = project_box %0 : ${ let NonTrivialStruct }, 0 %13a = mark_unresolved_non_copyable_value [assignable_but_not_consumable] %13 : $*NonTrivialStruct %14 = load_borrow %13a : $*NonTrivialStruct %15 = function_ref @use_nontrivialstruct : $@convention(thin) (@guaranteed NonTrivialStruct) -> () %16 = apply %15(%14) : $@convention(thin) (@guaranteed NonTrivialStruct) -> () end_borrow %14 : $NonTrivialStruct %18 = project_box %0 : ${ let NonTrivialStruct }, 0 %18a = mark_unresolved_non_copyable_value [assignable_but_not_consumable] %18 : $*NonTrivialStruct %19 = load [copy] %18a : $*NonTrivialStruct %20 = function_ref @consume_nontrivialstruct : $@convention(thin) (@owned NonTrivialStruct) -> () %21 = apply %20(%19) : $@convention(thin) (@owned NonTrivialStruct) -> () end_borrow %11 : $@callee_guaranteed () -> () destroy_value %10 : $@callee_guaranteed () -> () destroy_value %0 : ${ let NonTrivialStruct } %25 = tuple () return %25 : $() } sil private [ossa] @captured_let_allocstack_closure : $@convention(thin) (@guaranteed { let NonTrivialStruct }) -> () { bb0(%0 : @closureCapture @guaranteed ${ let NonTrivialStruct }): %1 = project_box %0 : ${ let NonTrivialStruct }, 0 %2 = mark_unresolved_non_copyable_value [assignable_but_not_consumable] %1 : $*NonTrivialStruct %3 = load [copy] %2 : $*NonTrivialStruct %4 = move_value %3 : $NonTrivialStruct destroy_value %4 : $NonTrivialStruct %6 = project_box %0 : ${ let NonTrivialStruct }, 0 %7 = mark_unresolved_non_copyable_value [assignable_but_not_consumable] %6 : $*NonTrivialStruct %8 = load [copy] %7 : $*NonTrivialStruct %9 = move_value %8 : $NonTrivialStruct destroy_value %9 : $NonTrivialStruct cond_br undef, bb1, bb2 bb1: %17 = project_box %0 : ${ let NonTrivialStruct }, 0 %18 = mark_unresolved_non_copyable_value [assignable_but_not_consumable] %17 : $*NonTrivialStruct %19 = load [copy] %18 : $*NonTrivialStruct %20 = function_ref @consume_nontrivialstruct : $@convention(thin) (@owned NonTrivialStruct) -> () %21 = apply %20(%19) : $@convention(thin) (@owned NonTrivialStruct) -> () %22 = project_box %0 : ${ let NonTrivialStruct }, 0 %23 = mark_unresolved_non_copyable_value [assignable_but_not_consumable] %22 : $*NonTrivialStruct %24 = load_borrow %23 : $*NonTrivialStruct %25 = function_ref @use_nontrivialstruct : $@convention(thin) (@guaranteed NonTrivialStruct) -> () %26 = apply %25(%24) : $@convention(thin) (@guaranteed NonTrivialStruct) -> () end_borrow %24 : $NonTrivialStruct br bb3 bb2: br bb3 bb3: %30 = tuple () return %30 : $() } // CHECK: sil hidden [ossa] @earlyallocbox_to_stack_partial_apply_test_caller : $@convention(thin) (@owned NonTrivialStruct) -> () { // CHECK: alloc_stack [lexical] $NonTrivialStruct, var, name "x" // CHECK: } // end sil function 'earlyallocbox_to_stack_partial_apply_test_caller' sil hidden [ossa] @earlyallocbox_to_stack_partial_apply_test_caller : $@convention(thin) (@owned NonTrivialStruct) -> () { bb0(%arg : @owned $NonTrivialStruct): %0 = alloc_box ${ var NonTrivialStruct }, var, name "x" %1 = begin_borrow [lexical] %0 : ${ var NonTrivialStruct } %2 = project_box %1 : ${ var NonTrivialStruct }, 0 store %arg to [init] %2 : $*NonTrivialStruct %15 = function_ref @earlyallocbox_to_stack_partial_apply_test_callee : $@convention(thin) (@guaranteed { var NonTrivialStruct }) -> () %16 = copy_value %1 : ${ var NonTrivialStruct } %18 = partial_apply [callee_guaranteed] %15(%16) : $@convention(thin) (@guaranteed { var NonTrivialStruct }) -> () destroy_value %18 : $@callee_guaranteed () -> () end_borrow %1 : ${ var NonTrivialStruct } destroy_value %0 : ${ var NonTrivialStruct } %24 = tuple () return %24 : $() } sil private [ossa] @earlyallocbox_to_stack_partial_apply_test_callee : $@convention(thin) (@guaranteed { var NonTrivialStruct }) -> () { bb0(%0 : @closureCapture @guaranteed ${ var NonTrivialStruct }): %1 = project_box %0 : ${ var NonTrivialStruct }, 0 debug_value %1 : $*NonTrivialStruct, var, name "x", argno 1, expr op_deref %3 = begin_access [read] [unknown] %1 : $*NonTrivialStruct %4 = mark_unresolved_non_copyable_value [no_consume_or_assign] %3 : $*NonTrivialStruct %5 = load [copy] %4 : $*NonTrivialStruct end_access %3 : $*NonTrivialStruct %7 = move_value %5 : $NonTrivialStruct destroy_value %7 : $NonTrivialStruct %9 = tuple () return %9 : $() }