mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
In OSSA, the result of an `unchecked_bitwise_cast` must immediately be copied or `unchecked_bitwise_cast`'d again. In particular, it is not permitted to borrow it. For example, the result can't be borrowed for the purpose of performinig additional projections (`struct_extract`, `tuple_extract`) on the borrowed value. Consequently, we cannot promote an address if such a promotion would result in such a pattern. That means we can't promote an address `%addr` which is used like `struct_element_addr(unchecked_addr_cast(%addr))` or `tuple_element_addr(unchecked_addr_cast(%addr))`. We can still promote `unchecked_addr_cast(unchecked_addr_cast(%addr))`. In ownership-lowered SIL, this doesn't apply and we can still promote address with such projections. rdar://153693915
834 lines
26 KiB
Plaintext
834 lines
26 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all %s -mem2reg | %FileCheck %s
|
|
|
|
import Builtin
|
|
|
|
//////////////////
|
|
// Declarations //
|
|
//////////////////
|
|
|
|
typealias AnyObject = Builtin.AnyObject
|
|
|
|
struct Int64 {
|
|
var _value : Builtin.Int64
|
|
}
|
|
|
|
struct Int {
|
|
var _value : Builtin.Int64
|
|
}
|
|
|
|
struct Bool {
|
|
var _value : Builtin.Int1
|
|
}
|
|
|
|
enum FakeOptional<T> {
|
|
case some(T)
|
|
case none
|
|
}
|
|
|
|
class Klass {}
|
|
|
|
struct SmallCodesizeStruct {
|
|
var cls1 : Klass
|
|
var cls2 : Klass
|
|
}
|
|
|
|
struct LargeCodesizeStruct {
|
|
var s1: SmallCodesizeStruct
|
|
var s2: SmallCodesizeStruct
|
|
var s3: SmallCodesizeStruct
|
|
var s4: SmallCodesizeStruct
|
|
var s5: SmallCodesizeStruct
|
|
}
|
|
|
|
class C {}
|
|
|
|
struct S {
|
|
var field: C
|
|
}
|
|
|
|
struct J {
|
|
var c: C
|
|
}
|
|
|
|
struct I {
|
|
var j: J
|
|
}
|
|
|
|
struct S1 {
|
|
var i: I
|
|
}
|
|
|
|
struct S2 {
|
|
var t: (J, J)
|
|
}
|
|
|
|
///////////
|
|
// Tests //
|
|
///////////
|
|
|
|
// CHECK-LABEL: sil [ossa] @store_only_allocas :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'store_only_allocas'
|
|
// simple.foo0 (c : Swift.Int64) -> ()
|
|
sil [ossa] @store_only_allocas : $@convention(thin) (Int64) -> () {
|
|
bb0(%0 : $Int64):
|
|
%1 = alloc_stack $Int64, var, name "c"
|
|
store %0 to [trivial] %1 : $*Int64
|
|
// function_ref Swift.print (val : Swift.Int64) -> ()
|
|
%3 = function_ref @_Ts5printFT3valSi_T_ : $@convention(thin) (Int64) -> ()
|
|
%4 = apply %3(%0) : $@convention(thin) (Int64) -> ()
|
|
dealloc_stack %1 : $*Int64
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
// Swift.print (val : Swift.Int64) -> ()
|
|
sil [ossa] @_Ts5printFT3valSi_T_ : $@convention(thin) (Int64) -> ()
|
|
|
|
// CHECK-LABEL: sil [ossa] @multiple_store_vals :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'multiple_store_vals'
|
|
// simple.foo1 (c : Swift.Int64) -> Swift.Int64
|
|
sil [ossa] @multiple_store_vals : $@convention(thin) (Int64) -> Int64 {
|
|
bb0(%0 : $Int64):
|
|
%1 = alloc_stack $Int64, var, name "c"
|
|
store %0 to [trivial] %1 : $*Int64
|
|
%3 = alloc_stack $Int64, var, name "x"
|
|
%4 = integer_literal $Builtin.Int64, 2
|
|
%5 = struct $Int64 (%4 : $Builtin.Int64)
|
|
store %5 to [trivial] %3 : $*Int64
|
|
%7 = integer_literal $Builtin.Int64, 5
|
|
%8 = integer_literal $Builtin.Int1, 0
|
|
%9 = struct $Int64 (%7 : $Builtin.Int64)
|
|
cond_fail %8 : $Builtin.Int1
|
|
store %9 to [trivial] %3 : $*Int64
|
|
store %9 to [trivial] %3 : $*Int64
|
|
dealloc_stack %3 : $*Int64
|
|
dealloc_stack %1 : $*Int64
|
|
return %9 : $Int64
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @multiple_store_vals2 :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'multiple_store_vals2'
|
|
// simple.foo2 (c : Swift.Int64) -> Swift.Int64
|
|
sil [ossa] @multiple_store_vals2 : $@convention(thin) (Int64) -> Int64 {
|
|
bb0(%0 : $Int64):
|
|
%1 = alloc_stack $Int64, var, name "c"
|
|
store %0 to [trivial] %1 : $*Int64
|
|
%3 = alloc_box $<τ_0_0> { var τ_0_0 } <Int64>, var, name "x"
|
|
%3a = project_box %3 : $<τ_0_0> { var τ_0_0 } <Int64>, 0
|
|
%4 = integer_literal $Builtin.Int64, 2
|
|
%5 = struct $Int64 (%4 : $Builtin.Int64)
|
|
store %5 to [trivial] %3a : $*Int64
|
|
%8 = struct_extract %0 : $Int64, #Int64._value
|
|
%9 = builtin "cmp_sgt_Int64"(%8 : $Builtin.Int64, %4 : $Builtin.Int64) : $Builtin.Int1
|
|
cond_br %9, bb1, bb2
|
|
|
|
bb1:
|
|
destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Int64>
|
|
br bb3(%5 : $Int64)
|
|
|
|
bb2:
|
|
%13 = integer_literal $Builtin.Int64, 5
|
|
%14 = struct $Int64 (%13 : $Builtin.Int64)
|
|
cond_fail %9 : $Builtin.Int1
|
|
destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Int64>
|
|
br bb3(%14 : $Int64)
|
|
|
|
bb3(%18 : $Int64):
|
|
dealloc_stack %1 : $*Int64
|
|
return %18 : $Int64
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @with_loads :
|
|
// CHECK: bb3([[RET:%[0-9]+]] : $Int64):
|
|
// CHECK-LABEL: } // end sil function 'with_loads'
|
|
// simple.foo2 (c : Swift.Int64) -> Swift.Int64
|
|
sil [ossa] @with_loads : $@convention(thin) (Int64) -> Int64 {
|
|
bb0(%0 : $Int64):
|
|
%1 = alloc_stack $Int64, var, name "c"
|
|
store %0 to [trivial] %1 : $*Int64
|
|
%3 = alloc_box $<τ_0_0> { var τ_0_0 } <Int64>, var, name "x"
|
|
%3a = project_box %3 : $<τ_0_0> { var τ_0_0 } <Int64>, 0
|
|
%4 = integer_literal $Builtin.Int64, 2
|
|
%5 = struct $Int64 (%4 : $Builtin.Int64)
|
|
store %5 to [trivial] %3a : $*Int64
|
|
%8 = struct_extract %0 : $Int64, #Int64._value
|
|
%9 = builtin "cmp_sgt_Int64"(%8 : $Builtin.Int64, %4 : $Builtin.Int64) : $Builtin.Int1
|
|
cond_br %9, bb1, bb2
|
|
|
|
bb1:
|
|
destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Int64>
|
|
br bb3(%5 : $Int64)
|
|
|
|
bb2:
|
|
%13 = integer_literal $Builtin.Int64, 5
|
|
%14 = struct $Int64 (%13 : $Builtin.Int64)
|
|
cond_fail %9 : $Builtin.Int1
|
|
destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Int64>
|
|
br bb3(%14 : $Int64)
|
|
|
|
bb3(%18 : $Int64):
|
|
%20 = load [trivial] %1 : $*Int64
|
|
dealloc_stack %1 : $*Int64
|
|
return %18 : $Int64
|
|
}
|
|
|
|
// 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'
|
|
// test.foo3 (c : Swift.Int64) -> ()
|
|
sil [ossa] @basic_block_with_loads_and_stores : $@convention(thin) (Int64) -> () {
|
|
bb0(%0 : $Int64):
|
|
%1 = alloc_stack $Int64, var, name "c"
|
|
store %0 to [trivial] %1 : $*Int64
|
|
%3 = alloc_stack $Int64, var, name "x"
|
|
%4 = integer_literal $Builtin.Int64, 3
|
|
%5 = struct $Int64 (%4 : $Builtin.Int64)
|
|
store %5 to [trivial] %3 : $*Int64
|
|
%7 = integer_literal $Builtin.Int64, 3
|
|
%9 = struct_extract %0 : $Int64, #Int64._value
|
|
%10 = builtin "cmp_sgt_Int64"(%9 : $Builtin.Int64, %7 : $Builtin.Int64) : $Builtin.Int1
|
|
|
|
%12 = integer_literal $Builtin.Int64, 2
|
|
%13 = struct $Int64 (%12 : $Builtin.Int64)
|
|
store %13 to [trivial] %3 : $*Int64
|
|
|
|
// function_ref Swift.print (val : Swift.Int64) -> ()
|
|
%16 = function_ref @_Ts5printFT3valSi_T_ : $@convention(thin) (Int64) -> ()
|
|
%17 = load [trivial] %3 : $*Int64
|
|
%18 = apply %16(%17) : $@convention(thin) (Int64) -> ()
|
|
dealloc_stack %3 : $*Int64
|
|
dealloc_stack %1 : $*Int64
|
|
%21 = tuple ()
|
|
return %21 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @load_uninitialized_empty :
|
|
// CHECK-NOT: load
|
|
// CHECK-LABEL: } // end sil function 'load_uninitialized_empty'
|
|
sil [ossa] @load_uninitialized_empty : $@convention(thin) (@inout ()) -> () {
|
|
bb0(%0 : $*()):
|
|
%1 = alloc_stack $()
|
|
%2 = load [trivial] %1 : $*()
|
|
store %2 to [trivial] %0 : $*()
|
|
dealloc_stack %1 : $*()
|
|
%3 = tuple ()
|
|
return %3 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @mem2reg_debug_value :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-NOT: debug_value {{.*}} expr op_deref
|
|
// CHECK: debug_value %0
|
|
// CHECK-LABEL: } // end sil function 'mem2reg_debug_value'
|
|
sil [ossa] @mem2reg_debug_value : $@convention(thin) (Int) -> Int {
|
|
bb0(%0 : $Int):
|
|
%1 = alloc_stack $Int
|
|
store %0 to [trivial] %1 : $*Int
|
|
debug_value %1 : $*Int, expr op_deref
|
|
%2 = load [trivial] %1 : $*Int
|
|
dealloc_stack %1 : $*Int
|
|
return %2 : $Int
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @mem2reg_struct_addr :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK: struct_extract
|
|
// CHECK-LABEL: } // end sil function 'mem2reg_struct_addr'
|
|
sil [ossa] @mem2reg_struct_addr : $@convention(thin) (Int64) -> Builtin.Int64 {
|
|
bb0(%0 : $Int64):
|
|
%1 = alloc_stack $Int64
|
|
store %0 to [trivial] %1 : $*Int64
|
|
%2 = struct_element_addr %1 : $*Int64, #Int64._value
|
|
%3 = load [trivial] %2 : $*Builtin.Int64
|
|
dealloc_stack %1 : $*Int64
|
|
return %3 : $Builtin.Int64
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @mem2reg_tuple_addr :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK: tuple_extract {{.*}}, 0
|
|
// CHECK-LABEL: } // end sil function 'mem2reg_tuple_addr'
|
|
sil [ossa] @mem2reg_tuple_addr : $@convention(thin) (Int64) -> Int64 {
|
|
bb0(%0 : $Int64):
|
|
%1 = alloc_stack $(Int64, Int64)
|
|
%2 = tuple (%0 : $Int64, %0 : $Int64)
|
|
store %2 to [trivial] %1 : $*(Int64, Int64)
|
|
%4 = tuple_element_addr %1 : $*(Int64, Int64), 0
|
|
%5 = load [trivial] %4 : $*Int64
|
|
dealloc_stack %1 : $*(Int64, Int64)
|
|
return %5 : $Int64
|
|
}
|
|
|
|
// 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'
|
|
|
|
sil [ossa] @first : $@convention(thin) () -> Int
|
|
sil [ossa] @second : $@convention(thin) () -> Int
|
|
|
|
// CHECK: sil [ossa] @promote_function_refs :
|
|
sil [ossa] @promote_function_refs : $@convention(thin) (Bool) -> Int {
|
|
// CHECK: bb0
|
|
bb0(%0 : $Bool):
|
|
// CHECK-NOT: [[STACK:%.*]] = alloc_stack
|
|
%1 = alloc_stack $@callee_owned () -> Int
|
|
debug_value %0 : $Bool
|
|
%3 = struct_extract %0 : $Bool, #Bool._value
|
|
cond_br %3, bb1, bb2
|
|
|
|
// CHECK: bb1
|
|
bb1:
|
|
// CHECK: [[FIRSTREF:%.*]] = function_ref @first
|
|
%5 = function_ref @first : $@convention(thin) () -> Int
|
|
// CHECK: [[FIRSTTHICK:%.*]] = thin_to_thick_function [[FIRSTREF]]
|
|
%6 = thin_to_thick_function %5 : $@convention(thin) () -> Int to $@callee_owned () -> Int
|
|
// CHECK-NOT: store
|
|
store %6 to [init] %1 : $*@callee_owned () -> Int
|
|
// CHECK: br bb3([[FIRSTTHICK]] : $@callee_owned () -> Int
|
|
br bb3
|
|
|
|
// CHECK: bb2
|
|
bb2:
|
|
// CHECK: [[SECONDREF:%.*]] = function_ref @second
|
|
%9 = function_ref @second : $@convention(thin) () -> Int
|
|
// CHECK: [[SECONDTHICK:%.*]] = thin_to_thick_function [[SECONDREF]]
|
|
%10 = thin_to_thick_function %9 : $@convention(thin) () -> Int to $@callee_owned () -> Int
|
|
// CHECK-NOT: store
|
|
store %10 to [init] %1 : $*@callee_owned () -> Int
|
|
// CHECK: br bb3([[SECONDTHICK]] : $@callee_owned () -> Int)
|
|
br bb3
|
|
|
|
// CHECK: bb3([[ARG:%.*]] : @owned $@callee_owned () -> Int):
|
|
bb3:
|
|
// CHECK-NOT: load
|
|
%13 = load [copy] %1 : $*@callee_owned () -> Int
|
|
// : [[COPY:%.*]] = copy_value [[ARG]]
|
|
// The above copy is eliminated by owned value canonicalization.
|
|
// CHECK: [[RESULT:%.*]] = apply [[ARG]]
|
|
%15 = apply %13() : $@callee_owned () -> Int
|
|
br bb4
|
|
|
|
// NOTE: This block and the branch above exist to ensure that we
|
|
// test what happens when %1 hasn't already been loaded in this
|
|
// block.
|
|
// CHECK: bb4
|
|
bb4:
|
|
// CHECK-NOT: destroy_addr
|
|
// : destroy_value [[ARG]]
|
|
// The above destroy is eliminated by owned value canonicalization.
|
|
destroy_addr %1 : $*@callee_owned () -> Int
|
|
// CHECK-NOT: dealloc_stack
|
|
dealloc_stack %1 : $*@callee_owned () -> Int
|
|
return %15 : $Int
|
|
}
|
|
// CHECK-LABEL: } // end sil function 'promote_function_refs'
|
|
|
|
// 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 [dynamic_lifetime] $Builtin.Int32
|
|
// CHECK-NOT: debug_value {{.*}} expr op_deref
|
|
debug_value %0 : $*Builtin.Int32, let, name "x", argno 1, expr op_deref
|
|
// CHECK-NOT: dealloc_stack
|
|
dealloc_stack %0 : $*Builtin.Int32
|
|
%1 = tuple ()
|
|
return %1 : $()
|
|
}
|
|
// CHECK-LABEL: } // end sil function 'no_real_uses'
|
|
|
|
// CHECK-LABEL: sil [ossa] @keep_release :
|
|
// CHECK: destroy_value %0
|
|
// CHECK-LABEL: } // end sil function 'keep_release'
|
|
sil [ossa] @keep_release : $@convention(thin) (@owned AnyObject) -> () {
|
|
bb0(%0 : @owned $AnyObject):
|
|
%1 = alloc_stack $AnyObject
|
|
store %0 to [init] %1 : $*AnyObject
|
|
destroy_addr %1 : $*AnyObject
|
|
dealloc_stack %1 : $*AnyObject
|
|
%7 = tuple ()
|
|
return %7 : $()
|
|
}
|
|
|
|
// Test cases where there are dead address instructions.
|
|
// CHECK-LABEL: sil [ossa] @dead_use :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'dead_use'
|
|
sil [ossa] @dead_use : $@convention(thin) () -> () {
|
|
%0 = alloc_stack $Int64
|
|
%1 = struct_element_addr %0 : $*Int64, #Int64._value
|
|
dealloc_stack %0 : $*Int64
|
|
%2 = alloc_stack $(Int64, Int64)
|
|
%3 = tuple_element_addr %2 : $*(Int64, Int64), 0
|
|
dealloc_stack %2 : $*(Int64, Int64)
|
|
%4 = tuple ()
|
|
return %4 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_crash_on_dead_arg_use :
|
|
// CHECK: bb0{{.*}}:
|
|
// CHECK: tuple ()
|
|
// CHECK-LABEL: } // end sil function 'dont_crash_on_dead_arg_use'
|
|
sil [ossa] @dont_crash_on_dead_arg_use : $@convention(thin) (@inout Int64) -> () {
|
|
bb0(%0 : $*Int64):
|
|
%2 = alloc_stack $Int64
|
|
%1 = struct_element_addr %0 : $*Int64, #Int64._value
|
|
%3 = struct_element_addr %2 : $*Int64, #Int64._value
|
|
dealloc_stack %2 : $*Int64
|
|
%4 = tuple ()
|
|
return %4 : $()
|
|
}
|
|
|
|
// Make sure that we do expand destroy_addr appropriately for code-size
|
|
// trade-offs.
|
|
// CHECK-LABEL: sil [ossa] @large_struct_test :
|
|
// CHECK: bb0([[ARG0:%.*]] : @owned $LargeCodesizeStruct):
|
|
// CHECK: destroy_value [[ARG0]]
|
|
// CHECK: } // end sil function 'large_struct_test'
|
|
sil [ossa] @large_struct_test : $@convention(thin) (@owned LargeCodesizeStruct) -> () {
|
|
bb0(%0 : @owned $LargeCodesizeStruct):
|
|
%1 = alloc_stack $LargeCodesizeStruct
|
|
store %0 to [init] %1 : $*LargeCodesizeStruct
|
|
destroy_addr %1 : $*LargeCodesizeStruct
|
|
dealloc_stack %1 : $*LargeCodesizeStruct
|
|
%7 = tuple ()
|
|
return %7 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @small_struct_test :
|
|
// CHECK: bb0([[ARG0:%.*]] : @owned $SmallCodesizeStruct):
|
|
// CHECK: ([[ELEM1:%[0-9]+]], [[ELEM2:%[0-9]+]]) = destructure_struct [[ARG0]]
|
|
// CHECK: destroy_value [[ELEM1]]
|
|
// CHECK: destroy_value [[ELEM2]]
|
|
// CHECK: } // end sil function 'small_struct_test'
|
|
sil [ossa] @small_struct_test : $@convention(thin) (@owned SmallCodesizeStruct) -> () {
|
|
bb0(%0 : @owned $SmallCodesizeStruct):
|
|
%1 = alloc_stack $SmallCodesizeStruct
|
|
store %0 to [init] %1 : $*SmallCodesizeStruct
|
|
destroy_addr %1 : $*SmallCodesizeStruct
|
|
dealloc_stack %1 : $*SmallCodesizeStruct
|
|
%7 = tuple ()
|
|
return %7 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @small_struct_multi_test :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK: [[COPY:%.*]] = copy_value %0
|
|
// CHECK-NEXT: destructure_struct %2
|
|
// CHECK-NEXT: destroy_value
|
|
// CHECK-NEXT: destroy_value
|
|
// CHECK-NEXT: begin_borrow %0
|
|
// CHECK-NEXT: debug_value
|
|
// CHECK-NEXT: end_borrow
|
|
// CHECK-NEXT: destroy_value %0
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: destructure_struct %0
|
|
// CHECK-NEXT: destroy_value
|
|
// CHECK-NEXT: destroy_value
|
|
// CHECK-LABEL: } // end sil function 'small_struct_multi_test'
|
|
sil [ossa] @small_struct_multi_test : $@convention(thin) (@owned SmallCodesizeStruct) -> () {
|
|
bb0(%0 : @owned $SmallCodesizeStruct):
|
|
%1 = alloc_stack $SmallCodesizeStruct
|
|
store %0 to [init] %1 : $*SmallCodesizeStruct
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%3 = load [copy] %1 : $*SmallCodesizeStruct
|
|
destroy_addr %1 : $*SmallCodesizeStruct
|
|
dealloc_stack %1 : $*SmallCodesizeStruct
|
|
%4 = begin_borrow %3 : $SmallCodesizeStruct
|
|
debug_value %4 : $SmallCodesizeStruct
|
|
end_borrow %4 : $SmallCodesizeStruct
|
|
destroy_value %3 : $SmallCodesizeStruct
|
|
br bb3
|
|
|
|
bb2:
|
|
destroy_addr %1 : $*SmallCodesizeStruct
|
|
dealloc_stack %1 : $*SmallCodesizeStruct
|
|
br bb3
|
|
|
|
bb3:
|
|
%7 = tuple ()
|
|
return %7 : $()
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: sil [ossa] @dead_address_projections :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK: } // end sil function 'dead_address_projections'
|
|
sil [ossa] @dead_address_projections : $@convention(thin) (((), ())) -> ((), ()) {
|
|
bb0(%0 : $((), ())):
|
|
%1 = alloc_stack $((), ())
|
|
%200 = tuple_element_addr %1 : $*((), ()), 0
|
|
%300 = tuple_element_addr %1 : $*((), ()), 1
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
store %0 to [trivial] %1 : $*((), ())
|
|
%16 = load [trivial] %1 : $*((), ())
|
|
dealloc_stack %1 : $*((), ())
|
|
br bb3(%16 : $((), ()))
|
|
|
|
bb2:
|
|
dealloc_stack %1 : $*((), ())
|
|
br bb3(%0 : $((), ()))
|
|
|
|
bb3(%20 : $((), ())):
|
|
return %20 : $((), ())
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @load_tuple_of_void :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK: [[T:%[0-9]+]] = tuple (%{{[0-9]+}} : $(), %{{[0-9]+}} : $())
|
|
// CHECK: return [[T]] : $((), ())
|
|
// CHECK: } // end sil function 'load_tuple_of_void'
|
|
sil [ossa] @load_tuple_of_void : $@convention(thin) () -> ((), ()) {
|
|
bb0:
|
|
%1 = alloc_stack $((), ())
|
|
%16 = load [trivial] %1 : $*((), ())
|
|
dealloc_stack %1 : $*((), ())
|
|
return %16 : $((), ())
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_optional_in_multiple_blocks :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK: } // end sil function 'test_optional_in_multiple_blocks'
|
|
sil [ossa] @test_optional_in_multiple_blocks : $@convention(method) (@guaranteed FakeOptional<Klass>) -> () {
|
|
bb0(%0 : @guaranteed $FakeOptional<Klass>):
|
|
%1 = copy_value %0 : $FakeOptional<Klass>
|
|
%32 = alloc_stack $FakeOptional<Klass>
|
|
store %1 to [init] %32 : $*FakeOptional<Klass>
|
|
switch_enum %0 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb6, case #FakeOptional.none!enumelt: bb5
|
|
|
|
bb5:
|
|
dealloc_stack %32 : $*FakeOptional<Klass>
|
|
br bb7
|
|
|
|
bb6(%50 : @guaranteed $Klass):
|
|
%53 = load [copy] %32 : $*FakeOptional<Klass>
|
|
destroy_value %53 : $FakeOptional<Klass>
|
|
destroy_addr %32 : $*FakeOptional<Klass>
|
|
dealloc_stack %32 : $*FakeOptional<Klass>
|
|
br bb7
|
|
|
|
bb7:
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_optional_in_multiple_blocks_lexical :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK: } // end sil function 'test_optional_in_multiple_blocks_lexical'
|
|
sil [ossa] @test_optional_in_multiple_blocks_lexical : $@convention(method) (@guaranteed FakeOptional<Klass>) -> () {
|
|
bb0(%0 : @guaranteed $FakeOptional<Klass>):
|
|
%1 = copy_value %0 : $FakeOptional<Klass>
|
|
%32 = alloc_stack [lexical] $FakeOptional<Klass>
|
|
store %1 to [init] %32 : $*FakeOptional<Klass>
|
|
switch_enum %0 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb6, case #FakeOptional.none!enumelt: bb5
|
|
|
|
bb5:
|
|
dealloc_stack %32 : $*FakeOptional<Klass>
|
|
br bb7
|
|
|
|
bb6(%50 : @guaranteed $Klass):
|
|
%53 = load [copy] %32 : $*FakeOptional<Klass>
|
|
destroy_value %53 : $FakeOptional<Klass>
|
|
destroy_addr %32 : $*FakeOptional<Klass>
|
|
dealloc_stack %32 : $*FakeOptional<Klass>
|
|
br bb7
|
|
|
|
bb7:
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_optional_in_multiple_blocks_lexical_storedvalue :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK: } // end sil function 'test_optional_in_multiple_blocks_lexical_storedvalue'
|
|
sil [ossa] @test_optional_in_multiple_blocks_lexical_storedvalue : $@convention(method) (@owned FakeOptional<Klass>) -> () {
|
|
bb0(%0 : @owned $FakeOptional<Klass>):
|
|
%1 = copy_value %0 : $FakeOptional<Klass>
|
|
%32 = alloc_stack $FakeOptional<Klass>
|
|
store %0 to [init] %32 : $*FakeOptional<Klass>
|
|
switch_enum %1 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb6, case #FakeOptional.none!enumelt: bb5
|
|
|
|
bb5:
|
|
dealloc_stack %32 : $*FakeOptional<Klass>
|
|
br bb7
|
|
|
|
bb6(%50 : @owned $Klass):
|
|
%53 = load [copy] %32 : $*FakeOptional<Klass>
|
|
destroy_value %53 : $FakeOptional<Klass>
|
|
destroy_value %50 : $Klass
|
|
destroy_addr %32 : $*FakeOptional<Klass>
|
|
dealloc_stack %32 : $*FakeOptional<Klass>
|
|
br bb7
|
|
|
|
bb7:
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @optimize_optional_in_single_block :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK: } // end sil function 'optimize_optional_in_single_block'
|
|
sil [ossa] @optimize_optional_in_single_block : $@convention(method) (@guaranteed FakeOptional<Klass>) -> () {
|
|
bb0(%0 : @guaranteed $FakeOptional<Klass>):
|
|
switch_enum %0 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb6, case #FakeOptional.none!enumelt: bb5
|
|
|
|
bb5:
|
|
br bb7
|
|
|
|
bb6(%50 : @guaranteed $Klass):
|
|
%32 = alloc_stack $FakeOptional<Klass>
|
|
%1 = copy_value %0 : $FakeOptional<Klass>
|
|
store %1 to [init] %32 : $*FakeOptional<Klass>
|
|
%53 = load [take] %32 : $*FakeOptional<Klass>
|
|
destroy_value %53 : $FakeOptional<Klass>
|
|
dealloc_stack %32 : $*FakeOptional<Klass>
|
|
br bb7
|
|
|
|
bb7:
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @switch_enum_out_of_new_phi_block : {{.*}} {
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK: } // end sil function 'switch_enum_out_of_new_phi_block'
|
|
sil [ossa] @switch_enum_out_of_new_phi_block : $() -> () {
|
|
entry:
|
|
%addr = alloc_stack $FakeOptional<Klass>
|
|
cond_br undef, store_none, agg_either
|
|
|
|
store_none:
|
|
%none1 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
|
|
store %none1 to [init] %addr : $*FakeOptional<Klass>
|
|
br switcheroo
|
|
|
|
agg_either:
|
|
cond_br undef, agg_some, agg_none
|
|
|
|
agg_some:
|
|
%Klass = apply undef() : $@convention(thin) () -> (@owned Klass)
|
|
%some = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %Klass : $Klass
|
|
br store_maybe(%some : $FakeOptional<Klass>)
|
|
|
|
agg_none:
|
|
%none2 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
|
|
br store_maybe(%none2 : $FakeOptional<Klass>)
|
|
|
|
store_maybe(%maybe : @owned $FakeOptional<Klass>):
|
|
store %maybe to [init] %addr : $*FakeOptional<Klass>
|
|
br switcheroo
|
|
|
|
switcheroo:
|
|
%borrow = load_borrow %addr : $*FakeOptional<Klass>
|
|
switch_enum %borrow : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb14, case #FakeOptional.none!enumelt: bb15
|
|
|
|
bb14(%some_borrowed : @guaranteed $Klass):
|
|
end_borrow %borrow : $FakeOptional<Klass>
|
|
destroy_addr %addr : $*FakeOptional<Klass>
|
|
br bb16
|
|
|
|
bb15:
|
|
end_borrow %borrow : $FakeOptional<Klass>
|
|
br bb16
|
|
|
|
bb16:
|
|
dealloc_stack %addr : $*FakeOptional<Klass>
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @debug_value_of_store_borrow_addr_multi_block : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] :
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: debug_value [[LIFETIME]]
|
|
// CHECK-LABEL: } // end sil function 'debug_value_of_store_borrow_addr_multi_block'
|
|
sil [ossa] @debug_value_of_store_borrow_addr_multi_block : $@convention(thin) (@owned S) -> () {
|
|
entry(%instance : @owned $S):
|
|
br header
|
|
|
|
header:
|
|
%lifetime = begin_borrow %instance : $S
|
|
%stack = alloc_stack $S
|
|
%stack_borrow = store_borrow %lifetime to %stack : $*S
|
|
debug_value %stack_borrow : $*S
|
|
br body
|
|
|
|
body:
|
|
%field_addr = struct_element_addr %stack_borrow : $*S, #S.field
|
|
%field = load [copy] %field_addr : $*C
|
|
end_borrow %stack_borrow : $*S
|
|
dealloc_stack %stack : $*S
|
|
end_borrow %lifetime : $S
|
|
destroy_value %field : $C
|
|
cond_br undef, backedge, exit
|
|
|
|
backedge:
|
|
br header
|
|
|
|
exit:
|
|
destroy_value %instance : $S
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @debug_value_of_store_borrow_addr_single_block : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] :
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: debug_value [[LIFETIME]]
|
|
// CHECK-LABEL: } // end sil function 'debug_value_of_store_borrow_addr_single_block'
|
|
sil [ossa] @debug_value_of_store_borrow_addr_single_block : $@convention(thin) (@owned S) -> () {
|
|
entry(%instance : @owned $S):
|
|
br header
|
|
|
|
header:
|
|
%lifetime = begin_borrow %instance : $S
|
|
%stack = alloc_stack $S
|
|
%stack_borrow = store_borrow %lifetime to %stack : $*S
|
|
debug_value %stack_borrow : $*S
|
|
%field_addr = struct_element_addr %stack_borrow : $*S, #S.field
|
|
%field = load [copy] %field_addr : $*C
|
|
end_borrow %stack_borrow : $*S
|
|
dealloc_stack %stack : $*S
|
|
end_borrow %lifetime : $S
|
|
destroy_value %field : $C
|
|
cond_br undef, backedge, exit
|
|
|
|
backedge:
|
|
br header
|
|
|
|
exit:
|
|
destroy_value %instance : $S
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_canonicalize_undef : {{.*}} {
|
|
// CHECK: [[RETVAL:%[^,]+]] = tuple
|
|
// CHECK: return [[RETVAL]]
|
|
// CHECK-LABEL: } // end sil function 'dont_canonicalize_undef'
|
|
sil [ossa] @dont_canonicalize_undef : $@convention(thin) () -> () {
|
|
%addr = alloc_stack $()
|
|
store undef to [trivial] %addr : $*()
|
|
dealloc_stack %addr : $*()
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_canonicalize_erased_copy : {{.*}} {
|
|
// CHECK: bb0(%0 :
|
|
// CHECK: destroy_value %0
|
|
// CHECK-LABEL: } // end sil function 'dont_canonicalize_erased_copy'
|
|
sil [ossa] @dont_canonicalize_erased_copy : $@convention(thin) (@owned C) -> () {
|
|
entry(%instance : @owned $C):
|
|
%stack = alloc_stack $C
|
|
%copy = copy_value %instance : $C
|
|
store %copy to [init] %stack : $*C
|
|
%loaded_copy = load [take] %stack : $*C
|
|
destroy_value %loaded_copy : $C
|
|
store %instance to [init] %stack : $*C
|
|
%loaded_instance = load [take] %stack : $*C
|
|
destroy_value %loaded_instance : $C
|
|
dealloc_stack %stack : $*C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @no_promo_proj_uac_1 : {{.*}} {
|
|
// CHECK: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'no_promo_proj_uac_1'
|
|
sil [ossa] @no_promo_proj_uac_1 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%s = apply undef() : $@convention(thin) () -> (@owned S1)
|
|
%addr = alloc_stack $S1
|
|
store %s to [init] %addr
|
|
%i_addr = unchecked_addr_cast %addr to $*I
|
|
%j_addr = struct_element_addr %i_addr, #I.j
|
|
%j = load [copy] %j_addr
|
|
destroy_addr %addr
|
|
dealloc_stack %addr
|
|
apply undef(%j) : $@convention(thin) (@owned J) -> ()
|
|
%retval = tuple ()
|
|
return %retval
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @no_promo_proj_uac_2 : {{.*}} {
|
|
// CHECK: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'no_promo_proj_uac_2'
|
|
sil [ossa] @no_promo_proj_uac_2 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%s = apply undef() : $@convention(thin) () -> (@owned S2)
|
|
%addr = alloc_stack $S2
|
|
store %s to [init] %addr
|
|
%t_addr = unchecked_addr_cast %addr to $*(J, J)
|
|
%j_addr = tuple_element_addr %t_addr, 0
|
|
%j = load [copy] %j_addr
|
|
destroy_addr %addr
|
|
dealloc_stack %addr
|
|
apply undef(%j) : $@convention(thin) (@owned J) -> ()
|
|
%retval = tuple ()
|
|
return %retval
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @promo_uac_uac : {{.*}} {
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'promo_uac_uac'
|
|
sil [ossa] @promo_uac_uac : $@convention(thin) () -> () {
|
|
bb0:
|
|
%s = apply undef() : $@convention(thin) () -> (@owned S1)
|
|
%addr = alloc_stack $S1
|
|
store %s to [init] %addr
|
|
%i_addr = unchecked_addr_cast %addr to $*I
|
|
%j_addr = unchecked_addr_cast %i_addr to $*J
|
|
%j = load [copy] %j_addr
|
|
destroy_addr %addr
|
|
dealloc_stack %addr
|
|
apply undef(%j) : $@convention(thin) (@owned J) -> ()
|
|
%retval = tuple ()
|
|
return %retval
|
|
}
|