| // RUN: %target-swift-frontend -O -emit-sil -primary-file %s | %FileCheck %s |
| |
| // Check that values of static let and global let variables are propagated into their uses |
| // and enable further optimizations like constant propagation, simplifications, etc. |
| |
| // Define some global let variables. |
| |
| // Currently GlobalOpt cannot deal with the new alloc_global instruction. |
| |
| let PI = 3.1415 |
| let ONE = 1.000 |
| let I = 100 |
| let J = 200 |
| let S = "String1" |
| |
| let VOLUME1 = I * J |
| let VOLUME2 = J * 2 |
| let VOLUME3 = I + 10 |
| |
| |
| |
| struct IntWrapper1 { |
| let val: Int |
| } |
| |
| struct IntWrapper2 { |
| let val: IntWrapper1 |
| } |
| |
| struct IntWrapper3 { |
| let val: IntWrapper2 |
| } |
| |
| struct IntWrapper4 { |
| let val: IntWrapper2 |
| let val2: IntWrapper1 |
| } |
| |
| // Test with an initializer, where a SIL debug_value instruction might block |
| // analysis of the initializer and inhibit optimization of the let. |
| struct IntWrapper5 { |
| let val: Int |
| init(val: Int) { self.val = val } |
| static let Five = IntWrapper5(val: 5) |
| } |
| |
| var PROP1: Double { |
| return PI |
| } |
| |
| var PROP2: Int { |
| return I * J - I |
| } |
| |
| var VPI = 3.1415 |
| var VI = 100 |
| var VS = "String2" |
| |
| // Define some static let variables inside a struct. |
| struct B { |
| static let PI = 3.1415 |
| |
| static let ONE = 1.000 |
| |
| static let I = 100 |
| |
| static let J = 200 |
| |
| static let S1 = "String3" |
| |
| static let VOLUME1 = I * J |
| |
| static let VOLUME2 = J * 2 |
| |
| static let VOLUME3 = I + 10 |
| |
| static var PROP1: Double { |
| return PI |
| } |
| |
| static var PROP2: Int { |
| return I * J - I |
| } |
| |
| static func foo() {} |
| |
| static let IW3 = IntWrapper3(val: IntWrapper2(val: IntWrapper1(val: 10))) |
| |
| static let IW4 = IntWrapper4(val: IntWrapper2(val: IntWrapper1(val: 10)), val2: IntWrapper1(val: 100)) |
| |
| static let IT1 = ((10, 20), 30, 40) |
| |
| static let IT2 = (100, 200, 300) |
| } |
| |
| // Define some static let variables inside a class. |
| class C { |
| static let PI = 3.1415 |
| |
| static let ONE = 1.000 |
| |
| static let I = 100 |
| |
| static let J = 200 |
| |
| static let S1 = "String3" |
| |
| static let VOLUME1 = I * J |
| |
| static let VOLUME2 = J * 2 |
| |
| static let VOLUME3 = I + 10 |
| |
| static var PROP1: Double { |
| return PI |
| } |
| |
| static var PROP2: Int { |
| return I * J - I |
| } |
| |
| static func foo() {} |
| |
| static let IW3 = IntWrapper3(val: IntWrapper2(val: IntWrapper1(val: 10))) |
| |
| static let IW4 = IntWrapper4(val: IntWrapper2(val: IntWrapper1(val: 10)), val2: IntWrapper1(val: 100)) |
| |
| static let IT1 = ((10, 20), 30, 40) |
| |
| static let IT2 = (100, 200, 300) |
| } |
| |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation05test_B7_doubleSdyF |
| // CHECK: bb0: |
| // CHECK-NEXT: float_literal |
| // CHECK-NEXT: struct |
| // CHECK: return |
| @inline(never) |
| public func test_let_double() -> Double { |
| return PI + 1.0 |
| } |
| |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation05test_B4_intSiyF |
| // CHECK: bb0: |
| // CHECK-NEXT: integer_literal |
| // CHECK-NEXT: struct |
| // CHECK: return |
| @inline(never) |
| public func test_let_int() -> Int { |
| return I + 1 |
| } |
| |
| @inline(never) |
| public func test_let_string() -> String { |
| return S |
| } |
| |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation05test_B15_double_complexSdyF |
| // CHECK: bb0: |
| // CHECK-NEXT: float_literal |
| // CHECK-NEXT: struct |
| // CHECK: return |
| @inline(never) |
| public func test_let_double_complex() -> Double { |
| return PI + ONE + PROP1 |
| } |
| |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation05test_B12_int_complexSiyF |
| // CHECK: bb0: |
| // CHECK-NEXT: integer_literal |
| // CHECK-NEXT: struct |
| // CHECK: return |
| @inline(never) |
| public func test_let_int_complex() -> Int { |
| return I + J + VOLUME1 + VOLUME2 + VOLUME3 + PROP2 |
| } |
| |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation019test_static_struct_B7_doubleSdyF |
| // CHECK: bb0: |
| // CHECK-NEXT: float_literal |
| // CHECK-NEXT: struct |
| // CHECK: return |
| @inline(never) |
| public func test_static_struct_let_double() -> Double { |
| return B.PI + 1.0 |
| } |
| |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation019test_static_struct_B4_intSiyF |
| // CHECK: bb0: |
| // CHECK-NEXT: integer_literal |
| // CHECK-NEXT: struct |
| // CHECK: return |
| @inline(never) |
| public func test_static_struct_let_int() -> Int { |
| return B.I + 1 |
| } |
| |
| @inline(never) |
| public func test_static_struct_let_string() -> String { |
| return B.S1 |
| } |
| |
| |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation019test_static_struct_B15_double_complexSdyF |
| // CHECK: bb0: |
| // CHECK-NEXT: float_literal |
| // CHECK-NEXT: struct |
| // CHECK: return |
| @inline(never) |
| public func test_static_struct_let_double_complex() -> Double { |
| return B.PI + B.ONE + B.PROP1 |
| } |
| |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation019test_static_struct_B12_int_complexSiyF |
| // CHECK: bb0: |
| // CHECK-NEXT: integer_literal |
| // CHECK-NEXT: struct |
| // CHECK: return |
| @inline(never) |
| public func test_static_struct_let_int_complex() -> Int { |
| return B.I + B.J + B.VOLUME1 + B.VOLUME2 + B.VOLUME3 + B.PROP2 |
| } |
| |
| |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation018test_static_class_B7_doubleSdyF |
| // CHECK: bb0: |
| // CHECK-NEXT: float_literal |
| // CHECK-NEXT: struct |
| // CHECK: return |
| @inline(never) |
| public func test_static_class_let_double() -> Double { |
| return C.PI + 1.0 |
| } |
| |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation018test_static_class_B4_intSiyF |
| // CHECK: bb0: |
| // CHECK-NEXT: integer_literal |
| // CHECK-NEXT: struct |
| // CHECK: return |
| @inline(never) |
| public func test_static_class_let_int() -> Int { |
| return C.I + 1 |
| } |
| |
| @inline(never) |
| public func test_static_class_let_string() -> String { |
| return C.S1 |
| } |
| |
| |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation018test_static_class_B15_double_complexSdyF |
| // CHECK: bb0: |
| // CHECK-NEXT: float_literal |
| // CHECK-NEXT: struct |
| // CHECK: return |
| @inline(never) |
| public func test_static_class_let_double_complex() -> Double { |
| return C.PI + C.ONE + C.PROP1 |
| } |
| |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation018test_static_class_B12_int_complexSiyF |
| // CHECK: bb0: |
| // CHECK-NEXT: integer_literal |
| // CHECK-NEXT: struct |
| // CHECK: return |
| @inline(never) |
| public func test_static_class_let_int_complex() -> Int { |
| return C.I + C.J + C.VOLUME1 + C.VOLUME2 + C.VOLUME3 + C.PROP2 |
| } |
| |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation15test_var_doubleSdyF |
| // CHECK: bb0: |
| // CHECK-NEXT: global_addr |
| // CHECK-NEXT: struct_element_addr |
| // CHECK-NEXT: load |
| @inline(never) |
| public func test_var_double() -> Double { |
| return VPI + 1.0 |
| } |
| |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation12test_var_intSiyF |
| // CHECK: bb0: |
| // CHECK-NEXT: global_addr |
| // CHECK-NEXT: struct_element_addr |
| // CHECK-NEXT: load |
| @inline(never) |
| public func test_var_int() -> Int { |
| return VI + 1 |
| } |
| |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation018test_static_class_B12_wrapped_intSiyF |
| // CHECK: bb0: |
| // CHECK-NEXT: integer_literal |
| // CHECK-NEXT: struct |
| // CHECK: return |
| @inline(never) |
| public func test_static_class_let_wrapped_int() -> Int { |
| return C.IW3.val.val.val + 1 |
| } |
| |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation019test_static_struct_B12_wrapped_intSiyF |
| // CHECK: bb0: |
| // CHECK-NEXT: integer_literal |
| // CHECK-NEXT: struct |
| // CHECK: return |
| @inline(never) |
| public func test_static_struct_let_wrapped_int() -> Int { |
| return B.IW3.val.val.val + 1 |
| } |
| |
| // Test accessing multiple Int fields wrapped into multiple structs, where each struct may have |
| // multiple fields. |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation019test_static_struct_b1_F22_wrapped_multiple_intsSiyF |
| // CHECK: bb0: |
| // CHECK-NOT: global_addr |
| // CHECK: integer_literal |
| // CHECK-NOT: global_addr |
| // CHECK: struct |
| // CHECK: return |
| @inline(never) |
| public func test_static_struct_let_struct_wrapped_multiple_ints() -> Int { |
| return B.IW4.val.val.val + B.IW4.val2.val + IntWrapper5.Five.val + 1 |
| } |
| |
| // Test accessing multiple Int fields wrapped into multiple structs, where each struct may have |
| // multiple fields. |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation018test_static_class_B29_struct_wrapped_multiple_intsSiyF |
| // CHECK: bb0: |
| // CHECK-NOT: global_addr |
| // CHECK: integer_literal |
| // CHECK-NOT: global_addr |
| // CHECK: struct |
| // CHECK: return |
| @inline(never) |
| public func test_static_class_let_struct_wrapped_multiple_ints() -> Int { |
| return C.IW4.val.val.val + C.IW4.val2.val + IntWrapper5.Five.val + 1 |
| } |
| |
| // Test accessing multiple Int fields wrapped into multiple tuples, where each tuple may have |
| // multiple fields. |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation019test_static_struct_B19_tuple_wrapped_intsSiyF |
| // CHECK: bb0: |
| // CHECK-NOT: global_addr |
| // CHECK: integer_literal |
| // CHECK: struct |
| // CHECK: return |
| @inline(never) |
| public func test_static_struct_let_tuple_wrapped_ints() -> Int { |
| return B.IT1.0.0 + B.IT2.1 |
| } |
| |
| // Test accessing multiple Int fields wrapped into multiple tuples, where each tuple may have |
| // multiple fields. |
| // CHECK-LABEL: sil [noinline] @_T025globalopt_let_propagation018test_static_class_B19_tuple_wrapped_intsSiyF |
| // CHECK: bb0: |
| // CHECK-NOT: global_addr |
| // CHECK: integer_literal |
| // CHECK: struct |
| // CHECK: return |
| @inline(never) |
| public func test_static_class_let_tuple_wrapped_ints() -> Int { |
| return C.IT1.0.0 + C.IT2.1 |
| } |