blob: e18b8b1ef53d9783fca791caf9cbf79d8001d7f2 [file] [log] [blame]
// RUN: %target-sil-opt -enable-sil-verify-all -inline -specdevirt %s | FileCheck %s
// Check that the @_semantics("optimize.sil.never") annotation prevents
// any optimizations of the annotated function:
// - No functions are inlined into the annotated function.
// - No calls are devirtualized in the body of the annotated function.
// - No generic specializations of the annotated function are generated.
// - The annotated function is not inlined into any other function.
sil_stage canonical
import Builtin
import Swift
import SwiftShims
public class C {
@inline(never) func foo() -> Int32
deinit
init()
}
public class D : C {
@inline(never) override func foo() -> Int32
deinit
override init()
}
public func transform1<T>(x: T) -> Int32
@_semantics("optimize.sil.never") public func foo1<T>(x: T, _ c: C) -> Int32
public func boo1(c: C) -> Int32
public func transform2(x: Int32) -> Int32
@_semantics("optimize.sil.never") public func foo2(x: Int32, _ c: C) -> Int32
public func boo2(c: C) -> Int32
public func transform3<T>(x: T) -> Int32
public func foo3<T>(x: T, _ c: C) -> Int32
public func boo3(c: C) -> Int32
public func transform4(x: Int32) -> Int32
public func foo4(x: Int32, _ c: C) -> Int32
public func boo4(c: C) -> Int32
sil_global [fragile] @_TZvOs7Process5_argcVs5Int32 : $Int32
sil_global private_external [fragile] @globalinit_33_1BDF70FFC18749BAB495A73B459ED2F0_token5 : $Builtin.Word
sil_global [fragile] @_TZvOs7Process11_unsafeArgvGSpGSpVs4Int8__ : $UnsafeMutablePointer<UnsafeMutablePointer<Int8>>
sil hidden [noinline] @_TFC14optimize_never1C3foofT_Vs5Int32 : $@convention(method) (@guaranteed C) -> Int32 {
bb0(%0 : $C):
%2 = integer_literal $Builtin.Int32, 1
%3 = struct $Int32 (%2 : $Builtin.Int32)
return %3 : $Int32
}
sil [transparent] [fragile] @_TFVs5Int32CfT22_builtinIntegerLiteralBi2048__S_ : $@convention(thin) (Builtin.Int2048, @thin Int32.Type) -> Int32
sil @_TFC14optimize_never1CD : $@convention(method) (@owned C) -> () {
bb0(%0 : $C):
%2 = function_ref @_TFC14optimize_never1Cd : $@convention(method) (@guaranteed C) -> @owned Builtin.NativeObject
%3 = apply %2(%0) : $@convention(method) (@guaranteed C) -> @owned Builtin.NativeObject
%4 = unchecked_ref_cast %3 : $Builtin.NativeObject to $C
dealloc_ref %4 : $C
%6 = tuple ()
return %6 : $()
}
sil @_TFC14optimize_never1Cd : $@convention(method) (@guaranteed C) -> @owned Builtin.NativeObject {
bb0(%0 : $C):
%2 = unchecked_ref_cast %0 : $C to $Builtin.NativeObject
return %2 : $Builtin.NativeObject
}
sil hidden @_TFC14optimize_never1CcfT_S0_ : $@convention(method) (@owned C) -> @owned C {
bb0(%0 : $C):
return %0 : $C
}
sil hidden [noinline] @_TFC14optimize_never1D3foofT_Vs5Int32 : $@convention(method) (@guaranteed D) -> Int32 {
bb0(%0 : $D):
%2 = integer_literal $Builtin.Int32, 11
%3 = struct $Int32 (%2 : $Builtin.Int32)
return %3 : $Int32
}
sil @_TFC14optimize_never1DD : $@convention(method) (@owned D) -> () {
bb0(%0 : $D):
%2 = function_ref @_TFC14optimize_never1Dd : $@convention(method) (@guaranteed D) -> @owned Builtin.NativeObject
%3 = apply %2(%0) : $@convention(method) (@guaranteed D) -> @owned Builtin.NativeObject
%4 = unchecked_ref_cast %3 : $Builtin.NativeObject to $D
dealloc_ref %4 : $D
%6 = tuple ()
return %6 : $()
}
sil @_TFC14optimize_never1Dd : $@convention(method) (@guaranteed D) -> @owned Builtin.NativeObject {
bb0(%0 : $D):
%2 = upcast %0 : $D to $C
%3 = function_ref @_TFC14optimize_never1Cd : $@convention(method) (@guaranteed C) -> @owned Builtin.NativeObject
%4 = apply %3(%2) : $@convention(method) (@guaranteed C) -> @owned Builtin.NativeObject
return %4 : $Builtin.NativeObject
}
sil hidden @_TFC14optimize_never1DcfT_S0_ : $@convention(method) (@owned D) -> @owned D {
bb0(%0 : $D):
%1 = alloc_stack $D
store %0 to %1#1 : $*D
%3 = upcast %0 : $D to $C
%4 = function_ref @_TFC14optimize_never1CcfT_S0_ : $@convention(method) (@owned C) -> @owned C
%5 = apply %4(%3) : $@convention(method) (@owned C) -> @owned C
%6 = unchecked_ref_cast %5 : $C to $D
store %6 to %1#1 : $*D
dealloc_stack %1#0 : $*@local_storage D
return %6 : $D
}
sil @_TF14optimize_never10transform1urFxVs5Int32 : $@convention(thin) <T> (@in T) -> Int32 {
bb0(%0 : $*T):
%2 = integer_literal $Builtin.Int32, 2
%3 = struct $Int32 (%2 : $Builtin.Int32)
destroy_addr %0 : $*T
return %3 : $Int32
}
// Check that both calls are not inlined or devirtualized.
// CHECK-LABEL: sil [_semantics "optimize.sil.never"] @_TF14optimize_never4foo1urFTxCS_1C_Vs5Int32
// CHECK-NOT: checked_cast_br
// CHECK: function_ref @_TF14optimize_never10transform1urFxVs5Int32
// CHECK: apply
// CHECK-NOT: checked_cast_br
// CHECK: class_method {{%.*}} : $C, #C.foo!1 : C -> () -> Int32 , $@convention(method) (@guaranteed C) -> Int32
// CHECK: apply
// CHECK: return
sil [_semantics "optimize.sil.never"] @_TF14optimize_never4foo1urFTxCS_1C_Vs5Int32 : $@convention(thin) <T> (@in T, @owned C) -> Int32 {
bb0(%0 : $*T, %1 : $C):
%4 = function_ref @_TF14optimize_never10transform1urFxVs5Int32 : $@convention(thin) _0_0> (@in τ_0_0) -> Int32
%5 = alloc_stack $T
copy_addr %0 to [initialization] %5#1 : $*T
%7 = apply %4<T>(%5#1) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> Int32
%8 = class_method %1 : $C, #C.foo!1 : C -> () -> Int32 , $@convention(method) (@guaranteed C) -> Int32
%9 = apply %8(%1) : $@convention(method) (@guaranteed C) -> Int32
%10 = struct_extract %7 : $Int32, #Int32._value
%11 = struct_extract %9 : $Int32, #Int32._value
%12 = integer_literal $Builtin.Int1, -1
%13 = builtin "sadd_with_overflow_Int32"(%10 : $Builtin.Int32, %11 : $Builtin.Int32, %12 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%14 = tuple_extract %13 : $(Builtin.Int32, Builtin.Int1), 0
%15 = tuple_extract %13 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %15 : $Builtin.Int1
%17 = struct $Int32 (%14 : $Builtin.Int32)
dealloc_stack %5#0 : $*@local_storage T
strong_release %1 : $C
destroy_addr %0 : $*T
return %17 : $Int32
}
sil [transparent] [fragile] @_TZFsoi1pFTVs5Int32S__S_ : $@convention(thin) (Int32, Int32) -> Int32
// CHECK-LABEL: sil @_TF14optimize_never4boo1FCS_1CVs5Int32
// CHECK-NOT: return
// This call should not be inlined, because the callee is annotated with @_semantics("optimize.sil.never")
// CHECK: function_ref @_TF14optimize_never4foo1urFTxCS_1C_Vs5Int32
// CHECK: apply
// CHECK: return
sil @_TF14optimize_never4boo1FCS_1CVs5Int32 : $@convention(thin) (@owned C) -> Int32 {
bb0(%0 : $C):
%2 = function_ref @_TF14optimize_never4foo1urFTxCS_1C_Vs5Int32 : $@convention(thin) _0_0> (@in τ_0_0, @owned C) -> Int32
%3 = integer_literal $Builtin.Int32, 1
%4 = struct $Int32 (%3 : $Builtin.Int32)
%5 = alloc_stack $Int32
store %4 to %5#1 : $*Int32
strong_retain %0 : $C
%8 = apply %2<Int32>(%5#1, %0) : $@convention(thin) <τ_0_0> (@in τ_0_0, @owned C) -> Int32
dealloc_stack %5#0 : $*@local_storage Int32
strong_release %0 : $C
return %8 : $Int32
}
sil [transparent] [fragile] @_TFSiCfT22_builtinIntegerLiteralBi2048__Si : $@convention(thin) (Builtin.Int2048, @thin Int.Type) -> Int
sil @_TF14optimize_never10transform2FVs5Int32S0_ : $@convention(thin) (Int32) -> Int32 {
bb0(%0 : $Int32):
return %0 : $Int32
}
// Check that both calls are not inlined or devirtualized.
// CHECK-LABEL: sil [_semantics "optimize.sil.never"] @_TF14optimize_never4foo2FTVs5Int32CS_1C_S0_
// CHECK-NOT: checked_cast_br
// CHECK: function_ref @_TF14optimize_never10transform2FVs5Int32S0_
// CHECK: apply
// CHECK-NOT: checked_cast_br
// CHECK: class_method {{%.*}} : $C, #C.foo!1 : C -> () -> Int32 , $@convention(method) (@guaranteed C) -> Int32
// CHECK: apply
// CHECK: return
sil [_semantics "optimize.sil.never"] @_TF14optimize_never4foo2FTVs5Int32CS_1C_S0_ : $@convention(thin) (Int32, @owned C) -> Int32 {
bb0(%0 : $Int32, %1 : $C):
%4 = function_ref @_TF14optimize_never10transform2FVs5Int32S0_ : $@convention(thin) (Int32) -> Int32
%5 = apply %4(%0) : $@convention(thin) (Int32) -> Int32
%6 = class_method %1 : $C, #C.foo!1 : C -> () -> Int32 , $@convention(method) (@guaranteed C) -> Int32
%7 = apply %6(%1) : $@convention(method) (@guaranteed C) -> Int32
%8 = struct_extract %5 : $Int32, #Int32._value
%9 = struct_extract %7 : $Int32, #Int32._value
%10 = integer_literal $Builtin.Int1, -1
%11 = builtin "sadd_with_overflow_Int32"(%8 : $Builtin.Int32, %9 : $Builtin.Int32, %10 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%12 = tuple_extract %11 : $(Builtin.Int32, Builtin.Int1), 0
%13 = tuple_extract %11 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %13 : $Builtin.Int1
%15 = struct $Int32 (%12 : $Builtin.Int32)
strong_release %1 : $C
return %15 : $Int32
}
// CHECK-LABEL: sil @_TF14optimize_never4boo2FCS_1CVs5Int32
// CHECK-NOT: return
// This call should not be inlined, because the callee is annotated with @_semantics("optimize.sil.never")
// CHECK: function_ref @_TF14optimize_never4foo2FTVs5Int32CS_1C_S0_
// CHECK: apply
// CHECK: return
sil @_TF14optimize_never4boo2FCS_1CVs5Int32 : $@convention(thin) (@owned C) -> Int32 {
bb0(%0 : $C):
%2 = function_ref @_TF14optimize_never4foo2FTVs5Int32CS_1C_S0_ : $@convention(thin) (Int32, @owned C) -> Int32
%3 = integer_literal $Builtin.Int32, 1
%4 = struct $Int32 (%3 : $Builtin.Int32)
strong_retain %0 : $C
%6 = apply %2(%4, %0) : $@convention(thin) (Int32, @owned C) -> Int32
strong_release %0 : $C
return %6 : $Int32
}
// Check that no generic specialization was produced for foo1 because it is excluded from optimizations.
// CHECK-NOT: generic specialization <Swift.Int> of {{.*}}.foo1
// But foo3 was specialized, because it is not annotated with @_semantics("optimize.sil.never")
// CHECK: generic specialization <Swift.Int32> of {{.*}}.foo3
sil @_TF14optimize_never10transform3urFxVs5Int32 : $@convention(thin) <T> (@in T) -> Int32 {
bb0(%0 : $*T):
%2 = integer_literal $Builtin.Int32, 2
%3 = struct $Int32 (%2 : $Builtin.Int32)
destroy_addr %0 : $*T
return %3 : $Int32
}
sil @_TF14optimize_never4foo3urFTxCS_1C_Vs5Int32 : $@convention(thin) <T> (@in T, @owned C) -> Int32 {
bb0(%0 : $*T, %1 : $C):
%4 = function_ref @_TF14optimize_never10transform3urFxVs5Int32 : $@convention(thin) _0_0> (@in τ_0_0) -> Int32
%5 = alloc_stack $T
copy_addr %0 to [initialization] %5#1 : $*T
%7 = apply %4<T>(%5#1) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> Int32
%8 = class_method %1 : $C, #C.foo!1 : C -> () -> Int32 , $@convention(method) (@guaranteed C) -> Int32
%9 = apply %8(%1) : $@convention(method) (@guaranteed C) -> Int32
%10 = struct_extract %7 : $Int32, #Int32._value
%11 = struct_extract %9 : $Int32, #Int32._value
%12 = integer_literal $Builtin.Int1, -1
%13 = builtin "sadd_with_overflow_Int32"(%10 : $Builtin.Int32, %11 : $Builtin.Int32, %12 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%14 = tuple_extract %13 : $(Builtin.Int32, Builtin.Int1), 0
%15 = tuple_extract %13 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %15 : $Builtin.Int1
%17 = struct $Int32 (%14 : $Builtin.Int32)
dealloc_stack %5#0 : $*@local_storage T
strong_release %1 : $C
destroy_addr %0 : $*T
return %17 : $Int32
}
// Everything in this function should get devirtualized, inlined and folded together,
// because neither this function nor any of its callees are annotated to be
// excluded from the optimization.
// CHECK-LABEL: sil @_TF14optimize_never4boo3FCS_1CVs5Int32
// CHECK: bb0
// CHECK-NOT: function_ref @_TF14optimize_never4foo3urFTxCS_1C_Vs5Int32
// Presence of checked_cast_br indicates that the speculative devirtualization
// was performed. And this is only possible, if the original call is inlined.
// CHECK: checked_cast_br [exact] {{%.*}} : $C to $C, bb2, bb3
// CHECK: return
sil @_TF14optimize_never4boo3FCS_1CVs5Int32 : $@convention(thin) (@owned C) -> Int32 {
bb0(%0 : $C):
%2 = function_ref @_TF14optimize_never4foo3urFTxCS_1C_Vs5Int32 : $@convention(thin) _0_0> (@in τ_0_0, @owned C) -> Int32
%3 = integer_literal $Builtin.Int32, 1
%4 = struct $Int32 (%3 : $Builtin.Int32)
%5 = alloc_stack $Int32
store %4 to %5#1 : $*Int32
strong_retain %0 : $C
%8 = apply %2<Int32>(%5#1, %0) : $@convention(thin) <τ_0_0> (@in τ_0_0, @owned C) -> Int32
dealloc_stack %5#0 : $*@local_storage Int32
strong_release %0 : $C
return %8 : $Int32
}
sil @_TF14optimize_never10transform4FVs5Int32S0_ : $@convention(thin) (Int32) -> Int32 {
bb0(%0 : $Int32):
return %0 : $Int32
}
sil @_TF14optimize_never4foo4FTVs5Int32CS_1C_S0_ : $@convention(thin) (Int32, @owned C) -> Int32 {
bb0(%0 : $Int32, %1 : $C):
%4 = function_ref @_TF14optimize_never10transform4FVs5Int32S0_ : $@convention(thin) (Int32) -> Int32
%5 = apply %4(%0) : $@convention(thin) (Int32) -> Int32
%6 = class_method %1 : $C, #C.foo!1 : C -> () -> Int32 , $@convention(method) (@guaranteed C) -> Int32
%7 = apply %6(%1) : $@convention(method) (@guaranteed C) -> Int32
%8 = struct_extract %5 : $Int32, #Int32._value
%9 = struct_extract %7 : $Int32, #Int32._value
%10 = integer_literal $Builtin.Int1, -1
%11 = builtin "sadd_with_overflow_Int32"(%8 : $Builtin.Int32, %9 : $Builtin.Int32, %10 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%12 = tuple_extract %11 : $(Builtin.Int32, Builtin.Int1), 0
%13 = tuple_extract %11 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %13 : $Builtin.Int1
%15 = struct $Int32 (%12 : $Builtin.Int32)
strong_release %1 : $C
return %15 : $Int32
}
// Everything in this function should get devirtualized and inlined,
// because neither this function nor any of its callees are annotated to be
// excluded from the optimization.
// CHECK-LABEL: sil @_TF14optimize_never4boo4FCS_1CVs5Int32
// CHECK: bb0
// CHECK-NOT: function_ref @_TF14optimize_never4foo4FTVs5Int32CS_1C_S0_
// Presence of checked_cast_br indicates that the speculative devirtualization
// was performed. And this is only possible, if the original call is inlined.
// CHECK: checked_cast_br [exact] {{%.*}} : $C to $C, bb2, bb3
// CHECK: return
sil @_TF14optimize_never4boo4FCS_1CVs5Int32 : $@convention(thin) (@owned C) -> Int32 {
bb0(%0 : $C):
%2 = function_ref @_TF14optimize_never4foo4FTVs5Int32CS_1C_S0_ : $@convention(thin) (Int32, @owned C) -> Int32
%3 = integer_literal $Builtin.Int32, 1
%4 = struct $Int32 (%3 : $Builtin.Int32)
strong_retain %0 : $C
%6 = apply %2(%4, %0) : $@convention(thin) (Int32, @owned C) -> Int32
strong_release %0 : $C
return %6 : $Int32
}
sil_vtable C {
#C.foo!1: _TFC14optimize_never1C3foofT_Vs5Int32
#C.deinit!deallocator: _TFC14optimize_never1CD
#C.init!initializer.1: _TFC14optimize_never1CcfT_S0_
}
sil_vtable D {
#C.foo!1: _TFC14optimize_never1D3foofT_Vs5Int32
#C.init!initializer.1: _TFC14optimize_never1DcfT_S0_
#D.deinit!deallocator: _TFC14optimize_never1DD
}