blob: 0a4f0149e3155e0fbfa2509ed7bd35601670687b [file] [log] [blame]
// 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
}