// RUN: %target-sil-opt -enable-sil-verify-all %s -alloc-stack-hoisting | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-MERGING %s // RUN: %target-sil-opt -enable-sil-verify-all %s -alloc-stack-hoisting -sil-merge-stack-slots=false | %FileCheck %s sil_stage canonical import Builtin import Swift import SwiftShims protocol P { } struct Generic { var x : T } struct FixedSize { var x : Builtin.Int8 } // CHECK-LABEL: sil @hoist_generic // CHECK: bb0({{.*}}): // CHECK: [[AS:%.*]] = alloc_stack $T // CHECK: bb1: // CHECK-NOT: alloc_stack // CHECK-NOT: dealloc_stack // CHECK: bb2 // CHECK: bb3: // CHECK: dealloc_stack [[AS]] // CHECK: return sil @hoist_generic : $@convention(thin) (@in T, Builtin.Int1) -> () { bb0(%0 : $*T, %1: $Builtin.Int1): cond_br %1, bb1, bb2 bb1: %2 = alloc_stack $T copy_addr [take] %0 to [init] %2 : $*T destroy_addr %2 : $*T dealloc_stack %2 : $*T br bb3 bb2: destroy_addr %0 : $*T br bb3 bb3: %3 = tuple () return %3 : $() } sil @throwing_fun : $@convention(thin) () -> @error any Error // CHECK-LABEL: sil @hoist_generic // CHECK: bb0({{.*}}): // CHECK: [[AS:%.*]] = alloc_stack $T // CHECK: bb1: // CHECK-NOT: alloc_stack // CHECK-NOT: dealloc_stack // CHECK: bb2 // CHECK: bb3: // CHECK: try_apply // CHECK: bb4({{.*}}: // CHECK: dealloc_stack [[AS]] // CHECK: return // CHECK: bb5({{.*}}): // CHECK: dealloc_stack [[AS]] // CHECK: throw sil @hoist_generic_throwing : $@convention(thin) (@in T, Builtin.Int1) -> @error any Error { bb0(%0 : $*T, %1: $Builtin.Int1): cond_br %1, bb1, bb2 bb1: %2 = alloc_stack $T copy_addr [take] %0 to [init] %2 : $*T destroy_addr %2 : $*T dealloc_stack %2 : $*T br bb3 bb2: destroy_addr %0 : $*T br bb3 bb3: %3 = function_ref @throwing_fun : $@convention(thin) () -> @error any Error try_apply %3() : $@convention(thin) () -> @error any Error, normal bb4, error bb5 bb4(%6: $()): %4 = tuple () return %4 : $() bb5(%5: $Error): throw %5: $Error } // CHECK-LABEL: sil @hoist_generic // CHECK: bb0({{.*}}): // CHECK: [[AS:%.*]] = alloc_stack $Generic // CHECK: bb1: // CHECK-NOT: alloc_stack // CHECK-NOT: dealloc_stack // CHECK: bb2 // CHECK: bb3: // CHECK: dealloc_stack [[AS]] // CHECK: return sil @hoist_generic_type : $@convention(thin) (@in Generic, Builtin.Int1) -> () { bb0(%0 : $*Generic, %1: $Builtin.Int1): cond_br %1, bb1, bb2 bb1: %2 = alloc_stack $Generic copy_addr [take] %0 to [init] %2 : $*Generic destroy_addr %2 : $*Generic dealloc_stack %2 : $*Generic br bb3 bb2: destroy_addr %0 : $*Generic br bb3 bb3: %3 = tuple () return %3 : $() } // CHECK-LABEL: sil @hoist_generic_nesting // CHECK: bb0({{.*}}): // CHECK: [[AS:%.*]] = alloc_stack $T // CHECK: [[AS2:%.*]] = alloc_stack $T // CHECK: [[FIXED:%.*]] = alloc_stack $FixedSize // CHECK: bb1: // CHECK-NOT: alloc_stack // CHECK-NOT: dealloc_stack // CHECK: bb2 // CHECK: bb3: // CHECK: dealloc_stack [[FIXED]] // CHECK: dealloc_stack [[AS2]] // CHECK: dealloc_stack [[AS]] // CHECK: return sil @hoist_generic_nesting : $@convention(thin) (@in T, Builtin.Int1) -> () { bb0(%0 : $*T, %1: $Builtin.Int1): %2 = alloc_stack $FixedSize cond_br %1, bb1, bb2 bb1: %3 = alloc_stack $T %4 = alloc_stack $T copy_addr [take] %0 to [init] %3 : $*T destroy_addr %3 : $*T dealloc_stack %4: $*T dealloc_stack %3 : $*T br bb3 bb2: destroy_addr %0 : $*T br bb3 bb3: dealloc_stack %2: $*FixedSize %5 = tuple () return %5 : $() } // CHECK-LABEL: sil @dont_hoist_opened_generic // CHECK: bb0({{.*}}): // CHECK-NOT: alloc_stack // CHECK: bb1: // CHECK: alloc_stack // CHECK: bb2: // CHECK: bb3: // CHECK-NOT: dealloc_stack // CHECK: return sil @dont_hoist_opened_generic : $@convention(thin) (@in P, Builtin.Int1) -> () { bb0(%0 : $*P, %1: $Builtin.Int1): cond_br %1, bb1, bb2 bb1: %2 = open_existential_addr mutable_access %0 : $*P to $*@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60", P) Self %3 = alloc_stack $@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60", P) Self copy_addr [take] %2 to [init] %3 : $*@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60", P) Self destroy_addr %3 : $*@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60", P) Self dealloc_stack %3 : $*@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60", P) Self br bb3 bb2: destroy_addr %0 : $*P br bb3 bb3: %4 = tuple () return %4 : $() } // CHECK-LABEL: sil @dont_hoist_protocol // CHECK: bb0({{.*}}): // CHECK-NOT: alloc_stack // CHECK: bb1: // CHECK: alloc_stack // CHECK: bb2: // CHECK: bb3: // CHECK-NOT: dealloc_stack // CHECK: return sil @dont_hoist_protocol : $@convention(thin) (@in P, Builtin.Int1) -> () { bb0(%0 : $*P, %1: $Builtin.Int1): cond_br %1, bb1, bb2 bb1: %2 = alloc_stack $P copy_addr [take] %0 to [init] %2 : $*P destroy_addr %2 : $*P dealloc_stack %2 : $*P br bb3 bb2: destroy_addr %0 : $*P br bb3 bb3: %3 = tuple () return %3 : $() } // CHECK-LABEL: sil @dont_crash_on_unreachable // CHECK: bb0({{.*}}): // CHECK: alloc_stack // CHECK: bb1: // CHECK-NOT: alloc_stack // CHECK: bb2: // CHECK: bb3: // CHECK: unreachable sil @dont_crash_on_unreachable : $@convention(thin) (@in T, Builtin.Int1) -> Never { bb0(%0 : $*T, %1: $Builtin.Int1): cond_br %1, bb1, bb2 bb1: %2 = alloc_stack $T copy_addr [take] %0 to [init] %2 : $*T destroy_addr %2 : $*T br bb3 bb2: destroy_addr %0 : $*T br bb3 bb3: %3 = builtin "int_trap"() : $() unreachable } // CHECK-LABEL: sil @dont_hoist_with_availability_checks // CHECK-NOT: alloc_stack // CHECK: cond_br // CHECK: bb1: // CHECK: alloc_stack // CHECK: } // end sil function 'dont_hoist_with_availability_checks' sil @dont_hoist_with_availability_checks : $@convention(thin) (@in T, Builtin.Int1) -> () { bb0(%0 : $*T, %1: $Builtin.Int1): %5 = integer_literal $Builtin.Int32, 15 %7 = builtin "targetOSVersionAtLeast"(%5 : $Builtin.Int32, %5 : $Builtin.Int32, %5 : $Builtin.Int32) : $Builtin.Int32 %8 = builtin "cmp_eq_Int32"(%7 : $Builtin.Int32, %5 : $Builtin.Int32) : $Builtin.Int1 cond_br %8, bb1, bb2 bb1: %2 = alloc_stack $T copy_addr [take] %0 to [init] %2 : $*T destroy_addr %2 : $*T dealloc_stack %2 : $*T br bb3 bb2: destroy_addr %0 : $*T br bb3 bb3: %3 = tuple () return %3 : $() } // CHECK-LABEL: sil @dont_hoist_with_has_symbol_checks // CHECK-NOT: alloc_stack // CHECK: cond_br // CHECK: bb1: // CHECK: alloc_stack // CHECK: } // end sil function 'dont_hoist_with_has_symbol_checks' sil @dont_hoist_with_has_symbol_checks : $@convention(thin) (@in T, Builtin.Int1) -> () { bb0(%0 : $*T, %1: $Builtin.Int1): %5 = has_symbol #FixedSize.init cond_br %5, bb1, bb2 bb1: %2 = alloc_stack $T copy_addr [take] %0 to [init] %2 : $*T destroy_addr %2 : $*T dealloc_stack %2 : $*T br bb3 bb2: destroy_addr %0 : $*T br bb3 bb3: %3 = tuple () return %3 : $() } // CHECK-MERGING-LABEL: sil @merging // CHECK-MERGING: %1 = alloc_stack $T // CHECK-MERGING-NEXT: debug_value %1 // CHECK-MERGING-NEXT: debug_value %1 // CHECK-MERGING: dealloc_stack %1 // CHECK-MERGING-NOT: alloc_stack // CHECK: } // end sil function 'merging' sil @merging : $@convention(thin) (@in T) -> () { bb0(%0 : $*T): %1 = alloc_stack $T debug_value %1 : $*T, name "x" dealloc_stack %1 : $*T %2 = alloc_stack $T debug_value %2 : $*T, name "y" dealloc_stack %2 : $*T %r = tuple () return %r : $() } // CHECK-LABEL: sil @dont_merge // CHECK: %1 = alloc_stack $T // CHECK-NEXT: %2 = alloc_stack $T // CHECK-NEXT: debug_value %2 // CHECK-NEXT: debug_value %1 // CHECK: dealloc_stack %2 // CHECK-NEXT: dealloc_stack %1 // CHECK: } // end sil function 'dont_merge' sil @dont_merge : $@convention(thin) (@in T) -> () { bb0(%0 : $*T): %1 = alloc_stack $T debug_value %1 : $*T, name "x" %3 = alloc_stack $T debug_value %3 : $*T, name "y" dealloc_stack %3 : $*T dealloc_stack %1 : $*T %r = tuple () return %r : $() }