mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Type annotations for instruction operands are omitted, e.g. ``` %3 = struct $S(%1, %2) ``` Operand types are redundant anyway and were only used for sanity checking in the SIL parser. But: operand types _are_ printed if the definition of the operand value was not printed yet. This happens: * if the block with the definition appears after the block where the operand's instruction is located * if a block or instruction is printed in isolation, e.g. in a debugger The old behavior can be restored with `-Xllvm -sil-print-types`. This option is added to many existing test files which check for operand types in their check-lines.
200 lines
5.5 KiB
Plaintext
200 lines
5.5 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types -enable-objc-interop -module-name devirt_speculative -enable-sil-verify-all %s -specdevirt | %FileCheck %s
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
@objc class MyNSObject {}
|
|
private class Base : MyNSObject {
|
|
override init()
|
|
@inline(never) func foo()
|
|
@inline(never) func exit() -> Never
|
|
}
|
|
|
|
private class Sub : Base {
|
|
override init()
|
|
@inline(never) override func foo()
|
|
@inline(never) override func exit() -> Never
|
|
}
|
|
|
|
sil private [noinline] @_TBaseFooFun : $@convention(method) (@guaranteed Base) -> () {
|
|
bb0(%0 : $Base):
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
sil private [noinline] @_TSubFooFun : $@convention(method) (@guaranteed Sub) -> () {
|
|
bb0(%0 : $Sub):
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
|
|
sil @Base_exit : $@convention(method) (@guaranteed Base) -> Never
|
|
|
|
sil @Sub_exit : $@convention(method) (@guaranteed Sub) -> Never
|
|
|
|
sil_vtable Base {
|
|
#Base.foo: @_TBaseFooFun
|
|
#Base.exit: @Base_exit
|
|
}
|
|
|
|
sil_vtable Sub {
|
|
#Base.foo: @_TSubFooFun [override]
|
|
#Base.exit: @Sub_exit [override]
|
|
}
|
|
|
|
sil @test_objc_ancestry : $@convention(thin) (@guaranteed Base) -> () {
|
|
bb0(%0: $Base):
|
|
%1 = class_method %0 : $Base, #Base.foo : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
|
|
%2 = apply %1(%0) : $@convention(method) (@guaranteed Base) -> ()
|
|
%3 = tuple()
|
|
return %3 : $()
|
|
}
|
|
|
|
// Make sure we leave the generic method call because an objc derived class can be extended at runtime.
|
|
|
|
// CHECK-LABEL: sil @test_objc_ancestry
|
|
// CHECK: bb0
|
|
// CHECK: [[METH:%.*]] = class_method %0 : $Base, #Base.foo : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
|
|
// CHECK: checked_cast_br [exact] Base in %0 : $Base to Base, bb{{.*}}, bb[[CHECK2:[0-9]+]]
|
|
// CHECK: bb[[CHECK2]]{{.*}}:
|
|
// CHECK: checked_cast_br [exact] Base in %0 : $Base to Sub, bb{{.*}}, bb[[GENCALL:[0-9]+]]
|
|
// CHECK: bb[[GENCALL]]{{.*}}:
|
|
// CHECK: apply [[METH]]
|
|
|
|
struct MyValue {}
|
|
|
|
private class Generic<T> : MyNSObject {
|
|
override init()
|
|
}
|
|
|
|
private class Base2 : Generic<MyValue> {
|
|
override init()
|
|
@inline(never) func foo()
|
|
}
|
|
|
|
private class Sub2 : Base2 {
|
|
override init()
|
|
@inline(never) override func foo()
|
|
}
|
|
|
|
sil private [noinline] @_TBase2FooFun : $@convention(method) (@guaranteed Base2) -> () {
|
|
bb0(%0 : $Base2):
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
sil private [noinline] @_TSub2FooFun : $@convention(method) (@guaranteed Sub2) -> () {
|
|
bb0(%0 : $Sub2):
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
sil_vtable Base2 {
|
|
#Base2.foo: @_TBase2FooFun
|
|
}
|
|
|
|
sil_vtable Sub2 {
|
|
#Base2.foo: @_TSub2FooFun [override]
|
|
}
|
|
|
|
sil @test_objc_ancestry2 : $@convention(thin) (@guaranteed Base2) -> () {
|
|
bb0(%0: $Base2):
|
|
%1 = class_method %0 : $Base2, #Base2.foo : (Base2) -> () -> (), $@convention(method) (@guaranteed Base2) -> ()
|
|
%2 = apply %1(%0) : $@convention(method) (@guaranteed Base2) -> ()
|
|
%3 = tuple()
|
|
return %3 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @test_objc_ancestry2
|
|
// CHECK: bb0
|
|
// CHECK: [[METH:%.*]] = class_method %0 : $Base2, #Base2.foo : (Base2) -> () -> (), $@convention(method) (@guaranteed Base2) -> ()
|
|
// CHECK: checked_cast_br [exact] Base2 in %0 : $Base2 to Base2, bb{{.*}}, bb[[CHECK2:[0-9]+]]
|
|
// CHECK: bb[[CHECK2]]{{.*}}:
|
|
// CHECK: checked_cast_br [exact] Base2 in %0 : $Base2 to Sub2, bb{{.*}}, bb[[GENCALL:[0-9]+]]
|
|
// CHECK: bb[[GENCALL]]{{.*}}:
|
|
// CHECK: apply [[METH]]
|
|
|
|
// Check that NoReturn functions are devirtualized properly.
|
|
// The new apply should be followed by an unreachable instruction
|
|
// instead of a branch instruction.
|
|
// CHECK-LABEL: sil{{.*}}test_devirt_of_noreturn_function
|
|
// CHECK: checked_cast_br
|
|
// CHECK: function_ref @Base_exit
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: unreachable
|
|
// CHECK: checked_cast_br
|
|
// CHECK: function_ref @Sub_exit
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: unreachable
|
|
sil hidden [noinline] @test_devirt_of_noreturn_function : $@convention(thin) (@owned Base) -> () {
|
|
bb0(%0 : $Base):
|
|
%2 = class_method %0 : $Base, #Base.exit : (Base) -> () -> Never, $@convention(method) (@guaranteed Base) -> Never
|
|
%3 = apply %2(%0) : $@convention(method) (@guaranteed Base) -> Never
|
|
unreachable
|
|
}
|
|
|
|
class Throw {
|
|
func mayThrow() throws
|
|
}
|
|
|
|
class S1 : Throw {
|
|
override func mayThrow()
|
|
}
|
|
|
|
class S2 : Throw {
|
|
override func mayThrow() throws
|
|
}
|
|
|
|
sil hidden [thunk] @$S4main4ThrowC8mayThrowyyKF : $@convention(method) (@guaranteed Throw) -> @error any Error {
|
|
bb0(%0 : $Throw):
|
|
%1 = tuple ()
|
|
return %1 : $()
|
|
}
|
|
|
|
sil hidden @$S4main2S1C8mayThrowyyF : $@convention(method) (@guaranteed S1) -> () {
|
|
bb0(%0 : $S1):
|
|
%1 = tuple ()
|
|
return %1 : $()
|
|
}
|
|
|
|
sil hidden [thunk] [always_inline] @$S4main2S2C8mayThrowyyKF : $@convention(method) (@guaranteed S2) -> @error any Error {
|
|
bb0(%0 : $S2):
|
|
%1 = tuple ()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil{{.*}} @test_devirt_of_throw_without_error
|
|
// CHECK-NOT: checked_cast_br [exact] Throw in %0 : $Throw to S1
|
|
// CHECK: return
|
|
|
|
sil hidden [noinline] @test_devirt_of_throw_without_error : $@convention(thin) (@owned Throw) -> () {
|
|
bb0(%0 : $Throw):
|
|
%80 = class_method %0 : $Throw, #Throw.mayThrow : (Throw) -> () throws -> (), $@convention(method) (@guaranteed Throw) -> @error any Error // user: %81
|
|
try_apply %80(%0) : $@convention(method) (@guaranteed Throw) -> @error any Error, normal bb7, error bb6
|
|
|
|
bb6(%82 : $Error):
|
|
br bb1
|
|
|
|
bb7(%84 : $()):
|
|
br bb1
|
|
|
|
bb1:
|
|
%3 = tuple ()
|
|
return %3 : $()
|
|
}
|
|
|
|
sil_vtable Throw {
|
|
#Throw.mayThrow: (Throw) -> () throws -> () : @$S4main4ThrowC8mayThrowyyKF
|
|
}
|
|
|
|
sil_vtable S1 {
|
|
#Throw.mayThrow: (Throw) -> () throws -> () : @$S4main2S1C8mayThrowyyF [override]
|
|
}
|
|
|
|
sil_vtable S2 {
|
|
#Throw.mayThrow: (Throw) -> () throws -> () : @$S4main2S2C8mayThrowyyKF [override]
|
|
}
|