mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
The InstructionDeleter can remove instructions including their destroys and then insert compensating destroys at a new place. This is effectively destroy-hoisting which doesn't respect deinit-barriers. Therefore it's not done for lexical lifetimes. However, since https://github.com/swiftlang/swift/pull/85334, the optimizer should treat _all_ lifetimes as fixed and not only lexical lifetimes. This change adds a `assumeFixedLifetimes` flag to InstructionDeleter which is on by default. Only mandatory passes (like OSLogOptimization) should turn this off.
1414 lines
49 KiB
Plaintext
1414 lines
49 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all -update-borrowed-from -dce %s | %FileCheck %s
|
|
|
|
// REQUIRES: swift_in_compiler
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
class Klass {
|
|
|
|
}
|
|
|
|
enum EitherNoneOrAnyObject {
|
|
case none
|
|
case any(AnyObject)
|
|
}
|
|
|
|
struct NonTrivialStruct {
|
|
var val:Klass
|
|
}
|
|
|
|
enum FakeOptional<T> {
|
|
case none
|
|
case some(T)
|
|
}
|
|
|
|
struct Wrapper1 {
|
|
var val1: Wrapper2
|
|
}
|
|
|
|
struct Wrapper2 {
|
|
var val2: Klass
|
|
}
|
|
|
|
sil [ossa] @$testtryapplyklassgen : $@convention(thin) () -> (@owned Klass, @error any Error)
|
|
sil [ossa] @$use_klass1 : $@convention(thin) (@owned Klass) -> ()
|
|
sil [ossa] @$use_klass2 : $@convention(thin) (@guaranteed Klass) -> ()
|
|
sil [ossa] @$use_nontrivialstruct1 : $@convention(thin) (@owned NonTrivialStruct) -> ()
|
|
sil [ossa] @$use_nontrivialstruct2 : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
|
|
// We cannot DCE a function argument
|
|
// CHECK-LABEL: sil [ossa] @dce_dontoptarg1 :
|
|
// CHECK: destroy_value %0
|
|
// CHECK-LABEL: } // end sil function 'dce_dontoptarg1'
|
|
sil [ossa] @dce_dontoptarg1 : $@convention(thin) (@owned Klass) -> () {
|
|
bb0(%0 : @owned $Klass):
|
|
destroy_value %0 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_dontoptarg2 :
|
|
// CHECK: copy_value
|
|
// CHECK: destroy_value
|
|
// CHECK-LABEL: } // end sil function 'dce_dontoptarg2'
|
|
sil [ossa] @dce_dontoptarg2 : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%1 = copy_value %0 : $Klass
|
|
br bb1(%1 : $Klass)
|
|
|
|
bb1(%2 : @owned $Klass):
|
|
%3 = copy_value %2 : $Klass
|
|
%4 = function_ref @$use_klass1 : $@convention(thin) (@owned Klass) -> ()
|
|
%5 = apply %4(%3) : $@convention(thin) (@owned Klass) -> ()
|
|
destroy_value %2 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// Don't dce due to a useful dependency due to apply
|
|
// CHECK-LABEL: sil [ossa] @dce_dontoptrevdep1 :
|
|
// CHECK: [[RES:%.*]] = load_borrow %0
|
|
// CHECK: end_borrow [[RES]]
|
|
// CHECK-LABEL: } // end sil function 'dce_dontoptrevdep1'
|
|
sil [ossa] @dce_dontoptrevdep1 : $@convention(thin) (@in Klass) -> () {
|
|
bb0(%0 : $*Klass):
|
|
%1 = load_borrow %0 : $*Klass
|
|
%2 = function_ref @$use_klass2 : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%3 = apply %2(%1) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %1 : $Klass
|
|
destroy_addr %0 : $*Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// Don't dce due to a useful dependency due to apply
|
|
// CHECK-LABEL: sil [ossa] @dce_dontoptendborrow1 :
|
|
// CHECK: [[RES:%.*]] = begin_borrow %0
|
|
// CHECK: end_borrow
|
|
// CHECK-LABEL: } // end sil function 'dce_dontoptendborrow1'
|
|
sil [ossa] @dce_dontoptendborrow1 : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%1 = begin_borrow %0 : $Klass
|
|
br bb1(%1 : $Klass)
|
|
|
|
bb1(%2 : @guaranteed $Klass):
|
|
%3 = function_ref @$use_klass2 : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%4 = apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %2 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// Cannot optimize dead non phi args
|
|
// CHECK-LABEL: sil [ossa] @dce_dontoptarg3 :
|
|
// CHECK: destroy_value
|
|
// CHECK-LABEL: } // end sil function 'dce_dontoptarg3'
|
|
sil [ossa] @dce_dontoptarg3 : $@convention(thin) (@guaranteed Klass) -> @error any Error {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%2 = function_ref @$testtryapplyklassgen : $@convention(thin) () -> (@owned Klass, @error any Error)
|
|
try_apply %2() : $@convention(thin) () -> (@owned Klass, @error any Error), normal bb1, error bb2
|
|
|
|
bb1(%3 : @owned $Klass):
|
|
destroy_value %3 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
|
|
bb2(%4 : $Error):
|
|
throw %4 : $Error
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_deadcopy1 :
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: destroy_value %0
|
|
// CHECK-LABEL: } // end sil function 'dce_deadcopy1'
|
|
sil [ossa] @dce_deadcopy1 : $@convention(thin) (@owned Klass) -> () {
|
|
bb0(%0 : @owned $Klass):
|
|
%1 = copy_value %0 : $Klass
|
|
destroy_value %1 : $Klass
|
|
destroy_value %0 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_deadcopy2 :
|
|
// CHECK-NOT: copy_value
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK-LABEL: } // end sil function 'dce_deadcopy2'
|
|
sil [ossa] @dce_deadcopy2 : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%1 = copy_value %0 : $Klass
|
|
destroy_value %1 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_deadcopy3 :
|
|
// CHECK: bb0([[ARG:%.*]])
|
|
// CHECK-NEXT: br bb1
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: [[RES:%.*]] = tuple ()
|
|
// CHECK-NEXT: return [[RES]]
|
|
// CHECK-LABEL: } // end sil function 'dce_deadcopy3'
|
|
sil [ossa] @dce_deadcopy3 : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%1 = copy_value %0 : $Klass
|
|
br bb1(%1 : $Klass)
|
|
|
|
bb1(%2 : @owned $Klass):
|
|
destroy_value %2 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_deadcopy4 :
|
|
// CHECK-NOT: copy_value
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK-LABEL: } // end sil function 'dce_deadcopy4'
|
|
sil [ossa] @dce_deadcopy4 : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%1 = copy_value %0 : $Klass
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb3(%1 : $Klass)
|
|
|
|
bb2:
|
|
br bb3(%1 : $Klass)
|
|
|
|
bb3(%2 : @owned $Klass):
|
|
destroy_value %2 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_deadcopy5 :
|
|
// CHECK: bb0([[ARG:%.*]])
|
|
// CHECK-NEXT: br bb1
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: [[RES:%.*]] = tuple ()
|
|
// CHECK-NEXT: return [[RES]]
|
|
// CHECK-LABEL: } // end sil function 'dce_deadcopy5'
|
|
sil [ossa] @dce_deadcopy5 : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%1 = copy_value %0 : $Klass
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb3(%2 : @owned $Klass):
|
|
destroy_value %2 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
|
|
bb1:
|
|
br bb3(%1 : $Klass)
|
|
|
|
bb2:
|
|
br bb3(%1 : $Klass)
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_deadcopy6 :
|
|
// CHECK: bb0([[ARG:%.*]])
|
|
// CHECK-NEXT: br bb1
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: [[RES:%.*]] = tuple ()
|
|
// CHECK-NEXT: return [[RES]]
|
|
// CHECK-LABEL: } // end sil function 'dce_deadcopy6'
|
|
sil [ossa] @dce_deadcopy6 : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%1 = copy_value %0 : $Klass
|
|
cond_br undef, bb1a, bb2a
|
|
|
|
bb1a:
|
|
br bb1(%1 : $Klass)
|
|
|
|
bb2a:
|
|
br bb2(%1 : $Klass)
|
|
|
|
bb1(%1a : @owned $Klass):
|
|
br bb3(%1a : $Klass)
|
|
|
|
bb2(%1b : @owned $Klass):
|
|
br bb3(%1b : $Klass)
|
|
|
|
bb3(%2 : @owned $Klass):
|
|
destroy_value %2 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_deadcopy7 :
|
|
// CHECK-NOT: load [copy]
|
|
// CHECK-LABEL: } // end sil function 'dce_deadcopy7'
|
|
sil [ossa] @dce_deadcopy7 : $@convention(thin) (@in Klass) -> () {
|
|
bb0(%0 : $*Klass):
|
|
%1 = load [copy] %0 : $*Klass
|
|
br bb1(%1 : $Klass)
|
|
|
|
bb1(%2 : @owned $Klass):
|
|
destroy_value %2 : $Klass
|
|
destroy_addr %0 : $*Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_destructure1 :
|
|
// CHECK: bb0(%0 : {{.*}})
|
|
// CHECK-NEXT: destroy_value %0
|
|
// CHECK-NEXT: [[RES:%.*]] = tuple ()
|
|
// CHECK-NEXT: return [[RES]]
|
|
// CHECK-LABEL: } // end sil function 'dce_destructure1'
|
|
sil [ossa] @dce_destructure1 : $@convention(thin) (@owned NonTrivialStruct) -> () {
|
|
bb0(%0 : @owned $NonTrivialStruct):
|
|
(%1) = destructure_struct %0 : $NonTrivialStruct
|
|
destroy_value %1 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_destructure2 :
|
|
// CHECK: bb0(%0 : {{.*}})
|
|
// CHECK-NEXT: [[RES:%.*]] = tuple ()
|
|
// CHECK-NEXT: return [[RES]]
|
|
// CHECK-LABEL: } // end sil function 'dce_destructure2'
|
|
sil [ossa] @dce_destructure2 : $@convention(thin) (@guaranteed NonTrivialStruct) -> () {
|
|
bb0(%0 : @guaranteed $NonTrivialStruct):
|
|
(%1) = destructure_struct %0 : $NonTrivialStruct
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_destructure3 :
|
|
// CHECK: bb0(%0 : {{.*}})
|
|
// CHECK-NOT: destructure_struct
|
|
// CHECK-LABEL: } // end sil function 'dce_destructure3'
|
|
sil [ossa] @dce_destructure3 : $@convention(thin) (@guaranteed NonTrivialStruct) -> () {
|
|
bb0(%0 : @guaranteed $NonTrivialStruct):
|
|
%1 = copy_value %0 : $NonTrivialStruct
|
|
%func = function_ref @$use_nontrivialstruct2 : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
%funcres = apply %func(%1) : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
(%2) = destructure_struct %1 : $NonTrivialStruct
|
|
destroy_value %2 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// This test shows that when we delete a dead instruction which has lifetime ending ops,
|
|
// we need to insert destroys of ops to end their lifetime correctly
|
|
// CHECK-LABEL: sil [ossa] @dce_insertdestroy1 :
|
|
// CHECK-NOT: struct
|
|
// CHECK-LABEL: } // end sil function 'dce_insertdestroy1'
|
|
sil [ossa] @dce_insertdestroy1 : $@convention(thin) (@owned Klass) -> () {
|
|
bb0(%0 : @owned $Klass):
|
|
%1 = copy_value %0 : $Klass
|
|
%func = function_ref @$use_klass2 : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%funcres = apply %func(%1) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%3 = struct $NonTrivialStruct(%1 : $Klass)
|
|
destroy_value %3 : $NonTrivialStruct
|
|
destroy_value %0 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// This test shows that when we delete a dead phi arg and its incoming values are live,
|
|
// we need to insert destroys of the incoming values in its pred blocks.
|
|
// CHECK-LABEL: sil [ossa] @dce_insertdestroy2 :
|
|
// CHECK: bb1(%3 : {{.*}})
|
|
// CHECK-NEXT: destroy_value %3
|
|
// CHECK-NEXT: br bb3
|
|
// CHECK-LABEL: } // end sil function 'dce_insertdestroy2'
|
|
sil [ossa] @dce_insertdestroy2 : $@convention(thin) (@guaranteed Klass) -> @error any Error {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%2 = function_ref @$testtryapplyklassgen : $@convention(thin) () -> (@owned Klass, @error any Error)
|
|
try_apply %2() : $@convention(thin) () -> (@owned Klass, @error any Error), normal bb1, error bb2
|
|
|
|
bb1(%3 : @owned $Klass):
|
|
br bb3(%3 : $Klass)
|
|
|
|
bb2(%4 : $Error):
|
|
throw %4 : $Error
|
|
|
|
bb3(%5 : @owned $Klass):
|
|
destroy_value %5 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_multiplerevdepdests :
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK-LABEL: } // end sil function 'dce_multiplerevdepdests'
|
|
sil [ossa] @dce_multiplerevdepdests : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%1 = copy_value %0 : $Klass
|
|
br bb1(%1 : $Klass)
|
|
|
|
bb1(%2 : @owned $Klass):
|
|
cond_br undef, bb2, bb3
|
|
|
|
bb2:
|
|
destroy_value %2 : $Klass
|
|
br bb4
|
|
|
|
bb3:
|
|
destroy_value %2 : $Klass
|
|
br bb4
|
|
|
|
bb4:
|
|
%res = tuple()
|
|
return %res : $()
|
|
}
|
|
|
|
struct TestStruct {
|
|
var val:Klass
|
|
var index:Int
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_destructurenotfullydead :
|
|
// CHECK-NOT: copy_value
|
|
// CHECK-LABEL: } // end sil function 'dce_destructurenotfullydead'
|
|
sil [ossa] @dce_destructurenotfullydead : $@convention(thin) (@owned TestStruct) -> Int {
|
|
bb0(%0 : @owned $TestStruct):
|
|
%stk = alloc_stack $TestStruct
|
|
store %0 to [init] %stk : $*TestStruct
|
|
%copy = load [take] %stk : $*TestStruct
|
|
(%2, %3) = destructure_struct %copy : $TestStruct
|
|
%4 = struct $TestStruct (%2 : $Klass, %3 : $Int)
|
|
destroy_value %4 : $TestStruct
|
|
dealloc_stack %stk : $*TestStruct
|
|
return %3 : $Int
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_borrowlifetime1 :
|
|
// CHECK: bb1([[ARG1:%.*]] : @owned $NonTrivialStruct, [[ARG2:%.*]] : @reborrow $NonTrivialStruct):
|
|
// CHECK-LABEL: } // end sil function 'dce_borrowlifetime1'
|
|
sil [ossa] @dce_borrowlifetime1 : $@convention(thin) (@guaranteed NonTrivialStruct) -> @owned NonTrivialStruct {
|
|
bb0(%0 : @guaranteed $NonTrivialStruct):
|
|
%copy = copy_value %0 : $NonTrivialStruct
|
|
%borrow = begin_borrow %copy : $NonTrivialStruct
|
|
br bb1(%copy : $NonTrivialStruct, %borrow : $NonTrivialStruct)
|
|
|
|
bb1(%copy2 : @owned $NonTrivialStruct, %borrow2 : @guaranteed $NonTrivialStruct):
|
|
%newcopy = copy_value %borrow2 : $NonTrivialStruct
|
|
end_borrow %borrow2 : $NonTrivialStruct
|
|
destroy_value %copy2 : $NonTrivialStruct
|
|
return %newcopy : $NonTrivialStruct
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_borrowlifetime2 :
|
|
// CHECK: bb1:
|
|
// CHECK-LABEL: } // end sil function 'dce_borrowlifetime2'
|
|
sil [ossa] @dce_borrowlifetime2 : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%copy = copy_value %0 : $Klass
|
|
%borrow = begin_borrow %copy : $Klass
|
|
%2 = function_ref @$use_klass2 : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%3 = apply %2(%borrow) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%5 = apply %2(%copy) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
br bb1(%copy : $Klass, %borrow : $Klass)
|
|
|
|
bb1(%copy2 : @owned $Klass, %borrow2 : @guaranteed $Klass):
|
|
end_borrow %borrow2 : $Klass
|
|
destroy_value %copy2 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_borrowlifetime3 :
|
|
// CHECK: bb1:
|
|
// CHECK-LABEL: } // end sil function 'dce_borrowlifetime3'
|
|
sil [ossa] @dce_borrowlifetime3 : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%copy = copy_value %0 : $Klass
|
|
%borrow = begin_borrow %copy : $Klass
|
|
%2 = function_ref @$use_klass2 : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%3 = apply %2(%borrow) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%5 = apply %2(%copy) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
br bb1(%borrow : $Klass, %copy : $Klass)
|
|
|
|
bb1(%borrow2 : @guaranteed $Klass, %copy2 : @owned $Klass):
|
|
end_borrow %borrow2 : $Klass
|
|
destroy_value %copy2 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_borrowlifetime4 :
|
|
// CHECK: bb1:
|
|
// CHECK-LABEL: } // end sil function 'dce_borrowlifetime4'
|
|
sil [ossa] @dce_borrowlifetime4 : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%copy = copy_value %0 : $Klass
|
|
%borrow = begin_borrow %copy : $Klass
|
|
%2 = function_ref @$use_klass2 : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%3 = apply %2(%borrow) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%5 = apply %2(%copy) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
br bb1(%borrow : $Klass)
|
|
|
|
bb1(%borrow2 : @guaranteed $Klass):
|
|
end_borrow %borrow2 : $Klass
|
|
br bb2(%copy : $Klass)
|
|
|
|
bb2(%copy2 : @owned $Klass):
|
|
destroy_value %copy2 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_borrowlifetime5 :
|
|
// CHECK: bb1:
|
|
// CHECK-LABEL: } // end sil function 'dce_borrowlifetime5'
|
|
sil [ossa] @dce_borrowlifetime5 : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%copy1 = copy_value %0 : $Klass
|
|
%copy2 = copy_value %0 : $Klass
|
|
%borrow1 = begin_borrow %copy1 : $Klass
|
|
%borrow2 = begin_borrow %copy2 : $Klass
|
|
%2 = function_ref @$use_klass2 : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%3 = apply %2(%borrow1) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%4 = apply %2(%borrow2) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%5 = apply %2(%copy1) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%6 = apply %2(%copy2) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
br bb1(%copy1 : $Klass, %borrow1 : $Klass, %borrow2 : $Klass)
|
|
|
|
bb1(%newcopy : @owned $Klass, %newborrow1 : @guaranteed $Klass, %newborrow2 : @guaranteed $Klass):
|
|
end_borrow %newborrow1 : $Klass
|
|
end_borrow %newborrow2 : $Klass
|
|
destroy_value %newcopy : $Klass
|
|
destroy_value %copy2 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// Nested borrows are currently not optimized in DCE
|
|
sil [ossa] @dce_nestedborrowlifetime1 : $@convention(thin) (@guaranteed NonTrivialStruct) -> @owned NonTrivialStruct {
|
|
bb0(%0 : @guaranteed $NonTrivialStruct):
|
|
%borrowo = begin_borrow %0 : $NonTrivialStruct
|
|
%borrow = begin_borrow %borrowo : $NonTrivialStruct
|
|
br bb1(%borrowo : $NonTrivialStruct, %borrow : $NonTrivialStruct)
|
|
|
|
bb1(%newborrowo : @guaranteed $NonTrivialStruct, %borrow2 : @guaranteed $NonTrivialStruct):
|
|
%newcopy = copy_value %borrow2 : $NonTrivialStruct
|
|
end_borrow %borrow2 : $NonTrivialStruct
|
|
end_borrow %newborrowo : $NonTrivialStruct
|
|
return %newcopy : $NonTrivialStruct
|
|
}
|
|
|
|
sil [ossa] @dce_nestedborrowlifetime2 : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%borrowo = begin_borrow %0 : $Klass
|
|
%borrow = begin_borrow %borrowo : $Klass
|
|
%2 = function_ref @$use_klass2 : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%3 = apply %2(%borrow) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%5 = apply %2(%borrowo) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
br bb1(%borrowo : $Klass, %borrow : $Klass)
|
|
|
|
bb1(%newborrow : @guaranteed $Klass, %borrow2 : @guaranteed $Klass):
|
|
end_borrow %borrow2 : $Klass
|
|
end_borrow %newborrow : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// This test shows it is non trivial to find the insert point of an outer reborrow.
|
|
// Here %newborrowo and %newborrowi are both dead phis.
|
|
// First end_borrow for the incoming value of %newborrowi is added
|
|
// It is non straight forward to find the insert pt for the end_borrow of the incoming value of %newborrowo
|
|
// This may not be important once OSSACanonicalizeOwned supports rewrite of multi-block borrows.
|
|
sil [ossa] @dce_nestedborrowlifetime3 : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%borrowo = begin_borrow %0 : $Klass
|
|
%borrow = begin_borrow %borrowo : $Klass
|
|
%2 = function_ref @$use_klass2 : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%3 = apply %2(%borrow) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%5 = apply %2(%borrowo) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
br bb1(%borrow : $Klass, %borrowo : $Klass)
|
|
|
|
bb1(%newborrowi : @guaranteed $Klass, %newborrowo : @guaranteed $Klass):
|
|
end_borrow %newborrowi : $Klass
|
|
end_borrow %newborrowo : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
|
|
sil [ossa] @dce_nestedborrowlifetime4 : $@convention(thin) (@guaranteed Wrapper1, @guaranteed Wrapper1) -> () {
|
|
bb0(%0 : @guaranteed $Wrapper1, %1 : @guaranteed $Wrapper1):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%outer1 = begin_borrow %0 : $Wrapper1
|
|
%ex1 = struct_extract %outer1 : $Wrapper1, #Wrapper1.val1
|
|
%ex11 = struct_extract %ex1 : $Wrapper2, #Wrapper2.val2
|
|
br bb3(%ex11 : $Klass, %outer1 : $Wrapper1)
|
|
|
|
bb2:
|
|
%outer2 = begin_borrow %1 : $Wrapper1
|
|
%ex2 = struct_extract %outer2 : $Wrapper1, #Wrapper1.val1
|
|
%ex21 = struct_extract %ex2 : $Wrapper2, #Wrapper2.val2
|
|
br bb3(%ex21 : $Klass, %outer2 : $Wrapper1)
|
|
|
|
bb3(%phi1 : @guaranteed $Klass, %phi2 : @guaranteed $Wrapper1):
|
|
%f = function_ref @use_klass : $@convention(thin) (@guaranteed Klass) -> ()
|
|
apply %f(%phi1) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %phi2 : $Wrapper1
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
sil [ossa] @dce_nestedborrowlifetime5 : $@convention(thin) (@guaranteed Wrapper1) -> () {
|
|
bb0(%0 : @guaranteed $Wrapper1):
|
|
%outer1 = begin_borrow %0 : $Wrapper1
|
|
%inner1 = begin_borrow %outer1 : $Wrapper1
|
|
%ex1 = struct_extract %inner1 : $Wrapper1, #Wrapper1.val1
|
|
%ex11 = struct_extract %ex1 : $Wrapper2, #Wrapper2.val2
|
|
br bb2(%ex11 : $Klass, %inner1 : $Wrapper1)
|
|
|
|
bb2(%phi1 : @guaranteed $Klass, %phi2 : @guaranteed $Wrapper1):
|
|
%f = function_ref @use_klass : $@convention(thin) (@guaranteed Klass) -> ()
|
|
apply %f(%phi1) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %phi2 : $Wrapper1
|
|
end_borrow %outer1 : $Wrapper1
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @infinite_loop :
|
|
// CHECK-NOT: copy_value
|
|
// CHECK-LABEL: } // end sil function 'infinite_loop'
|
|
sil [ossa] @infinite_loop : $@convention(thin) (@guaranteed NonTrivialStruct, @guaranteed NonTrivialStruct) -> () {
|
|
bb0(%0 : @guaranteed $NonTrivialStruct, %1 : @guaranteed $NonTrivialStruct):
|
|
cond_br undef, bb1, bb4
|
|
|
|
bb1:
|
|
%copy0 = copy_value %0 : $NonTrivialStruct
|
|
%borrow0 = begin_borrow %copy0 : $NonTrivialStruct
|
|
br bb3(%borrow0 : $NonTrivialStruct, %copy0 : $NonTrivialStruct)
|
|
|
|
bb3(%newborrow : @guaranteed $NonTrivialStruct, %newowned : @owned $NonTrivialStruct):
|
|
br bb3(%newborrow : $NonTrivialStruct, %newowned : $NonTrivialStruct)
|
|
|
|
bb4:
|
|
%ret = tuple ()
|
|
return %ret : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_reborrow_with_different_basevalues :
|
|
// CHECK: bb3([[ARG1:%.*]] : @reborrow $NonTrivialStruct, [[ARG2:%.*]] : @owned $NonTrivialStruct, [[ARG3:%.*]] : @owned $NonTrivialStruct):
|
|
// CHECK-LABEL: } // end sil function 'dce_reborrow_with_different_basevalues'
|
|
sil [ossa] @dce_reborrow_with_different_basevalues : $@convention(thin) (@guaranteed NonTrivialStruct, @guaranteed NonTrivialStruct) -> @owned NonTrivialStruct {
|
|
bb0(%0 : @guaranteed $NonTrivialStruct, %1 : @guaranteed $NonTrivialStruct):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%copy0a = copy_value %0 : $NonTrivialStruct
|
|
%borrow0a = begin_borrow %copy0a : $NonTrivialStruct
|
|
%copy1a = copy_value %1 : $NonTrivialStruct
|
|
br bb3(%borrow0a : $NonTrivialStruct, %copy0a : $NonTrivialStruct, %copy1a : $NonTrivialStruct)
|
|
|
|
bb2:
|
|
%copy1b = copy_value %1 : $NonTrivialStruct
|
|
%borrow0b = begin_borrow %copy1b : $NonTrivialStruct
|
|
%copy0b = copy_value %0 : $NonTrivialStruct
|
|
br bb3(%borrow0b : $NonTrivialStruct, %copy0b : $NonTrivialStruct, %copy1b : $NonTrivialStruct)
|
|
|
|
bb3(%newborrow : @guaranteed $NonTrivialStruct, %newowned1 : @owned $NonTrivialStruct, %newowned2 : @owned $NonTrivialStruct):
|
|
%res = copy_value %newborrow : $NonTrivialStruct
|
|
end_borrow %newborrow : $NonTrivialStruct
|
|
destroy_value %newowned1 : $NonTrivialStruct
|
|
destroy_value %newowned2 : $NonTrivialStruct
|
|
return %res : $NonTrivialStruct
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_deadterm1 :
|
|
// CHECK-NOT: switch_enum
|
|
// CHECK-LABEL: } // end sil function 'dce_deadterm1'
|
|
sil [ossa] @dce_deadterm1 : $@convention(thin) (@owned FakeOptional<Builtin.NativeObject>) -> () {
|
|
bb0(%0 : @owned $FakeOptional<Builtin.NativeObject>):
|
|
%0a = alloc_stack $FakeOptional<Builtin.NativeObject>
|
|
store %0 to [init] %0a : $*FakeOptional<Builtin.NativeObject>
|
|
%1 = load [take] %0a : $*FakeOptional<Builtin.NativeObject>
|
|
switch_enum %1 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
|
|
|
|
bb1(%2 : @owned $Builtin.NativeObject):
|
|
destroy_value %2 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
dealloc_stack %0a : $*FakeOptional<Builtin.NativeObject>
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_deadterm2 :
|
|
// CHECK-NOT: load [copy]
|
|
// CHECK-NOT: switch_enum
|
|
// CHECK-LABEL: } // end sil function 'dce_deadterm2'
|
|
sil [ossa] @dce_deadterm2 : $@convention(thin) (@owned FakeOptional<Builtin.NativeObject>) -> () {
|
|
bb0(%0 : @owned $FakeOptional<Builtin.NativeObject>):
|
|
%0a = alloc_stack $FakeOptional<Builtin.NativeObject>
|
|
store %0 to [init] %0a : $*FakeOptional<Builtin.NativeObject>
|
|
%1 = load [copy] %0a : $*FakeOptional<Builtin.NativeObject>
|
|
switch_enum %1 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
|
|
|
|
bb1(%2 : @owned $Builtin.NativeObject):
|
|
destroy_value %2 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
destroy_addr %0a : $*FakeOptional<Builtin.NativeObject>
|
|
dealloc_stack %0a : $*FakeOptional<Builtin.NativeObject>
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_deadendlifetime1 :
|
|
// CHECK-NOT: end_lifetime
|
|
// CHECK-LABEL: } // end sil function 'dce_deadendlifetime1'
|
|
sil [ossa] @dce_deadendlifetime1 : $@convention(thin) () -> () {
|
|
bb0:
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb3(undef : $Klass)
|
|
|
|
bb2:
|
|
br bb3(undef : $Klass)
|
|
|
|
bb3(%2 : @owned $Klass):
|
|
end_lifetime %2 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_deadendlifetime2 :
|
|
// CHECK-NOT: end_lifetime
|
|
// CHECK-LABEL: } // end sil function 'dce_deadendlifetime2'
|
|
sil [ossa] @dce_deadendlifetime2 : $@convention(thin) () -> () {
|
|
bb0:
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb3(undef : $Klass)
|
|
|
|
bb2:
|
|
br bb3(undef : $Klass)
|
|
|
|
bb3(%2 : @owned $Klass):
|
|
br bb4(%2 : $Klass)
|
|
|
|
bb4(%3 : @owned $Klass):
|
|
end_lifetime %3 : $Klass
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @looping_borrow : $@convention(thin) () -> () {
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK-LABEL: } // end sil function 'looping_borrow'
|
|
sil [ossa] @looping_borrow : $@convention(thin) () -> () {
|
|
entry:
|
|
%instance_1 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
|
|
%lifetime_1 = begin_borrow %instance_1 : $FakeOptional<Klass>
|
|
br loop_entry(%instance_1 : $FakeOptional<Klass>, %lifetime_1 : $FakeOptional<Klass>)
|
|
|
|
loop_entry(%18 : @owned $FakeOptional<Klass>, %19 : @guaranteed $FakeOptional<Klass>):
|
|
br loop_body
|
|
|
|
loop_body:
|
|
cond_br undef, loop_back, loop_exit
|
|
|
|
loop_back:
|
|
br loop_entry(%18 : $FakeOptional<Klass>, %19 : $FakeOptional<Klass>)
|
|
|
|
loop_exit:
|
|
end_borrow %19 : $FakeOptional<Klass>
|
|
destroy_value %18 : $FakeOptional<Klass>
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @add_end_borrow_after_destroy_value : {{.*}} {
|
|
// CHECK: bb0({{%[^,]+}} : $Builtin.Int1, [[INSTANCE_1:%[^,]+]] : @owned $Klass, {{%[^,]+}} : @owned $Klass):
|
|
// CHECK: [[LIFETIME_1:%[^,]+]] = begin_borrow [[INSTANCE_1]]
|
|
// CHECK: copy_value [[LIFETIME_1]]
|
|
// CHECK: cond_br {{%[^,]+}}, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
|
|
// CHECK: [[LEFT]]:
|
|
// CHECK: end_borrow [[LIFETIME_1]]
|
|
// CHECK: destroy_value [[INSTANCE_1]]
|
|
// CHECK: [[RIGHT]]:
|
|
// CHECK: end_borrow [[LIFETIME_1]]
|
|
// CHECK: destroy_value [[INSTANCE_1]]
|
|
// CHECK-LABEL: } // end sil function 'add_end_borrow_after_destroy_value'
|
|
sil hidden [ossa] @add_end_borrow_after_destroy_value : $@convention(thin) (Builtin.Int1, @owned Klass, @owned Klass) -> () {
|
|
bb0(%condition : $Builtin.Int1, %instance_1 : @owned $Klass, %instance_2 : @owned $Klass):
|
|
%lifetime_1 = begin_borrow %instance_1 : $Klass
|
|
|
|
%copy_1 = copy_value %lifetime_1 : $Klass
|
|
%stack_addr = alloc_stack $Klass
|
|
store %copy_1 to [init] %stack_addr : $*Klass
|
|
destroy_addr %stack_addr : $*Klass
|
|
dealloc_stack %stack_addr : $*Klass
|
|
|
|
cond_br %condition, bb1, bb2
|
|
|
|
bb1:
|
|
end_borrow %lifetime_1 : $Klass
|
|
destroy_value %instance_1 : $Klass
|
|
%lifetime_2 = begin_borrow %instance_2 : $Klass
|
|
br bb3(%instance_2 : $Klass, %lifetime_2 : $Klass)
|
|
|
|
bb2:
|
|
destroy_value %instance_2 : $Klass
|
|
br bb3(%instance_1 : $Klass, %lifetime_1 : $Klass)
|
|
|
|
bb3(%original : @owned $Klass, %lifetime : @guaranteed $Klass):
|
|
end_borrow %lifetime : $Klass
|
|
destroy_value %original : $Klass
|
|
%result = tuple ()
|
|
return %result : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @borrow_none : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}:
|
|
// CHECK-NEXT: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK-NEXT: [[RETVAL:%[^,]+]] = tuple ()
|
|
// CHECK-NEXT: return [[RETVAL]] : $()
|
|
// CHECK-LABEL: } // end sil function 'borrow_none'
|
|
sil [ossa] @borrow_none : $@convention(thin) () -> () {
|
|
entry:
|
|
%outer_lifetime_1 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
|
|
switch_enum %outer_lifetime_1 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: work, case #FakeOptional.none!enumelt: to_exit, forwarding: @guaranteed
|
|
to_exit:
|
|
br exit
|
|
work(%outer_lifetime_2 : @guaranteed $Klass):
|
|
%inner_lifetime_1 = begin_borrow %outer_lifetime_2 : $Klass
|
|
end_borrow %inner_lifetime_1 : $Klass
|
|
br exit
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @reborrowed_begin_borrow : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $Klass):
|
|
// CHECK: [[OUTER_LIFETIME_1:%[^,]+]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]([[OUTER_LIFETIME_1]] : $Klass)
|
|
// CHECK: [[EXIT]]([[OUTER_LIFETIME_2:%[^,]+]] : @reborrow $Klass):
|
|
// CHECK: [[R:%.*]] = borrowed [[OUTER_LIFETIME_2]] : $Klass from (%0 : $Klass)
|
|
// CHECK: end_borrow [[R]]
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
|
|
// CHECK: return [[RETVAL]]
|
|
// CHECK-LABEL: } // end sil function 'reborrowed_begin_borrow'
|
|
sil [ossa] @reborrowed_begin_borrow : $@convention(thin) (@owned Klass) -> () {
|
|
entry(%instance : @owned $Klass):
|
|
%outer_lifetime_1 = begin_borrow %instance : $Klass
|
|
%inner_lifetime_1 = begin_borrow %outer_lifetime_1 : $Klass
|
|
br exit(%outer_lifetime_1 : $Klass, %inner_lifetime_1 : $Klass)
|
|
exit(%outer_lifetime_2 : @guaranteed $Klass, %inner_lifetime_2 : @guaranteed $Klass):
|
|
end_borrow %inner_lifetime_2 : $Klass
|
|
end_borrow %outer_lifetime_2 : $Klass
|
|
destroy_value %instance : $Klass
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @reborrowed_guaranteed_phi : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $Klass):
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
|
|
// CHECK: br [[WORK:bb[0-9]+]]([[LIFETIME]] : $Klass)
|
|
// CHECK: [[WORK]]([[LIFETIME_1:%[^,]+]] : @reborrow $Klass):
|
|
// CHECK: [[R:%.*]] = borrowed [[LIFETIME_1]] : $Klass from (%0 : $Klass)
|
|
// CHECK: br [[EXIT:bb[0-9]+]]([[R]] : $Klass)
|
|
// CHECK: [[EXIT]]([[LIFETIME_2:%[^,]+]] : @reborrow $Klass):
|
|
// CHECK: [[R2:%.*]] = borrowed [[LIFETIME_2]] : $Klass from (%0 : $Klass)
|
|
// CHECK: end_borrow [[R2]]
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
|
|
// CHECK: return [[RETVAL]] : $()
|
|
// CHECK-LABEL: } // end sil function 'reborrowed_guaranteed_phi'
|
|
sil [ossa] @reborrowed_guaranteed_phi : $@convention(thin) (@owned Klass) -> () {
|
|
entry(%instance : @owned $Klass):
|
|
%outer_lifetime_1 = begin_borrow %instance : $Klass
|
|
br work(%outer_lifetime_1 : $Klass)
|
|
work(%outer_lifetime_2 : @guaranteed $Klass):
|
|
%inner_lifetime_1 = begin_borrow %outer_lifetime_2 : $Klass
|
|
br exit(%outer_lifetime_2 : $Klass, %inner_lifetime_1 : $Klass)
|
|
exit(%outer_lifetime_3 : @guaranteed $Klass, %inner_lifetime_2 : @guaranteed $Klass):
|
|
end_borrow %inner_lifetime_2 : $Klass
|
|
end_borrow %outer_lifetime_3 : $Klass
|
|
destroy_value %instance : $Klass
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @reborrow_guaranteed_phi2 : {{.*}} {
|
|
// CHECK-NOT: switch_enum
|
|
// CHECK-LABEL: } // end sil function 'reborrow_guaranteed_phi2'
|
|
sil [ossa] @reborrow_guaranteed_phi2 : $@convention(thin) (@owned EitherNoneOrAnyObject) -> () {
|
|
entry(%0 : @owned $EitherNoneOrAnyObject):
|
|
%borrow_either = begin_borrow %0 : $EitherNoneOrAnyObject
|
|
switch_enum %borrow_either : $EitherNoneOrAnyObject, case #EitherNoneOrAnyObject.none!enumelt: none_block, case #EitherNoneOrAnyObject.any!enumelt: any_block
|
|
|
|
any_block(%borrow : @guaranteed $AnyObject):
|
|
%2 = begin_borrow %borrow : $AnyObject
|
|
end_borrow %2 : $AnyObject
|
|
end_borrow %borrow_either : $EitherNoneOrAnyObject
|
|
destroy_value %0 : $EitherNoneOrAnyObject
|
|
br exit
|
|
|
|
none_block:
|
|
end_borrow %borrow_either : $EitherNoneOrAnyObject
|
|
destroy_value %0 : $EitherNoneOrAnyObject
|
|
br exit
|
|
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @reborrowed_guaranteed_phi3 :
|
|
// CHECK: begin_borrow
|
|
// CHECK-NOT: begin_borrow
|
|
// CHECK-LABEL: } // end sil function 'reborrowed_guaranteed_phi3'
|
|
sil [ossa] @reborrowed_guaranteed_phi3 : $@convention(thin) (@owned Klass) -> () {
|
|
entry(%instance : @owned $Klass):
|
|
%outer_lifetime_1 = begin_borrow %instance : $Klass
|
|
%inner_lifetime_1 = begin_borrow %outer_lifetime_1 : $Klass
|
|
br exit(%inner_lifetime_1 : $Klass)
|
|
exit(%inner_lifetime_2 : @guaranteed $Klass):
|
|
end_borrow %inner_lifetime_2 : $Klass
|
|
end_borrow %outer_lifetime_1 : $Klass
|
|
destroy_value %instance : $Klass
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @reborrow_load_borrow : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : $*Klass):
|
|
// CHECK: [[LIFETIME:%[^,]+]] = load_borrow [[INSTANCE]]
|
|
// CHECK: br [[BASIC_BLOCK1:bb[0-9]+]]([[LIFETIME]] : $Klass)
|
|
// CHECK: [[BASIC_BLOCK1]]([[LIFETIME_2:%[^,]+]] : @reborrow $Klass):
|
|
// CHECK: [[R:%.*]] = borrowed [[LIFETIME_2]] : $Klass from ()
|
|
// CHECK: end_borrow [[R]]
|
|
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
|
|
// CHECK: return [[RETVAL]]
|
|
// CHECK-LABEL: } // end sil function 'reborrow_load_borrow'
|
|
sil [ossa] @reborrow_load_borrow : $@convention(method) (@in Klass) -> () {
|
|
bb0(%0 : $*Klass):
|
|
%1 = load_borrow %0 : $*Klass
|
|
%2 = begin_borrow %1 : $Klass
|
|
br bb1(%1 : $Klass, %2 : $Klass)
|
|
bb1(%4 : @guaranteed $Klass, %5 : @guaranteed $Klass):
|
|
end_borrow %5 : $Klass
|
|
end_borrow %4 : $Klass
|
|
%8 = tuple ()
|
|
return %8 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @reborrow_load_borrow2 : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[ADDR:%[^,]+]] : $*Klass):
|
|
// CHECK: [[LIFETIME:%[^,]+]] = load_borrow [[ADDR]] : $*Klass
|
|
// CHECK: br [[EXIT:bb[0-9]+]]([[LIFETIME]] : $Klass)
|
|
// CHECK: [[EXIT]]([[LIFETIME_2:%[^,]+]] : @reborrow $Klass):
|
|
// CHECK: [[R:%.*]] = borrowed [[LIFETIME_2]] : $Klass from ()
|
|
// CHECK: end_borrow [[R]] : $Klass
|
|
// CHECK: [[EXIT:%[^,]+]] = tuple ()
|
|
// CHECK: return [[EXIT]] : $()
|
|
// CHECK-LABEL: } // end sil function 'reborrow_load_borrow2'
|
|
sil [ossa] @reborrow_load_borrow2 : $@convention(method) (@in Klass) -> () {
|
|
bb0(%0 : $*Klass):
|
|
%1 = load_borrow %0 : $*Klass
|
|
%2 = begin_borrow %1 : $Klass
|
|
br bb1(%2 : $Klass, %1 : $Klass)
|
|
bb1(%4 : @guaranteed $Klass, %5 : @guaranteed $Klass):
|
|
end_borrow %4 : $Klass
|
|
end_borrow %5 : $Klass
|
|
%8 = tuple ()
|
|
return %8 : $()
|
|
}
|
|
|
|
class Wrapper {
|
|
let val: Klass
|
|
}
|
|
|
|
class DoubleWrapper {
|
|
let s: StructWrapper
|
|
}
|
|
|
|
struct StructWrapper {
|
|
let val: Klass
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @reborrow_load_borrow3 : $@convention(method) (@owned Wrapper) -> () {
|
|
// CHECK: load_borrow
|
|
// CHECK: end_borrow
|
|
// CHECK: br bb1
|
|
// CHECK-LABEL: } // end sil function 'reborrow_load_borrow3'
|
|
sil [ossa] @reborrow_load_borrow3 : $@convention(method) (@owned Wrapper) -> () {
|
|
bb0(%0 : @owned $Wrapper):
|
|
%1 = begin_borrow %0 : $Wrapper
|
|
%2 = ref_element_addr %1 : $Wrapper, #Wrapper.val
|
|
%3 = load_borrow %2 : $*Klass
|
|
%f = function_ref @use_klass : $@convention(thin) (@guaranteed Klass) -> ()
|
|
apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
br bb1(%1 : $Wrapper, %3 : $Klass)
|
|
|
|
bb1(%4 : @guaranteed $Wrapper, %5 : @guaranteed $Klass):
|
|
end_borrow %5 : $Klass
|
|
end_borrow %4 : $Wrapper
|
|
destroy_value %0 : $Wrapper
|
|
%8 = tuple ()
|
|
return %8 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @reborrow_load_borrow4 : $@convention(method) (@owned DoubleWrapper) -> () {
|
|
// CHECK: load_borrow
|
|
// CHECK: end_borrow
|
|
// CHECK: br bb1
|
|
// CHECK-LABEL: } // end sil function 'reborrow_load_borrow4'
|
|
sil [ossa] @reborrow_load_borrow4 : $@convention(method) (@owned DoubleWrapper) -> () {
|
|
bb0(%0 : @owned $DoubleWrapper):
|
|
%1 = begin_borrow %0 : $DoubleWrapper
|
|
%2 = ref_element_addr %1 : $DoubleWrapper, #DoubleWrapper.s
|
|
%4 = struct_element_addr %2 : $*StructWrapper, #StructWrapper.val
|
|
%5 = load_borrow %4 : $*Klass
|
|
%f = function_ref @use_klass : $@convention(thin) (@guaranteed Klass) -> ()
|
|
apply %f(%5) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
br bb1(%1 : $DoubleWrapper, %5 : $Klass)
|
|
|
|
bb1(%6 : @guaranteed $DoubleWrapper, %7 : @guaranteed $Klass):
|
|
end_borrow %7 : $Klass
|
|
end_borrow %6 : $DoubleWrapper
|
|
destroy_value %0 : $DoubleWrapper
|
|
%8 = tuple ()
|
|
return %8 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @borrow_guaranteed_tuple : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE_1:%[^,]+]] : @owned $Klass, [[INSTANCE_2:%[^,]+]] : @owned $Klass):
|
|
// CHECK: destroy_value [[INSTANCE_2]]
|
|
// CHECK: destroy_value [[INSTANCE_1]]
|
|
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
|
|
// CHECK: return [[RETVAL]] : $()
|
|
// CHECK-LABEL: } // end sil function 'borrow_guaranteed_tuple'
|
|
sil [ossa] @borrow_guaranteed_tuple : $@convention(thin) (@owned Klass, @owned Klass) -> () {
|
|
entry(%instance_1 : @owned $Klass, %instance_2 : @owned $Klass):
|
|
%lifetime_1_1 = begin_borrow %instance_1 : $Klass
|
|
%lifetime_2_1 = begin_borrow %instance_2 : $Klass
|
|
%tuple = tuple $(Klass, Klass) (%lifetime_1_1, %lifetime_2_1)
|
|
br exit(%lifetime_1_1 : $Klass, %lifetime_2_1 : $Klass, %tuple : $(Klass, Klass))
|
|
exit(%lifetime_1_2 : @guaranteed $Klass, %lifetime_2_2 : @guaranteed $Klass, %tuple_2 : @guaranteed $(Klass, Klass)):
|
|
end_borrow %lifetime_2_2 : $Klass
|
|
destroy_value %instance_2 : $Klass
|
|
end_borrow %lifetime_1_2 : $Klass
|
|
destroy_value %instance_1 : $Klass
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @borrow_guaranteed_struct : {{.*}} {
|
|
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $Klass):
|
|
// CHECK: destroy_value [[INSTANCE]]
|
|
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
|
|
// CHECK: return [[RETVAL]] : $()
|
|
// CHECK-LABEL: } // end sil function 'borrow_guaranteed_struct'
|
|
sil [ossa] @borrow_guaranteed_struct : $@convention(thin) (@owned Klass) -> () {
|
|
entry(%instance_1 : @owned $Klass):
|
|
%lifetime_1 = begin_borrow %instance_1 : $Klass
|
|
%struct = struct $NonTrivialStruct (%lifetime_1 : $Klass)
|
|
br exit(%lifetime_1 : $Klass, %struct : $NonTrivialStruct)
|
|
exit(%lifetime_2 : @guaranteed $Klass, %struct_2 : @guaranteed $NonTrivialStruct):
|
|
end_borrow %lifetime_2 : $Klass
|
|
destroy_value %instance_1 : $Klass
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
sil [ossa] @testBorrowedSwitch : $@convention(thin) (Optional<@sil_unmanaged AnyObject>) -> () {
|
|
bb0(%0 : $Optional<@sil_unmanaged AnyObject>):
|
|
switch_enum %0 : $Optional<@sil_unmanaged AnyObject>, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2
|
|
|
|
bb1(%2 : $@sil_unmanaged AnyObject):
|
|
%3 = unmanaged_to_ref %2 : $@sil_unmanaged AnyObject to $AnyObject
|
|
%4 = unchecked_ownership_conversion %3 : $AnyObject, @unowned to @guaranteed
|
|
%5 = begin_borrow [lexical] %4 : $AnyObject
|
|
end_borrow %5 : $AnyObject
|
|
end_borrow %4 : $AnyObject
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
%242 = tuple ()
|
|
return %242 : $()
|
|
}
|
|
|
|
// rdar://87985420 - crash in nullptr returned by findGuaranteedReferenceRoots
|
|
// Test that a borrow scope introduced by unchecked_ownership_conversion is not
|
|
// deleted by DCE.
|
|
sil [ossa] @testUncheckedConvertToGuaranteed : $@convention(thin) (@sil_unmanaged AnyObject) -> () {
|
|
bb0(%0 : $@sil_unmanaged AnyObject):
|
|
%3 = unmanaged_to_ref %0 : $@sil_unmanaged AnyObject to $AnyObject
|
|
%4 = unchecked_ownership_conversion %3 : $AnyObject, @unowned to @guaranteed
|
|
%5 = begin_borrow [lexical] %4 : $AnyObject
|
|
end_borrow %5 : $AnyObject
|
|
end_borrow %4 : $AnyObject
|
|
%242 = tuple ()
|
|
return %242 : $()
|
|
}
|
|
|
|
sil @foo : $@convention(thin) () -> ()
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_escape1 : {{.*}} {
|
|
// CHECK: br bb1
|
|
// CHECK: end_borrow
|
|
// CHECK-LABEL: } // end sil function 'test_escape1'
|
|
sil [ossa] @test_escape1 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%13 = function_ref @foo : $@convention(thin) () -> ()
|
|
%14 = partial_apply [callee_guaranteed] %13() : $@convention(thin) () -> ()
|
|
%15 = convert_escape_to_noescape %14 : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
|
|
%17 = begin_borrow %14 : $@callee_guaranteed () -> ()
|
|
%18 = mark_dependence %15 : $@noescape @callee_guaranteed () -> () on %17 : $@callee_guaranteed () -> ()
|
|
br bb1(%18 : $@noescape @callee_guaranteed () -> (), %17 : $@callee_guaranteed () -> (), %14 : $@callee_guaranteed () -> ())
|
|
|
|
bb1(%21 : @owned $@noescape @callee_guaranteed () -> (), %22 : @guaranteed $@callee_guaranteed () -> (), %23 : @owned $@callee_guaranteed () -> ()):
|
|
%27 = apply %21() : $@noescape @callee_guaranteed () -> ()
|
|
destroy_value %21 : $@noescape @callee_guaranteed () -> ()
|
|
end_borrow %22 : $@callee_guaranteed () -> ()
|
|
destroy_value %23 : $@callee_guaranteed () -> ()
|
|
%28 = tuple ()
|
|
return %28: $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_escape2 : {{.*}} {
|
|
// CHECK: br bb1
|
|
// CHECK: destroy_value
|
|
// CHECK: destroy_value
|
|
// CHECK-LABEL: } // end sil function 'test_escape2'
|
|
sil [ossa] @test_escape2 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%13 = function_ref @foo : $@convention(thin) () -> ()
|
|
%14 = partial_apply [callee_guaranteed] %13() : $@convention(thin) () -> ()
|
|
%15 = convert_escape_to_noescape %14 : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
|
|
%18 = mark_dependence %15 : $@noescape @callee_guaranteed () -> () on %14 : $@callee_guaranteed () -> ()
|
|
br bb1(%18 : $@noescape @callee_guaranteed () -> (), %14 : $@callee_guaranteed () -> ())
|
|
|
|
bb1(%21 : @owned $@noescape @callee_guaranteed () -> (), %23 : @owned $@callee_guaranteed () -> ()):
|
|
%27 = apply %21() : $@noescape @callee_guaranteed () -> ()
|
|
destroy_value %21 : $@noescape @callee_guaranteed () -> ()
|
|
destroy_value %23 : $@callee_guaranteed () -> ()
|
|
%28 = tuple ()
|
|
return %28: $()
|
|
}
|
|
|
|
sil @use_klass : $@convention(thin) (@guaranteed Klass) -> ()
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_forwarded_phi1 :
|
|
// CHECK: br bb3
|
|
// CHECK: end_borrow
|
|
// CHECK-LABEL: } // end sil function 'test_forwarded_phi1'
|
|
sil [ossa] @test_forwarded_phi1 : $@convention(thin) (@owned Wrapper1) -> () {
|
|
bb0(%0 : @owned $Wrapper1):
|
|
%outer = begin_borrow %0 : $Wrapper1
|
|
br bb1
|
|
|
|
bb1:
|
|
%ex1 = struct_extract %outer : $Wrapper1, #Wrapper1.val1
|
|
br bb2(%ex1 : $Wrapper2, %outer : $Wrapper1)
|
|
|
|
bb2(%phi1 : @guaranteed $Wrapper2, %phi2 : @guaranteed $Wrapper1):
|
|
%ex2 = struct_extract %phi1 : $Wrapper2, #Wrapper2.val2
|
|
br bb3(%ex2 : $Klass, %phi2 : $Wrapper1)
|
|
|
|
bb3(%phi3 : @guaranteed $Klass, %phi4 : @guaranteed $Wrapper1):
|
|
%f = function_ref @use_klass : $@convention(thin) (@guaranteed Klass) -> ()
|
|
apply %f(%phi3) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %phi4 : $Wrapper1
|
|
destroy_value %0 : $Wrapper1
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_forwarded_phi2 :
|
|
// CHECK: br bb3
|
|
// CHECK: end_borrow
|
|
// CHECK-LABEL: } // end sil function 'test_forwarded_phi2'
|
|
sil [ossa] @test_forwarded_phi2 : $@convention(thin) (@owned Wrapper1) -> () {
|
|
bb0(%0 : @owned $Wrapper1):
|
|
%outer = begin_borrow %0 : $Wrapper1
|
|
br bb1
|
|
|
|
bb1:
|
|
br bb2(%outer : $Wrapper1)
|
|
|
|
bb2(%phi1 : @guaranteed $Wrapper1):
|
|
%ex1 = struct_extract %phi1 : $Wrapper1, #Wrapper1.val1 // user: %4
|
|
%ex2 = struct_extract %ex1 : $Wrapper2, #Wrapper2.val2
|
|
br bb3(%ex2 : $Klass, %phi1 : $Wrapper1)
|
|
|
|
bb3(%phi2 : @guaranteed $Klass, %phi3 : @guaranteed $Wrapper1):
|
|
%f = function_ref @use_klass : $@convention(thin) (@guaranteed Klass) -> ()
|
|
apply %f(%phi2) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %phi3 : $Wrapper1
|
|
destroy_value %0 : $Wrapper1
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_forwarded_phi3 :
|
|
// CHECK: end_borrow
|
|
// CHECK: br bb3
|
|
// CHECK-LABEL: } // end sil function 'test_forwarded_phi3'
|
|
sil [ossa] @test_forwarded_phi3 : $@convention(thin) (@owned Wrapper1) -> () {
|
|
bb0(%0 : @owned $Wrapper1):
|
|
%outer = begin_borrow %0 : $Wrapper1
|
|
br bb1
|
|
|
|
bb1:
|
|
br bb2(%outer : $Wrapper1)
|
|
|
|
bb2(%phi1 : @guaranteed $Wrapper1):
|
|
%ex1 = struct_extract %phi1 : $Wrapper1, #Wrapper1.val1 // user: %4
|
|
%ex2 = struct_extract %ex1 : $Wrapper2, #Wrapper2.val2
|
|
%f = function_ref @use_klass : $@convention(thin) (@guaranteed Klass) -> ()
|
|
apply %f(%ex2) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
br bb3(%ex2 : $Klass, %phi1 : $Wrapper1)
|
|
|
|
bb3(%phi2 : @guaranteed $Klass, %phi3 : @guaranteed $Wrapper1):
|
|
end_borrow %phi3 : $Wrapper1
|
|
destroy_value %0 : $Wrapper1
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_loadborrow_dep :
|
|
// CHECK: br bb3
|
|
// CHECK: end_borrow
|
|
// CHECK-LABEL: } // end sil function 'test_loadborrow_dep'
|
|
sil [ossa] @test_loadborrow_dep : $@convention(thin) (@in Wrapper1) -> () {
|
|
bb0(%0 : $*Wrapper1):
|
|
%outer = load_borrow %0 : $*Wrapper1
|
|
br bb1
|
|
|
|
bb1:
|
|
%ex1 = struct_extract %outer : $Wrapper1, #Wrapper1.val1
|
|
br bb2(%ex1 : $Wrapper2, %outer : $Wrapper1)
|
|
|
|
bb2(%phi1 : @guaranteed $Wrapper2, %phi2 : @guaranteed $Wrapper1):
|
|
%ex2 = struct_extract %phi1 : $Wrapper2, #Wrapper2.val2
|
|
br bb3(%ex2 : $Klass, %phi2 : $Wrapper1)
|
|
|
|
bb3(%phi3 : @guaranteed $Klass, %phi4 : @guaranteed $Wrapper1):
|
|
%f = function_ref @use_klass : $@convention(thin) (@guaranteed Klass) -> ()
|
|
apply %f(%phi3) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %phi4 : $Wrapper1
|
|
destroy_addr %0 : $*Wrapper1
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
|
|
class C {}
|
|
|
|
sil [ossa] @getC : $@convention(thin) () -> (@owned C)
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_dce_lexical_phi :
|
|
// CHECK: destroy_value
|
|
// CHECK-LABEL: } // end sil function 'dont_dce_lexical_phi'
|
|
sil [ossa] @dont_dce_lexical_phi : $() -> () {
|
|
entry:
|
|
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
|
|
cond_br undef, left, right
|
|
left:
|
|
%c1 = apply %getC() : $@convention(thin) () -> (@owned C)
|
|
%m1 = move_value [lexical] %c1 : $C
|
|
br exit(%m1 : $C)
|
|
right:
|
|
%c2 = apply %getC() : $@convention(thin) () -> (@owned C)
|
|
br exit(%c2 : $C)
|
|
exit(%cm : @owned $C):
|
|
destroy_value %cm : $C
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
class KlassWithDeinit {
|
|
init()
|
|
deinit
|
|
}
|
|
|
|
// DCE should not delete dead allocations, leave it to DOE
|
|
// CHECK-LABEL: sil [ossa] @dont_delete_allocation :
|
|
// CHECK: alloc_ref
|
|
// CHECK-LABEL: } // end sil function 'dont_delete_allocation'
|
|
sil [ossa] @dont_delete_allocation : $@convention(thin) () -> () {
|
|
bb0:
|
|
%a = alloc_ref $KlassWithDeinit
|
|
destroy_value %a : $KlassWithDeinit
|
|
%t = tuple ()
|
|
return %t : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_dead_guaranteedphi :
|
|
// bb2:
|
|
// CHECK-LABEL: } // end sil function 'dce_dead_guaranteedphi'
|
|
sil [ossa] @dce_dead_guaranteedphi : $@convention(thin) (@owned NonTrivialStruct) -> () {
|
|
bb0(%0 : @owned $NonTrivialStruct):
|
|
%b = begin_borrow %0 : $NonTrivialStruct
|
|
%func = function_ref @$use_nontrivialstruct2 : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
%funcres = apply %func(%b) : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
br bb2(%b : $NonTrivialStruct, %b : $NonTrivialStruct)
|
|
|
|
bb2(%phi1 : @guaranteed $NonTrivialStruct, %phi2 : @guaranteed $NonTrivialStruct):
|
|
end_borrow %phi1 : $NonTrivialStruct
|
|
destroy_value %0 : $NonTrivialStruct
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_deadterm4 :
|
|
// CHECK-NOT: switch_enum
|
|
// CHECK-LABEL: } // end sil function 'dce_deadterm4'
|
|
sil [ossa] @dce_deadterm4 : $@convention(thin) (@owned FakeOptional<Builtin.NativeObject>) -> () {
|
|
bb0(%0 : @owned $FakeOptional<Builtin.NativeObject>):
|
|
%0a = alloc_stack $FakeOptional<Builtin.NativeObject>
|
|
store %0 to [init] %0a : $*FakeOptional<Builtin.NativeObject>
|
|
%1 = load [take] %0a : $*FakeOptional<Builtin.NativeObject>
|
|
%2 = copy_value %1 : $FakeOptional<Builtin.NativeObject>
|
|
apply undef(%2) : $@convention(thin) (@guaranteed FakeOptional<Builtin.NativeObject>) -> ()
|
|
switch_enum %1 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
|
|
|
|
bb1(%3 : @owned $Builtin.NativeObject):
|
|
destroy_value %3 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
switch_enum %2 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb4, case #FakeOptional.none!enumelt: bb5
|
|
|
|
bb4(%4 : @owned $Builtin.NativeObject):
|
|
destroy_value %4 : $Builtin.NativeObject
|
|
br bb6
|
|
|
|
bb5:
|
|
br bb6
|
|
|
|
bb6:
|
|
dealloc_stack %0a : $*FakeOptional<Builtin.NativeObject>
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_deadterm5 :
|
|
// CHECK: switch_enum
|
|
// CHECK-NOT: switch_enum
|
|
// CHECK-LABEL: } // end sil function 'dce_deadterm5'
|
|
sil [ossa] @dce_deadterm5 : $@convention(thin) (@owned FakeOptional<Builtin.NativeObject>) -> () {
|
|
bb0(%0 : @owned $FakeOptional<Builtin.NativeObject>):
|
|
%0a = alloc_stack $FakeOptional<Builtin.NativeObject>
|
|
store %0 to [init] %0a : $*FakeOptional<Builtin.NativeObject>
|
|
%1 = load [take] %0a : $*FakeOptional<Builtin.NativeObject>
|
|
%2 = copy_value %1 : $FakeOptional<Builtin.NativeObject>
|
|
apply undef(%2) : $@convention(thin) (@guaranteed FakeOptional<Builtin.NativeObject>) -> ()
|
|
switch_enum %1 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
|
|
|
|
bb1(%3 : @owned $Builtin.NativeObject):
|
|
destroy_value %3 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb2:
|
|
switch_enum %2 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb4, case #FakeOptional.none!enumelt: bb5
|
|
|
|
bb3:
|
|
destroy_value %2 : $FakeOptional<Builtin.NativeObject>
|
|
br bb6
|
|
|
|
bb4(%4 : @owned $Builtin.NativeObject):
|
|
destroy_value %4 : $Builtin.NativeObject
|
|
br bb6
|
|
|
|
bb5:
|
|
br bb6
|
|
|
|
bb6:
|
|
dealloc_stack %0a : $*FakeOptional<Builtin.NativeObject>
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dce_deadforwarding :
|
|
// CHECK-NOT: cond_br
|
|
// CHECK-LABEL: } // end sil function 'dce_deadforwarding'
|
|
sil [ossa] @dce_deadforwarding : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%1 = copy_value %0 : $Klass
|
|
%func = function_ref @$use_klass2 : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%funcres = apply %func(%1) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%3 = struct $NonTrivialStruct(%1 : $Klass)
|
|
destroy_value %3 : $NonTrivialStruct
|
|
br bb3
|
|
|
|
bb2:
|
|
%4 = struct $NonTrivialStruct(%1 : $Klass)
|
|
destroy_value %4 : $NonTrivialStruct
|
|
br bb3
|
|
|
|
bb3:
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// Ensure no verification error
|
|
sil [ossa] @dce_borrowedfromuser : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () {
|
|
bb0(%0 : @guaranteed $FakeOptional<Klass>):
|
|
%1 = copy_value %0
|
|
%2 = begin_borrow %1
|
|
%3 = begin_borrow %1
|
|
br bb1(%2, %3)
|
|
|
|
bb1(%5 : @reborrow $FakeOptional<Klass>, %6 : @reborrow $FakeOptional<Klass>):
|
|
%7 = borrowed %6 from (%1)
|
|
%8 = borrowed %5 from (%1)
|
|
switch_enum %7, case #FakeOptional.some!enumelt: bb2, case #FakeOptional.none!enumelt: bb3
|
|
|
|
bb2(%10 : @guaranteed $Klass):
|
|
%11 = function_ref @$use_klass2 : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%12 = apply %11(%10) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
br bb4
|
|
|
|
bb3:
|
|
br bb4
|
|
|
|
bb4:
|
|
br bb5(%8, %7)
|
|
|
|
bb5(%16 : @reborrow $FakeOptional<Klass>, %17 : @reborrow $FakeOptional<Klass>):
|
|
%18 = borrowed %17 from (%1)
|
|
%19 = borrowed %16 from (%1)
|
|
end_borrow %19
|
|
end_borrow %18
|
|
destroy_value %1
|
|
%23 = tuple ()
|
|
return %23
|
|
}
|
|
|