blob: 2880d06cd875845bd1cfe02ff7ca586e8cf31bf5 [file] [log] [blame]
// RUN: %target-swift-frontend -primary-file %s -O -sil-verify-all -module-name=test -emit-sil | %FileCheck %s
// Also do an end-to-end test to check if the generated code is correct.
// RUN: %empty-directory(%t)
// RUN: %target-build-swift -O -Xllvm -module-name=test %s -o %t/a.out
// RUN: %target-codesign %t/a.out
// RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT
// REQUIRES: executable_test
var g = 0
final class Myclass {
lazy var lvar: Int = {
print("lvar init")
return g
}()
}
struct Mystruct {
lazy var lvar: Int = {
print("lvar init")
return g
}()
}
// CHECK-LABEL: sil {{.*}} @$s4test0A7_simpleySiAA7MyclassCF
// CHECK: [[GETTER:%[0-9]+]] = function_ref @$s4test7MyclassC4lvarSivg
// CHECK: [[V1:%[0-9]+]] = apply [[GETTER]](%0)
// CHECK: [[V2OPT:%[0-9]+]] = load
// CHECK: [[V2:%[0-9]+]] = unchecked_enum_data [[V2OPT]]
// CHECK: [[V1VAL:%[0-9]+]] = struct_extract [[V1]]
// CHECK: [[V2VAL:%[0-9]+]] = struct_extract [[V2]]
// CHECK: builtin "sadd{{.*}}"([[V1VAL]] {{.*}}, [[V2VAL]]
// CHECK: } // end sil function '$s4test0A7_simpleySiAA7MyclassCF'
@inline(never)
func test_simple(_ c: Myclass) -> Int {
g = 27
let v1 = c.lvar
let v2 = c.lvar
return v1 &+ v2
}
// CHECK-LABEL: sil {{.*}} @$s4test0A4_cfgySiAA7MyclassC_SbtF
// CHECK: [[GETTER:%[0-9]+]] = function_ref @$s4test7MyclassC4lvarSivg
// CHECK: [[V1:%[0-9]+]] = apply [[GETTER]](%0)
// CHECK: bb1:
// CHECK: [[V2OPT:%[0-9]+]] = load
// CHECK: [[V2:%[0-9]+]] = unchecked_enum_data [[V2OPT]]
// CHECK: [[V2VAL:%[0-9]+]] = struct_extract [[V2]]
// CHECK: br bb3([[V2VAL]]
// CHECK: bb2:
// CHECK: bb3([[V2PHI:%[0-9]+]] {{.*}}):
// CHECK: [[V1VAL:%[0-9]+]] = struct_extract [[V1]]
// CHECK: builtin "sadd{{.*}}"([[V1VAL]] {{.*}}, [[V2PHI]]
// CHECK: } // end sil function '$s4test0A4_cfgySiAA7MyclassC_SbtF'
@inline(never)
func test_cfg(_ c: Myclass, _ b: Bool) -> Int {
g = 10
let v1 = c.lvar
var v2: Int
if b {
v2 = c.lvar
} else {
v2 = 0
}
return v1 &+ v2
}
// CHECK-LABEL: sil {{.*}} @$s4test0A12_no_hoistingySiAA7MyclassC_SbtF
// CHECK: bb1:
// CHECK: [[GETTER1:%[0-9]+]] = function_ref @$s4test7MyclassC4lvarSivg
// CHECK: = apply [[GETTER1]](%0)
// CHECK: bb2:
// CHECK: [[GETTER2:%[0-9]+]] = function_ref @$s4test7MyclassC4lvarSivg
// CHECK: = apply [[GETTER2]](%0)
// CHECK: bb3({{.*}}):
// CHECK: } // end sil function '$s4test0A12_no_hoistingySiAA7MyclassC_SbtF'
@inline(never)
func test_no_hoisting(_ c: Myclass, _ b: Bool) -> Int {
var v: Int
if b {
g = 20
v = c.lvar + 2
} else {
g = 30
v = c.lvar + 3
}
return v
}
// This test is disabled, because for structs, it does not work yet.
// CSE is too conservative to handle indirect getter arguments currently.
// CHECK-LABEL: sil {{.*}} @$s4test0A7_structySiAA8MystructVF
// CHECK-DISABLED: [[GETTER:%[0-9]+]] = function_ref @$s4test8MystructV4lvarSivg
// CHECK-DISABLED: [[V1:%[0-9]+]] = apply [[GETTER]]({{.*}})
// CHECK-DISABLED: [[V2OPT:%[0-9]+]] = load
// CHECK-DISABLED: [[V2:%[0-9]+]] = unchecked_enum_data [[V2OPT]]
// CHECK-DISABLED: [[V1VAL:%[0-9]+]] = struct_extract [[V1]]
// CHECK-DISABLED: [[V2VAL:%[0-9]+]] = struct_extract [[V2]]
// CHECK-DISABLED: builtin "sadd{{.*}}"([[V1VAL]] {{.*}}, [[V2VAL]]
// CHECK-DISABLED: } // end sil function '$s4test0A7_structySiAA8MystructVF'
@inline(never)
func test_struct(_ s: Mystruct) -> Int {
var sm = s
g = 42
let v1 = sm.lvar
let v2 = sm.lvar
return v1 &+ v2
}
// CHECK-LABEL: sil {{.*}} @$s4test0A19_overwritten_structySiAA8MystructVF
// CHECK: [[GETTER:%[0-9]+]] = function_ref @$s4test8MystructV4lvarSivg
// CHECK: [[V1:%[0-9]+]] = apply [[GETTER]]({{.*}})
// CHECK: [[V2:%[0-9]+]] = apply [[GETTER]]({{.*}})
// CHECK: [[V1VAL:%[0-9]+]] = struct_extract [[V1]]
// CHECK: [[V2VAL:%[0-9]+]] = struct_extract [[V2]]
// CHECK: builtin "sadd{{.*}}"([[V1VAL]] {{.*}}, [[V2VAL]]
// CHECK: } // end sil function '$s4test0A19_overwritten_structySiAA8MystructVF'
@inline(never)
func test_overwritten_struct(_ s: Mystruct) -> Int {
var sm = s
g = 42
let v1 = sm.lvar
sm = s
g = 43
let v2 = sm.lvar
return v1 &+ v2
}
func calltests() {
// CHECK-OUTPUT-LABEL: test_simple
print("test_simple")
// CHECK-OUTPUT-NEXT: lvar init
// CHECK-OUTPUT-NEXT: 54
print(test_simple(Myclass()))
// CHECK-OUTPUT-LABEL: test_cfg
print("test_cfg")
// CHECK-OUTPUT-NEXT: lvar init
// CHECK-OUTPUT-NEXT: 20
print(test_cfg(Myclass(), true))
// CHECK-OUTPUT-LABEL: test_no_hoisting
print("test_no_hoisting")
// CHECK-OUTPUT-NEXT: lvar init
// CHECK-OUTPUT-NEXT: 22
print(test_no_hoisting(Myclass(), true))
// CHECK-OUTPUT-NEXT: lvar init
// CHECK-OUTPUT-NEXT: 33
print(test_no_hoisting(Myclass(), false))
// CHECK-OUTPUT-LABEL: test_struct
print("test_struct")
// CHECK-OUTPUT-NEXT: lvar init
// CHECK-OUTPUT-NEXT: 84
print(test_struct(Mystruct()))
// CHECK-OUTPUT-LABEL: test_overwritten_struct
print("test_overwritten_struct")
// CHECK-OUTPUT-NEXT: lvar init
// CHECK-OUTPUT-NEXT: lvar init
// CHECK-OUTPUT-NEXT: 85
print(test_overwritten_struct(Mystruct()))
}
calltests()