blob: 7dc1959655cbdbb593338af24ce8b17575b2d823 [file] [log] [blame]
// RUN: %target-swift-frontend %s -O -emit-sil | FileCheck -check-prefix=CHECK-WMO %s
// RUN: %target-swift-frontend -primary-file %s -O -emit-sil | FileCheck %s
// Test propagation of non-static let properties with compile-time constant values.
// TODO: Once this optimization can remove the propagated private/internal let properties or
// mark them as ones without a storage, new tests should be added here to check for this
// functionality.
// FIXME: This test is written in Swift instead of SIL, because there are some problems
// with SIL deserialization (rdar://22636911)
// Check that initializers do not contain a code to initialize private or
// internal (if used with WMO) properties, because their values are propagated into
// their uses and they cannot be accessed from other modules. Therefore the
// initialization code could be removed.
// Specifically, the initialization code for Prop1, Prop2 and Prop3 can be removed.
// CHECK-WMO-LABEL: sil @_TFC19let_properties_opts3Fooc{{.*}} : $@convention(method) (Int32, @owned Foo) -> @owned Foo
// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop1
// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop2
// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop3
// CHECK-WMO: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop0
// CHECK-WMO: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop1
// CHECK-WMO: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop2
// CHECK-WMO: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop3
// CHECK-WMO: return
// CHECK-WMO-LABEL: sil @_TFC19let_properties_opts3Fooc{{.*}} : $@convention(method) (Int64, @owned Foo) -> @owned Foo
// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop1
// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop2
// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop3
// CHECK-WMO: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop0
// CHECK-WMO: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop1
// CHECK-WMO: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop2
// CHECK-WMO: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop3
// CHECK-WMO: return
// Check that initializers do not contain a code to initialize private properties,
// because their values are propagated into their uses and they cannot be accessed
// from other modules. Therefore the initialization code could be removed.
// Specifically, the initialization code for Prop2 can be removed.
// CHECK-LABEL: sil @_TFC19let_properties_opts3Fooc{{.*}} : $@convention(method) (Int32, @owned Foo) -> @owned Foo
// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop0
// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop1
// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop2
// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop3
// CHECK: return
// CHECK-LABEL: sil @_TFC19let_properties_opts3Fooc{{.*}} : $@convention(method) (Int64, @owned Foo) -> @owned Foo
// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop0
// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop1
// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop2
// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop3
// CHECK: return
public class Foo {
public let Prop0: Int32 = 1
let Prop1: Int32 = 1 + 4/2 + 8
private let Prop2: Int32 = 3*7
internal let Prop3: Int32 = 4*8
public init(i:Int32) {}
public init(i:Int64) {}
}
public class Foo1 {
let Prop1: Int32
private let Prop2: Int32 = 3*7
internal let Prop3: Int32 = 4*8
public init(i:Int32) {
Prop1 = 11
}
public init(i:Int64) {
Prop1 = 1111
}
}
public struct Boo {
public let Prop0: Int32 = 1
let Prop1: Int32 = 1 + 4/2 + 8
private let Prop2: Int32 = 3*7
internal let Prop3: Int32 = 4*8
public init(i:Int32) {}
public init(i:Int64) {}
}
// Check that Foo1.Prop1 is not constant-folded, because its value is unknown, since it is initialized differently
// by Foo1 initializers.
// CHECK-LABEL: sil @_TF19let_properties_opts13testClassLet1FCS_4Foo1Vs5Int32 : $@convention(thin) (@owned Foo1) -> Int32
// bb0
// CHECK: ref_element_addr %{{[0-9]+}} : $Foo1, #Foo1.Prop1
// CHECK-NOT: ref_element_addr %{{[0-9]+}} : $Foo1, #Foo1.Prop2
// CHECK-NOT: ref_element_addr %{{[0-9]+}} : $Foo1, #Foo1.Prop3
// CHECK: return
public func testClassLet1(f: Foo1) -> Int32 {
return f.Prop1 + f.Prop2 + f.Prop3
}
// Check that Foo1.Prop1 is not constant-folded, because its value is unknown, since it is initialized differently
// by Foo1 initializers.
// CHECK-LABEL: sil @_TF19let_properties_opts13testClassLet1FRCS_4Foo1Vs5Int32 : $@convention(thin) (@inout Foo1) -> Int32
// bb0
// CHECK: ref_element_addr %{{[0-9]+}} : $Foo1, #Foo1.Prop1
// CHECK-NOT: ref_element_addr %{{[0-9]+}} : $Foo1, #Foo1.Prop2
// CHECK-NOT: ref_element_addr %{{[0-9]+}} : $Foo1, #Foo1.Prop3
// CHECK: return
public func testClassLet1(inout f: Foo1) -> Int32 {
return f.Prop1 + f.Prop2 + f.Prop3
}
// Check that return expressions in all subsequent functions can be constant folded, because the values of let properties
// are known to be constants of simple types.
// CHECK: sil @_TF19let_properties_opts12testClassLetFCS_3FooVs5Int32 : $@convention(thin) (@owned Foo) -> Int32
// CHECK: bb0
// CHECK: integer_literal $Builtin.Int32, 75
// CHECK-NEXT: struct $Int32
// CHECK-NEXT: strong_release
// CHECK-NEXT: return
public func testClassLet(f: Foo) -> Int32 {
return f.Prop1 + f.Prop1 + f.Prop2 + f.Prop3
}
// CHECK-LABEL: sil @_TF19let_properties_opts12testClassLetFRCS_3FooVs5Int32 : $@convention(thin) (@inout Foo) -> Int32
// CHECK: bb0
// CHECK: integer_literal $Builtin.Int32, 75
// CHECK-NEXT: struct $Int32
// CHECK-NEXT: return
public func testClassLet(inout f: Foo) -> Int32 {
return f.Prop1 + f.Prop1 + f.Prop2 + f.Prop3
}
// CHECK-LABEL: sil @_TF19let_properties_opts18testClassPublicLetFCS_3FooVs5Int32 : $@convention(thin) (@owned Foo) -> Int32
// CHECK: bb0
// CHECK: integer_literal $Builtin.Int32, 1
// CHECK-NEXT: struct $Int32
// CHECK-NEXT: strong_release
// CHECK-NEXT: return
public func testClassPublicLet(f: Foo) -> Int32 {
return f.Prop0
}
// CHECK-LABEL: sil @_TF19let_properties_opts13testStructLetFVS_3BooVs5Int32 : $@convention(thin) (Boo) -> Int32
// CHECK: bb0
// CHECK: integer_literal $Builtin.Int32, 75
// CHECK-NEXT: struct $Int32
// CHECK-NEXT: return
public func testStructLet(b: Boo) -> Int32 {
return b.Prop1 + b.Prop1 + b.Prop2 + b.Prop3
}
// CHECK-LABEL: sil @_TF19let_properties_opts13testStructLetFRVS_3BooVs5Int32 : $@convention(thin) (@inout Boo) -> Int32
// CHECK: bb0
// CHECK: integer_literal $Builtin.Int32, 75
// CHECK-NEXT: struct $Int32
// CHECK-NEXT: return
public func testStructLet(inout b: Boo) -> Int32 {
return b.Prop1 + b.Prop1 + b.Prop2 + b.Prop3
}
// CHECK-LABEL: sil @_TF19let_properties_opts19testStructPublicLetFVS_3BooVs5Int32 : $@convention(thin) (Boo) -> Int32
// CHECK: bb0
// CHECK: integer_literal $Builtin.Int32, 1
// CHECK-NEXT: struct $Int32
// CHECK-NEXT: return
public func testStructPublicLet(b: Boo) -> Int32 {
return b.Prop0
}