| // RUN: %target-sil-opt -enable-sil-verify-all %s -mem2reg | %FileCheck %s |
| |
| import Builtin |
| import Swift |
| |
| ////////////////// |
| // Declarations // |
| ////////////////// |
| |
| class Klass {} |
| |
| struct SmallCodesizeStruct { |
| var cls1 : Klass |
| var cls2 : Klass |
| } |
| |
| struct WrapperStruct { |
| var cls : Klass |
| } |
| |
| struct LargeCodesizeStruct { |
| var s1: SmallCodesizeStruct |
| var s2: SmallCodesizeStruct |
| var s3: SmallCodesizeStruct |
| var s4: SmallCodesizeStruct |
| var s5: SmallCodesizeStruct |
| } |
| |
| /////////// |
| // Tests // |
| /////////// |
| |
| sil [noinline] [ossa] @blackhole : $@convention(thin) <T> (@in_guaranteed T) -> () { |
| bb0(%0 : $*T): |
| debug_value_addr %0 : $*T, let, name "t", argno 1 |
| %2 = tuple () |
| return %2 : $() |
| } |
| |
| sil shared [noinline] @blackhole_spl : $@convention(thin) (@guaranteed Klass) -> () { |
| bb0(%0 : $Klass): |
| %1 = tuple () |
| return %1 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @store_only_allocas : |
| // CHECK-NOT: alloc_stack |
| // CHECK: return |
| sil [ossa] @store_only_allocas : $@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 : |
| // CHECK-NOT: alloc_stack |
| // CHECK: destroy_value %0 : $Klass |
| // CHECK: [[FUNC:%.*]] = function_ref @blackhole_spl : |
| // CHECK: apply [[FUNC]](%1) : $@convention(thin) (@guaranteed Klass) -> () |
| // CHECK: destroy_value %1 : $Klass |
| // CHECK-LABEL: } // end sil function 'multiple_store_vals' |
| sil [ossa] @multiple_store_vals : $@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_vals2 : |
| // CHECK-NOT: alloc_stack |
| // CHECK: destroy_value %0 : $Klass |
| // CHECK: [[FUNC:%.*]] = function_ref @blackhole_spl : |
| // CHECK: apply [[FUNC]](%1) : $@convention(thin) (@guaranteed Klass) -> () |
| // CHECK: destroy_value %1 : $Klass |
| // CHECK-LABEL: } // end sil function 'multiple_store_vals2' |
| sil [ossa] @multiple_store_vals2 : $@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 |
| // CHECK: [[COPY0:%.*]] = copy_value %0 : $Klass |
| // CHECK: [[COPY1:%.*]] = copy_value %1 : $Klass |
| // CHECK: destroy_value [[COPY0]] : $Klass |
| // CHECK: [[FUNC:%.*]] = function_ref @blackhole_spl : |
| // CHECK: apply [[FUNC]]([[COPY1]]) : $@convention(thin) (@guaranteed Klass) -> () |
| // CHECK: destroy_value [[COPY1]] : $Klass |
| // 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] @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_stores : |
| // CHECK-NOT: alloc_stack |
| // CHECK-LABEL: } // end sil function 'basic_block_with_loads_and_stores' |
| sil [ossa] @basic_block_with_loads_and_stores : $@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 |
| // CHECK: [[COPY:%.*]] = copy_value %0 : $Klass |
| // CHECK: destroy_value [[COPY]] : $Klass |
| // CHECK: destroy_value %0 : $Klass |
| // 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 : $Klass |
| // 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 : $Klass) |
| // CHECK-LABEL: bb2: |
| // CHECK: br bb3(%0 : $Klass) |
| // 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 : $Klass, %0 : $Klass) |
| // CHECK-LABEL: bb2: |
| // CHECK: br bb3(%0 : $Klass, %1 : $Klass) |
| // 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_value_addr : |
| // CHECK-NOT: alloc_stack |
| // CHECK-NOT: debug_value_addr |
| // CHECK: debug_value %0 |
| // CHECK-LABEL: } // end sil function 'mem2reg_debug_value_addr' |
| sil [ossa] @mem2reg_debug_value_addr : $@convention(thin) (@owned Klass) -> @owned Klass { |
| bb0(%0 : @owned $Klass): |
| %1 = alloc_stack $Klass |
| store %0 to [init] %1 : $*Klass |
| debug_value_addr %1 : $*Klass |
| %2 = load [take] %1 : $*Klass |
| dealloc_stack %1 : $*Klass |
| return %2 : $Klass |
| } |
| |
| // CHECK-LABEL: sil [ossa] @mem2reg_struct_addr : |
| // CHECK-NOT: alloc_stack |
| // CHECK: [[BORROW:%.*]] = begin_borrow %0 : $SmallCodesizeStruct |
| // CHECK: [[ELE:%.*]] = struct_extract [[BORROW]] |
| // CHECK: [[COPY:%.*]] = copy_value [[ELE]] : $Klass |
| // CHECK: end_borrow [[BORROW]] : $SmallCodesizeStruct |
| // CHECK: return [[COPY]] |
| // CHECK-LABEL: } // end sil function 'mem2reg_struct_addr' |
| sil [ossa] @mem2reg_struct_addr : $@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_elemenet_addr/tuple_element_addr |
| // CHECK-LABEL: sil [ossa] @mem2reg_struct_addr_load_take : |
| // CHECK: alloc_stack |
| // 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_addr : |
| // CHECK-NOT: alloc_stack |
| // CHECK: [[TUP:%.*]] = tuple (%0 : $Klass, %1 : $Klass) |
| // CHECK: [[BORROW:%.*]] = begin_borrow [[TUP]] : $(Klass, Klass) |
| // CHECK: [[ELE:%.*]] = tuple_extract [[BORROW]] |
| // CHECK: [[COPY:%.*]] = copy_value [[ELE]] : $Klass |
| // CHECK: end_borrow [[BORROW]] : $(Klass, Klass) |
| // CHECK: return [[COPY]] |
| // CHECK-LABEL: } // end sil function 'mem2reg_tuple_addr' |
| sil [ossa] @mem2reg_tuple_addr : $@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_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' |
| |
| // 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 $Klass |
| %local = alloc_ref $Klass |
| store %local to [init] %0 : $*Klass |
| // CHECK-NOT: debug_value_addr |
| debug_value_addr %0 : $*Klass |
| destroy_addr %0 : $*Klass |
| // CHECK-NOT: dealloc_stack |
| dealloc_stack %0 : $*Klass |
| %1 = tuple () |
| return %1 : $() |
| } |
| // CHECK-LABEL: } // end sil function 'no_real_uses' |
| |
| // CHECK-LABEL: sil [ossa] @half_trivial |
| // CHECK: destructure_tuple %0 |
| // CHECK-NEXT: destroy_value |
| // 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_addr %2 : $*Klass |
| %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 |
| } |