// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s | %FileCheck %s func takeClosure(_ a : () -> Int) {} // Let decls don't get boxes for trivial types. // // CHECK-LABEL: sil hidden @{{.*}}test1 func test1(_ a : Int) -> Int { // CHECK-NOT: alloc_box // FIXME(integers): the following check should be updated for the new way + // gets invoked. // XCHECK-NOT: alloc_stack let (b,c) = (a, 32) return b+c // CHECK: return } // rdar://15716277 // CHECK: @{{.*}}_destructuring func let_destructuring() -> Int { let (a, b) = ((1,2), 5) return a.1+a.0+b } // Let decls being closed over. // // CHECK-LABEL: sil hidden @{{.*}}test2 func test2() { // No allocations. // CHECK-NOT: alloc_box // CHECK-NOT: alloc_stack let x = 42 takeClosure({x}) // CHECK: return } // The closure just returns its value, which it captured directly. // CHECK: sil private @_T09let_decls5test2yyFSiycfU_ : $@convention(thin) (Int) -> Int // CHECK: bb0(%0 : $Int): // CHECK: return %0 : $Int // Verify that we can close over let decls of tuple type. struct RegularStruct { var a: Int } func testTupleLetCapture() { let t = (RegularStruct(a: 41), 42) takeClosure( { t.0.a }) } func getAString() -> String { return "" } func useAString(_ a : String) {} // rdar://15689514 - Verify that the cleanup for the let decl runs at the end of // the 'let' lifetime, not at the end of the initializing expression. // // CHECK-LABEL: sil hidden @{{.*}}test3 func test3() { // CHECK: [[GETFN:%[0-9]+]] = function_ref{{.*}}getAString // CHECK-NEXT: [[STR:%[0-9]+]] = apply [[GETFN]]() let o = getAString() // CHECK-NOT: destroy_value // CHECK: [[USEFN:%[0-9]+]] = function_ref{{.*}}useAString // CHECK-NEXT: [[BORROWED_STR:%.*]] = begin_borrow [[STR]] // CHECK-NEXT: [[STR_COPY:%.*]] = copy_value [[BORROWED_STR]] // CHECK-NEXT: [[USE:%[0-9]+]] = apply [[USEFN]]([[STR_COPY]]) // CHECK-NEXT: end_borrow [[BORROWED_STR]] from [[STR]] useAString(o) // CHECK: destroy_value [[STR]] } // CHECK: } // end sil function '{{.*}}test3{{.*}}' struct AddressOnlyStruct { var elt : T var str : String } func produceAddressOnlyStruct(_ x : T) -> AddressOnlyStruct {} // CHECK-LABEL: sil hidden @{{.*}}testAddressOnlyStructString // CHECK: bb0([[FUNC_ARG:%.*]] : $*T): func testAddressOnlyStructString(_ a : T) -> String { return produceAddressOnlyStruct(a).str // CHECK: [[PRODFN:%[0-9]+]] = function_ref @{{.*}}produceAddressOnlyStruct // CHECK: [[TMPSTRUCT:%[0-9]+]] = alloc_stack $AddressOnlyStruct // CHECK: [[ARG:%.*]] = alloc_stack $T // CHECK: copy_addr [[FUNC_ARG]] to [initialization] [[ARG]] // CHECK: apply [[PRODFN]]([[TMPSTRUCT]], [[ARG]]) // CHECK-NEXT: dealloc_stack [[ARG]] // CHECK-NEXT: [[STRADDR:%[0-9]+]] = struct_element_addr [[TMPSTRUCT]] : $*AddressOnlyStruct, #AddressOnlyStruct.str // CHECK-NEXT: [[STRVAL:%[0-9]+]] = load [copy] [[STRADDR]] // CHECK-NEXT: destroy_addr [[TMPSTRUCT]] // CHECK-NEXT: dealloc_stack [[TMPSTRUCT]] // CHECK: return [[STRVAL]] } // CHECK-LABEL: sil hidden @{{.*}}testAddressOnlyStructElt func testAddressOnlyStructElt(_ a : T) -> T { return produceAddressOnlyStruct(a).elt // CHECK: [[PRODFN:%[0-9]+]] = function_ref @{{.*}}produceAddressOnlyStruct // CHECK: [[TMPSTRUCT:%[0-9]+]] = alloc_stack $AddressOnlyStruct // CHECK: [[ARG:%.*]] = alloc_stack $T // CHECK: apply [[PRODFN]]([[TMPSTRUCT]], [[ARG]]) // CHECK-NEXT: dealloc_stack [[ARG]] // CHECK-NEXT: [[ELTADDR:%[0-9]+]] = struct_element_addr [[TMPSTRUCT]] : $*AddressOnlyStruct, #AddressOnlyStruct.elt // CHECK-NEXT: copy_addr [[ELTADDR]] to [initialization] %0 : $*T // CHECK-NEXT: destroy_addr [[TMPSTRUCT]] } // rdar://15717123 - let decls of address-only type. // CHECK-LABEL: sil hidden @{{.*}}testAddressOnlyLet func testAddressOnlyLet(_ a : T) { let x = produceAddressOnlyStruct(a) } func produceSubscriptableRValue() -> [String] {} // CHECK-LABEL: sil hidden @{{.*}}subscriptRValue func subscriptRValue() { var a = produceSubscriptableRValue()[0] } struct GetOnlySubscriptStruct { // get-only subscript subscript (i : Int) -> Int { get {} } } // CHECK-LABEL: sil hidden @{{.*}}testGetOnlySubscript func testGetOnlySubscript(_ x : GetOnlySubscriptStruct, idx : Int) -> Int { return x[idx] // CHECK: [[SUBFN:%[0-9]+]] = function_ref @{{.*}}9subscript // CHECK-NEXT: [[CALL:%[0-9]+]] = apply [[SUBFN]]( // CHECK: return [[CALL]] } // Address-only let's get captured by box. extension Optional { func getLV() -> Int { } } struct CloseOverAddressOnlyConstant { func isError() { let AOV: T? takeClosure({ AOV.getLV() }) } } // CHECK-LABEL: sil hidden @{{.*}}callThroughLet func callThroughLet(_ predicate: @escaping (Int, Int) -> Bool) { let p = predicate if p(1, 2) { } } // Verify that we can emit address-only rvalues directly into the result slot in // chained calls. struct GenericTestStruct { func pass_address_only_rvalue_result(_ i: Int) -> T { return self[i] } subscript (i : Int) -> T { get {} set {} } } // CHECK-LABEL: sil hidden @{{.*}}pass_address_only_rvalue_result // CHECK: bb0(%0 : $*T, // CHECK: [[FN:%[0-9]+]] = function_ref @{{.*}}GenericTestStructV9subscript{{.*}}fg // CHECK: apply [[FN]](%0, struct NonMutableSubscriptable { subscript(x : Int) -> Int { get {} nonmutating set {} } } func produceNMSubscriptableRValue() -> NonMutableSubscriptable {} // CHECK-LABEL: sil hidden @{{.*}}test_nm_subscript_get // CHECK: bb0(%0 : $Int): // CHECK: [[FR1:%[0-9]+]] = function_ref @{{.*}}produceNMSubscriptableRValue // CHECK-NEXT: [[RES:%[0-9]+]] = apply [[FR1]]() // CHECK: [[GETFN:%[0-9]+]] = function_ref @_T09let_decls23NonMutableSubscriptableV9subscript{{[_0-9a-zA-Z]*}}fg // CHECK-NEXT: [[RES2:%[0-9]+]] = apply [[GETFN]](%0, [[RES]]) // CHECK-NEXT: return [[RES2]] func test_nm_subscript_get(_ a : Int) -> Int { return produceNMSubscriptableRValue()[a] } // CHECK-LABEL: sil hidden @{{.*}}test_nm_subscript_set // CHECK: bb0(%0 : $Int): // CHECK: [[FR1:%[0-9]+]] = function_ref @{{.*}}produceNMSubscriptableRValue // CHECK-NEXT: [[RES:%[0-9]+]] = apply [[FR1]]() // CHECK: [[SETFN:%[0-9]+]] = function_ref @_T09let_decls23NonMutableSubscriptableV9subscript{{[_0-9a-zA-Z]*}}fs // CHECK-NEXT: [[RES2:%[0-9]+]] = apply [[SETFN]](%0, %0, [[RES]]) func test_nm_subscript_set(_ a : Int) { produceNMSubscriptableRValue()[a] = a } struct WeirdPropertyTest { // This property has a mutating getter and !mutating setter. var p : Int { mutating get {} nonmutating set {} } } // CHECK-LABEL: sil hidden @{{.*}}test_weird_property func test_weird_property(_ v : WeirdPropertyTest, i : Int) -> Int { var v = v // CHECK: [[VBOX:%[0-9]+]] = alloc_box ${ var WeirdPropertyTest } // CHECK: [[PB:%.*]] = project_box [[VBOX]] // CHECK: store %0 to [trivial] [[PB]] // The setter isn't mutating, so we need to load the box. // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[PB]] // CHECK: [[VVAL:%[0-9]+]] = load [trivial] [[READ]] // CHECK: [[SETFN:%[0-9]+]] = function_ref @_T09let_decls17WeirdPropertyTestV1pSifs // CHECK: apply [[SETFN]](%1, [[VVAL]]) v.p = i // The getter is mutating, so it takes the box address. // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB]] // CHECK: [[GETFN:%[0-9]+]] = function_ref @_T09let_decls17WeirdPropertyTestV1pSifg // CHECK-NEXT: [[RES:%[0-9]+]] = apply [[GETFN]]([[WRITE]]) // CHECK: return [[RES]] return v.p } // CHECK-LABEL: sil hidden @{{.*}}generic_identity // CHECK: bb0(%0 : $*T, %1 : $*T): // CHECK-NEXT: debug_value_addr %1 : $*T // CHECK-NEXT: copy_addr %1 to [initialization] %0 : $*T // CHECK-NEXT: destroy_addr %1 // CHECK: } // end sil function '{{.*}}generic_identity{{.*}}' func generic_identity(_ a : T) -> T { // Should be a single copy_addr, with no temporary. return a } struct StaticLetMember { static let x = 5 } // CHECK-LABEL: sil hidden @{{.*}}testStaticLetMember func testStaticLetMember() -> Int { // CHECK: function_ref @{{.*}}StaticLetMemberV1xSi // CHECK: load {{.*}} : $*Int // CHECK-NEXT: return return StaticLetMember.x } protocol SimpleProtocol { func doSomethingGreat() } // Verify that no temporaries+copies are produced when calling non-@mutable // methods on protocol and archetypes calls. // CHECK-LABEL: sil hidden @{{.*}}testLetProtocolBases // CHECK: bb0(%0 : $*SimpleProtocol): func testLetProtocolBases(_ p : SimpleProtocol) { // CHECK-NEXT: debug_value_addr // CHECK-NEXT: open_existential_addr // CHECK-NEXT: witness_method // CHECK-NEXT: apply p.doSomethingGreat() // CHECK-NEXT: open_existential_addr // CHECK-NEXT: witness_method // CHECK-NEXT: apply p.doSomethingGreat() // CHECK-NEXT: destroy_addr %0 // CHECK-NEXT: tuple // CHECK-NEXT: return } // CHECK-LABEL: sil hidden @{{.*}}testLetArchetypeBases // CHECK: bb0(%0 : $*T): func testLetArchetypeBases(_ p : T) { // CHECK-NEXT: debug_value_addr // CHECK-NEXT: witness_method $T // CHECK-NEXT: apply p.doSomethingGreat() // CHECK-NEXT: witness_method $T // CHECK-NEXT: apply p.doSomethingGreat() // CHECK-NEXT: destroy_addr %0 // CHECK-NEXT: tuple // CHECK-NEXT: return } // CHECK-LABEL: sil hidden @{{.*}}testDebugValue // CHECK: bb0(%0 : $Int, %1 : $*SimpleProtocol): // CHECK-NEXT: debug_value %0 : $Int, let, name "a" // CHECK-NEXT: debug_value_addr %1 : $*SimpleProtocol, let, name "b" func testDebugValue(_ a : Int, b : SimpleProtocol) -> Int { // CHECK-NEXT: debug_value %0 : $Int, let, name "x" let x = a // CHECK: apply b.doSomethingGreat() // CHECK: destroy_addr // CHECK: return %0 return x } // CHECK-LABEL: sil hidden @{{.*}}testAddressOnlyTupleArgument func testAddressOnlyTupleArgument(_ bounds: (start: SimpleProtocol, pastEnd: Int)) { // CHECK: bb0(%0 : $*SimpleProtocol, %1 : $Int): // CHECK-NEXT: %2 = alloc_stack $(start: SimpleProtocol, pastEnd: Int), let, name "bounds" // CHECK-NEXT: %3 = tuple_element_addr %2 : $*(start: SimpleProtocol, pastEnd: Int), 0 // CHECK-NEXT: copy_addr [take] %0 to [initialization] %3 : $*SimpleProtocol // CHECK-NEXT: %5 = tuple_element_addr %2 : $*(start: SimpleProtocol, pastEnd: Int), 1 // CHECK-NEXT: store %1 to [trivial] %5 : $*Int // CHECK-NEXT: debug_value_addr %2 // CHECK-NEXT: destroy_addr %2 : $*(start: SimpleProtocol, pastEnd: Int) // CHECK-NEXT: dealloc_stack %2 : $*(start: SimpleProtocol, pastEnd: Int) } func address_only_let_closure(_ x:T) -> T { return { { x }() }() } struct GenericFunctionStruct { var f: (T) -> U } // CHECK-LABEL: sil hidden @{{.*}}member_ref_abstraction_change // CHECK: function_ref reabstraction thunk helper // CHECK: return func member_ref_abstraction_change(_ x: GenericFunctionStruct) -> (Int) -> Int { return x.f } // CHECK-LABEL: sil hidden @{{.*}}call_auto_closure // CHECK: bb0([[CLOSURE:%.*]] : $@callee_owned () -> Bool): // CHECK: [[BORROWED_CLOSURE:%.*]] = begin_borrow [[CLOSURE]] // CHECK: [[CLOSURE_COPY:%.*]] = copy_value [[BORROWED_CLOSURE]] // CHECK: apply [[CLOSURE_COPY]]() : $@callee_owned () -> Bool // CHECK: end_borrow [[BORROWED_CLOSURE]] from [[CLOSURE]] // CHECK: destroy_value [[CLOSURE]] // CHECK: } // end sil function '{{.*}}call_auto_closure{{.*}}' func call_auto_closure(x: @autoclosure () -> Bool) -> Bool { return x() // Calls of autoclosures should be marked transparent. } class SomeClass {} struct AnotherStruct { var i : Int var c : SomeClass } struct StructMemberTest { var c : SomeClass var i = 42 var s : AnotherStruct var t : (Int, AnotherStruct) // rdar://15867140 - Accessing the int member here should not copy_value the // whole struct. func testIntMemberLoad() -> Int { return i } // CHECK-LABEL: sil hidden @_T09let_decls16StructMemberTestV07testIntD4LoadSiyF : $@convention(method) (@guaranteed StructMemberTest) // CHECK: bb0([[ARG:%.*]] : $StructMemberTest): // CHECK: debug_value [[ARG]] : $StructMemberTest, let, name "self" // CHECK: [[TRIVIAL_VALUE:%.*]] = struct_extract [[ARG]] : $StructMemberTest, #StructMemberTest.i // CHECK-NOT: destroy_value [[ARG]] : $StructMemberTest // CHECK-NOT: destroy_value [[BORROWED_ARG]] : $StructMemberTest // CHECK: return [[TRIVIAL_VALUE]] : $Int // Accessing the int member in s should not copy_value the whole struct. func testRecursiveIntMemberLoad() -> Int { return s.i } // CHECK-LABEL: sil hidden @_T09let_decls16StructMemberTestV016testRecursiveIntD4LoadSiyF : $@convention(method) (@guaranteed StructMemberTest) // CHECK: bb0([[ARG:%.*]] : $StructMemberTest): // CHECK: debug_value %0 : $StructMemberTest, let, name "self" // CHECK: %2 = struct_extract %0 : $StructMemberTest, #StructMemberTest.s // CHECK: %3 = struct_extract %2 : $AnotherStruct, #AnotherStruct.i // CHECK-NOT: destroy_value %0 : $StructMemberTest // CHECK: return %3 : $Int func testTupleMemberLoad() -> Int { return t.1.i } // CHECK-LABEL: sil hidden @_T09let_decls16StructMemberTestV09testTupleD4LoadSiyF : $@convention(method) (@guaranteed StructMemberTest) // CHECK: bb0(%0 : $StructMemberTest): // CHECK-NEXT: debug_value %0 : $StructMemberTest, let, name "self" // CHECK-NEXT: [[T0:%.*]] = struct_extract %0 : $StructMemberTest, #StructMemberTest.t // CHECK-NEXT: [[T1:%.*]] = tuple_extract [[T0]] : $(Int, AnotherStruct), 0 // CHECK-NEXT: [[T2:%.*]] = tuple_extract [[T0]] : $(Int, AnotherStruct), 1 // CHECK-NEXT: [[T3:%.*]] = struct_extract [[T2]] : $AnotherStruct, #AnotherStruct.i // CHECK-NEXT: return [[T3]] : $Int } struct GenericStruct { var a : T var b : Int func getA() -> T { return a } // CHECK-LABEL: sil hidden @{{.*}}GenericStructV4getA{{.*}} : $@convention(method) (@in_guaranteed GenericStruct) -> @out T // CHECK: bb0(%0 : $*T, %1 : $*GenericStruct): // CHECK-NEXT: debug_value_addr %1 : $*GenericStruct, let, name "self" // CHECK-NEXT: %3 = struct_element_addr %1 : $*GenericStruct, #GenericStruct.a // CHECK-NEXT: copy_addr %3 to [initialization] %0 : $*T // CHECK-NEXT: %5 = tuple () // CHECK-NEXT: return %5 : $() func getB() -> Int { return b } // CHECK-LABEL: sil hidden @{{.*}}GenericStructV4getB{{.*}} : $@convention(method) (@in_guaranteed GenericStruct) -> Int // CHECK: bb0([[SELF_ADDR:%.*]] : $*GenericStruct): // CHECK-NEXT: debug_value_addr [[SELF_ADDR]] : $*GenericStruct, let, name "self" // CHECK-NEXT: [[PROJ_ADDR:%.*]] = struct_element_addr [[SELF_ADDR]] : $*GenericStruct, #GenericStruct.b // CHECK-NEXT: [[PROJ_VAL:%.*]] = load [trivial] [[PROJ_ADDR]] : $*Int // CHECK-NOT: destroy_addr [[SELF]] : $*GenericStruct // CHECK-NEXT: return [[PROJ_VAL]] : $Int } // rdar://15877337 struct LetPropertyStruct { let lp : Int } // CHECK-LABEL: sil hidden @{{.*}}testLetPropertyAccessOnLValueBase // CHECK: bb0(%0 : $LetPropertyStruct): // CHECK: [[ABOX:%[0-9]+]] = alloc_box ${ var LetPropertyStruct } // CHECK: [[A:%[0-9]+]] = project_box [[ABOX]] // CHECK: store %0 to [trivial] [[A]] : $*LetPropertyStruct // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[A]] // CHECK: [[STRUCT:%[0-9]+]] = load [trivial] [[READ]] : $*LetPropertyStruct // CHECK: [[PROP:%[0-9]+]] = struct_extract [[STRUCT]] : $LetPropertyStruct, #LetPropertyStruct.lp // CHECK: destroy_value [[ABOX]] : ${ var LetPropertyStruct } // CHECK: return [[PROP]] : $Int func testLetPropertyAccessOnLValueBase(_ a : LetPropertyStruct) -> Int { var a = a return a.lp } var addressOnlyGetOnlyGlobalProperty : SimpleProtocol { get {} } // CHECK-LABEL: sil hidden @_T09let_decls018testAddressOnlyGetE14GlobalPropertyAA14SimpleProtocol_pyF // CHECK: bb0(%0 : $*SimpleProtocol): // CHECK-NEXT: // function_ref // CHECK-NEXT: %1 = function_ref @_T09let_decls014addressOnlyGetD14GlobalPropertyAA14SimpleProtocol_pfg // CHECK-NEXT: %2 = apply %1(%0) : $@convention(thin) () -> @out SimpleProtocol // CHECK-NEXT: %3 = tuple () // CHECK-NEXT: return %3 : $() // CHECK-NEXT: } func testAddressOnlyGetOnlyGlobalProperty() -> SimpleProtocol { return addressOnlyGetOnlyGlobalProperty } // rdar://15962740 struct LetDeclInStruct { let immutable: Int init() { immutable = 1 } } // rdar://19854166 - Swift 1.2 uninitialized constant causes crash // The destroy_addr for a let stack temporary should be generated against // mark_uninitialized instruction, so DI will see it. func test_unassigned_let_constant() { let string : String } // CHECK: [[S:%[0-9]+]] = alloc_stack $String, let, name "string" // CHECK-NEXT: [[MUI:%[0-9]+]] = mark_uninitialized [var] [[S]] : $*String // CHECK-NEXT: destroy_addr [[MUI]] : $*String // CHECK-NEXT: dealloc_stack [[S]] : $*String