File: let_properties_opts_runtime.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (110 lines) | stat: -rw-r--r-- 3,694 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// RUN: %empty-directory(%t)
// RUN: %target-build-swift -O  %s -o %t/a.out
// RUN: %target-codesign %t/a.out
// RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT
// RUN: %target-build-swift -O -wmo %s -o %t/a.out2
// RUN: %target-codesign %t/a.out2
// RUN: %target-run %t/a.out2 | %FileCheck %s -check-prefix=CHECK-OUTPUT
// REQUIRES: executable_test

// Check that in optimized builds the compiler generates correct code for
// initializations of let properties, which is assigned multiple times inside
// initializers.

public class Foo1 {
  internal let Prop1: Int32
  internal let Prop2: Int32
  // Initialize Prop3 as part of declaration.
  internal let Prop3: Int32 = 20
  internal let Prop4: Int32

  @inline(never)
  init(_ count: Int32) {
    // Initialize Prop4 unconditionally and only once.
    Prop4 = 300
    // There are two different assignments to Prop1 and Prop2
    // on different branches of the if-statement.
    if count < 2 {
      // Initialize Prop1 and Prop2 conditionally.
      // Use other properties in the definition of Prop1 and Prop2.
      Prop1 = 5
      Prop2 = 10 - Prop1 + Prop4 - Prop3
    } else {
       // Initialize Prop1 and Prop2 conditionally.
      // Use other properties in the definition of Prop1 and Prop2.
      Prop1 = 100
      Prop2 = 200 + Prop1 - Prop4 - Prop3
    }
  }
}

public func testClassLet(_ f: Foo1) -> Int32 {
  return f.Prop1 + f.Prop2 + f.Prop3 + f.Prop4
}

// Prop1 = 5, Prop2 = (10-5+300-20) = 285, Prop3 = 20, Prop4 = 300
// Hence Prop1 + Prop2 + Prop3 + Prop4 = 610
// CHECK-OUTPUT: 610
print(testClassLet(Foo1(1)))

// Prop1 = 100, Prop2 = (200+100-300-20) = -20, Prop3 = 20, Prop4 = 300
// Hence Prop1 + Prop2 + Prop3 + Prop4 = 610
// CHECK-OUTPUT: 400
print(testClassLet(Foo1(10)))

public class C {}

struct Boo3 {
  //public 
  let Prop0: Int32
  let Prop1: Int32
  fileprivate let Prop2: Int32
  internal let Prop3: Int32

  @inline(__always)
  init(_ f1: C, _ f2: C) {
    self.Prop0 = 0
    self.Prop1 = 1
    self.Prop2 = 2
    self.Prop3 = 3
  }

  init(_ v: C) {
    self.Prop0 = 10
    self.Prop1 = 11
    self.Prop2 = 12
    self.Prop3 = 13
  }
}

// Check that the sum of properties is not folded into a constant.
@inline(never)
func testStructWithMultipleInits( _ boos1: Boo3, _ boos2: Boo3) -> Int32 {
  // count1 = 0 + 1 + 2 + 3 = 6
  // count2 = 10 + 11 + 12 + 13 = 46
  // count1 + count2 = 6 + 46 = 52
  let count1 =  boos1.Prop0 + boos1.Prop1 + boos1.Prop2 + boos1.Prop3
  let count2 =  boos2.Prop0 + boos2.Prop1 + boos2.Prop2 + boos2.Prop3
  return count1 + count2
}

public func testStructWithMultipleInitsAndInlinedInitializer() {
  let things = [C()]
  // This line results in inlining of the initializer Boo3(C, C) and later
  // removal of this initializer by the dead function elimination pass.
  // As a result, only one initializer, Boo3(C) is seen by the Let Properties Propagation
  // pass. This pass may think that there is only one initializer and take the
  // values of let properties assigned there as constants and try to propagate
  // those values into uses. But this is wrong! The pass should be clever enough
  // to detect all stores to the let properties, including those outside of
  // initializers, e.g. inside inlined initializers. And if it detects all such
  // stores it should understand that values of let properties in Boo3 are not
  // statically known constant initializers with the same value and thus
  // cannot be propagated.
  let boos1 = things.map { Boo3($0, C()) }
  let boos2 = things.map(Boo3.init)
  // CHECK-OUTPUT: 52
  print(testStructWithMultipleInits(boos1[0], boos2[0]))
}

testStructWithMultipleInitsAndInlinedInitializer()