@@ -39,10 +39,18 @@ public enum FakeOptional<T> {
3939 case some(T)
4040}
4141
42+ @_moveOnly struct MOS {}
43+
44+ sil [ossa] @getKlass : $@convention(thin) () -> @owned Klass
45+ sil [ossa] @getNonTrivialStruct : $@convention(thin) () -> @owned NonTrivialStruct
46+ sil [ossa] @getMOS : $@convention(thin) () -> @owned MOS
47+
4248sil @unknown : $@convention(thin) () -> ()
4349
4450sil [ossa] @guaranteed_user : $@convention(thin) (@guaranteed Klass) -> ()
4551sil [ossa] @guaranteed_user_with_result : $@convention(thin) (@guaranteed Klass) -> @out Klass
52+ sil [ossa] @inguaranteed_user_without_result_NTS : $@convention(thin) (@in_guaranteed NonTrivialStruct) -> ()
53+ sil [ossa] @inguaranteed_user_without_result_MOS : $@convention(thin) (@in_guaranteed MOS) -> ()
4654
4755sil [ossa] @inguaranteed_user_without_result : $@convention(thin) (@in_guaranteed Klass) -> () {
4856bb0(%0 : $*Klass):
@@ -764,8 +772,7 @@ bb0(%0 : $*Builtin.NativeObject):
764772//
765773// CHECK-LABEL: sil [ossa] @takeWithLoadRelease : $@convention(thin) (@in Builtin.NativeObject) -> () {
766774// CHECK: bb0(%0 : $*Builtin.NativeObject):
767- // CHECK: [[V:%.*]] = load [copy] %0 : $*Builtin.NativeObject
768- // CHECK: destroy_addr %0 : $*Builtin.NativeObject
775+ // CHECK: [[V:%.*]] = load [take] %0 : $*Builtin.NativeObject
769776// CHECK: apply %{{.*}}([[V]]) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
770777// CHECK: destroy_value [[V]] : $Builtin.NativeObject
771778// CHECK-LABEL: } // end sil function 'takeWithLoadRelease'
@@ -1506,6 +1513,208 @@ bb2:
15061513 unwind
15071514}
15081515
1516+ // CHECK-LABEL: sil [ossa] @take_from_original_copy_addr__final_use_load_take : {{.*}} {
1517+ // CHECK: [[GET:%[^,]+]] = function_ref @getKlass
1518+ // CHECK: [[USER:%[^,]+]] = function_ref @inguaranteed_user_without_result
1519+ // CHECK: [[INSTANCE_1:%[^,]+]] = apply [[GET]]()
1520+ // CHECK: [[ADDR:%[^,]+]] = alloc_stack $Klass
1521+ // CHECK: store [[INSTANCE_1]] to [init] [[ADDR]]
1522+ // CHECK: apply [[USER]]([[ADDR]])
1523+ // CHECK: [[INSTANCE_2:%[^,]+]] = load [take] [[ADDR]]
1524+ // CHECK: dealloc_stack [[ADDR]]
1525+ // CHECK: return [[INSTANCE_2]]
1526+ // CHECK-LABEL: } // end sil function 'take_from_original_copy_addr__final_use_load_take'
1527+ sil [ossa] @take_from_original_copy_addr__final_use_load_take : $() -> @owned Klass {
1528+ %getKlass = function_ref @getKlass : $@convention(thin) () -> @owned Klass
1529+ %user = function_ref @inguaranteed_user_without_result : $@convention(thin) (@in_guaranteed Klass) -> ()
1530+ %instance_1 = apply %getKlass() : $@convention(thin) () -> @owned Klass
1531+ %src = alloc_stack $Klass
1532+ store %instance_1 to [init] %src : $*Klass
1533+ apply %user(%src) : $@convention(thin) (@in_guaranteed Klass) -> ()
1534+ %tmp = alloc_stack $Klass
1535+ copy_addr [take] %src to [init] %tmp : $*Klass
1536+ %instance_2 = load [take] %tmp : $*Klass
1537+ dealloc_stack %tmp : $*Klass
1538+ dealloc_stack %src : $*Klass
1539+ return %instance_2 : $Klass
1540+ }
1541+
1542+ // CHECK-LABEL: sil [ossa] @take_from_original_copy_addr__final_use_copy_addr_take : {{.*}} {
1543+ // CHECK: {{bb[0-9]+}}([[OUT:%[^,]+]] :
1544+ // CHECK: [[GET:%[^,]+]] = function_ref @getKlass
1545+ // CHECK: [[USER:%[^,]+]] = function_ref @inguaranteed_user_without_result
1546+ // CHECK: [[INSTANCE_1:%[^,]+]] = apply [[GET]]()
1547+ // CHECK: [[SRC:%[^,]+]] = alloc_stack $Klass
1548+ // CHECK: store [[INSTANCE_1]] to [init] [[SRC]]
1549+ // CHECK: apply [[USER]]([[SRC]])
1550+ // CHECK: copy_addr [take] [[SRC]] to [init] [[OUT]]
1551+ // CHECK: dealloc_stack [[SRC]]
1552+ // CHECK-LABEL: } // end sil function 'take_from_original_copy_addr__final_use_copy_addr_take'
1553+ sil [ossa] @take_from_original_copy_addr__final_use_copy_addr_take : $() -> @out Klass {
1554+ entry(%out : $*Klass):
1555+ %getKlass = function_ref @getKlass : $@convention(thin) () -> @owned Klass
1556+ %user = function_ref @inguaranteed_user_without_result : $@convention(thin) (@in_guaranteed Klass) -> ()
1557+ %instance_1 = apply %getKlass() : $@convention(thin) () -> @owned Klass
1558+ %src = alloc_stack $Klass
1559+ store %instance_1 to [init] %src : $*Klass
1560+ apply %user(%src) : $@convention(thin) (@in_guaranteed Klass) -> ()
1561+ %tmp = alloc_stack $Klass
1562+ copy_addr [take] %src to [init] %tmp : $*Klass
1563+ copy_addr [take] %tmp to [init] %out : $*Klass
1564+ dealloc_stack %tmp : $*Klass
1565+ dealloc_stack %src : $*Klass
1566+ %retval = tuple ()
1567+ return %retval : $()
1568+ }
1569+
1570+ // CHECK-LABEL: sil [ossa] @take_from_original_copy_addr__final_use_field_load_copy : {{.*}} {
1571+ // CHECK: [[GET:%[^,]+]] = function_ref @getNonTrivialStruct
1572+ // CHECK: [[USER:%[^,]+]] = function_ref @inguaranteed_user_without_result_NTS
1573+ // CHECK: [[INSTANCE:%[^,]+]] = apply [[GET]]()
1574+ // CHECK: [[SRC:%[^,]+]] = alloc_stack $NonTrivialStruct
1575+ // CHECK: store [[INSTANCE]] to [init] [[SRC]]
1576+ // CHECK: apply [[USER]]([[SRC]])
1577+ // CHECK: [[FIELD_ADDR:%[^,]+]] = struct_element_addr [[SRC]]
1578+ // CHECK: [[FIELD:%[^,]+]] = load [copy] [[FIELD_ADDR]]
1579+ // CHECK: destroy_addr [[SRC]]
1580+ // CHECK: dealloc_stack [[SRC]]
1581+ // CHECK: return [[FIELD]]
1582+ // CHECK-LABEL: } // end sil function 'take_from_original_copy_addr__final_use_field_load_copy'
1583+ sil [ossa] @take_from_original_copy_addr__final_use_field_load_copy : $() -> @owned Klass {
1584+ %get = function_ref @getNonTrivialStruct : $@convention(thin) () -> @owned NonTrivialStruct
1585+ %user = function_ref @inguaranteed_user_without_result_NTS : $@convention(thin) (@in_guaranteed NonTrivialStruct) -> ()
1586+ %instance_1 = apply %get() : $@convention(thin) () -> @owned NonTrivialStruct
1587+ %src = alloc_stack $NonTrivialStruct
1588+ store %instance_1 to [init] %src : $*NonTrivialStruct
1589+ apply %user(%src) : $@convention(thin) (@in_guaranteed NonTrivialStruct) -> ()
1590+ %tmp = alloc_stack $NonTrivialStruct
1591+ copy_addr [take] %src to [init] %tmp : $*NonTrivialStruct
1592+ %field_addr = struct_element_addr %tmp : $*NonTrivialStruct, #NonTrivialStruct.val
1593+ %field = load [copy] %field_addr : $*Klass
1594+ destroy_addr %tmp : $*NonTrivialStruct
1595+ dealloc_stack %tmp : $*NonTrivialStruct
1596+ dealloc_stack %src : $*NonTrivialStruct
1597+ return %field : $Klass
1598+ }
1599+
1600+ // CHECK-LABEL: sil [ossa] @take_from_original_copy_addr__final_use_field_copy_addr_take : {{.*}} {
1601+ // CHECK: {{bb[0-9]+}}([[OUT:%[^,]+]] :
1602+ // CHECK: [[GET:%[^,]+]] = function_ref @getNonTrivialStruct
1603+ // CHECK: [[USER:%[^,]+]] = function_ref @inguaranteed_user_without_result_NTS
1604+ // CHECK: [[INSTANCE:%[^,]+]] = apply [[GET]]()
1605+ // CHECK: [[SRC:%[^,]+]] = alloc_stack $NonTrivialStruct
1606+ // CHECK: store [[INSTANCE]] to [init] [[SRC]]
1607+ // CHECK: apply [[USER]]([[SRC]])
1608+ // CHECK: [[FIELD_ADDR:%[^,]+]] = struct_element_addr [[SRC]]
1609+ // CHECK: copy_addr [[FIELD_ADDR]] to [init] [[OUT]]
1610+ // CHECK: destroy_addr [[SRC]]
1611+ // CHECK: dealloc_stack [[SRC]]
1612+ // CHECK-LABEL: } // end sil function 'take_from_original_copy_addr__final_use_field_copy_addr_take'
1613+ sil [ossa] @take_from_original_copy_addr__final_use_field_copy_addr_take : $() -> @out Klass {
1614+ entry(%out : $*Klass):
1615+ %getNonTrivialStruct = function_ref @getNonTrivialStruct : $@convention(thin) () -> @owned NonTrivialStruct
1616+ %user = function_ref @inguaranteed_user_without_result_NTS : $@convention(thin) (@in_guaranteed NonTrivialStruct) -> ()
1617+ %instance_1 = apply %getNonTrivialStruct() : $@convention(thin) () -> @owned NonTrivialStruct
1618+ %src = alloc_stack $NonTrivialStruct
1619+ store %instance_1 to [init] %src : $*NonTrivialStruct
1620+ apply %user(%src) : $@convention(thin) (@in_guaranteed NonTrivialStruct) -> ()
1621+ %tmp = alloc_stack $NonTrivialStruct
1622+ copy_addr [take] %src to [init] %tmp : $*NonTrivialStruct
1623+ %field_addr = struct_element_addr %tmp : $*NonTrivialStruct, #NonTrivialStruct.val
1624+ copy_addr %field_addr to [init] %out : $*Klass
1625+ destroy_addr %tmp : $*NonTrivialStruct
1626+ dealloc_stack %tmp : $*NonTrivialStruct
1627+ dealloc_stack %src : $*NonTrivialStruct
1628+ %retval = tuple ()
1629+ return %retval : $()
1630+ }
1631+
1632+ // CHECK-LABEL: sil [ossa] @take_from_original_copy_addr__final_use_load_copy : {{.*}} {
1633+ // CHECK: [[GET:%[^,]+]] = function_ref @getKlass
1634+ // CHECK: [[USER:%[^,]+]] = function_ref @inguaranteed_user_without_result
1635+ // CHECK: [[INSTANCE_1:%[^,]+]] = apply [[GET]]()
1636+ // CHECK: [[SRC:%[^,]+]] = alloc_stack $Klass
1637+ // CHECK: store [[INSTANCE_1]] to [init] [[SRC]]
1638+ // CHECK: apply [[USER]]([[SRC]])
1639+ // CHECK: [[INSTANCE_2:%[^,]+]] = load [copy] [[SRC]]
1640+ // CHECK: destroy_addr [[SRC]]
1641+ // CHECK: dealloc_stack [[SRC]]
1642+ // CHECK: return [[INSTANCE_2]]
1643+ // CHECK-LABEL: } // end sil function 'take_from_original_copy_addr__final_use_load_copy'
1644+ sil [ossa] @take_from_original_copy_addr__final_use_load_copy : $() -> @owned Klass {
1645+ %getKlass = function_ref @getKlass : $@convention(thin) () -> @owned Klass
1646+ %user = function_ref @inguaranteed_user_without_result : $@convention(thin) (@in_guaranteed Klass) -> ()
1647+ %instance_1 = apply %getKlass() : $@convention(thin) () -> @owned Klass
1648+ %src = alloc_stack $Klass
1649+ store %instance_1 to [init] %src : $*Klass
1650+ apply %user(%src) : $@convention(thin) (@in_guaranteed Klass) -> ()
1651+ %tmp = alloc_stack $Klass
1652+ copy_addr [take] %src to [init] %tmp : $*Klass
1653+ %instance_2 = load [copy] %tmp : $*Klass
1654+ destroy_addr %tmp : $*Klass
1655+ dealloc_stack %tmp : $*Klass
1656+ dealloc_stack %src : $*Klass
1657+ return %instance_2 : $Klass
1658+ }
1659+
1660+ // CHECK-LABEL: sil [ossa] @take_from_original_copy_addr__final_use_copy_addr_copy : {{.*}} {
1661+ // CHECK: {{bb[0-9]+}}([[OUT:%[^,]+]] : $*Klass):
1662+ // CHECK: [[GET:%[^,]+]] = function_ref @getKlass
1663+ // CHECK: [[USER:%[^,]+]] = function_ref @inguaranteed_user_without_result
1664+ // CHECK: [[INSTANCE:%[^,]+]] = apply [[GET]]()
1665+ // CHECK: [[SRC:%[^,]+]] = alloc_stack $Klass
1666+ // CHECK: store [[INSTANCE]] to [init] [[SRC]]
1667+ // CHECK: apply [[USER]]([[SRC]])
1668+ // CHECK: copy_addr [[SRC]] to [init] [[OUT]]
1669+ // CHECK: destroy_addr [[SRC]]
1670+ // CHECK: dealloc_stack [[SRC]]
1671+ // CHECK-LABEL: } // end sil function 'take_from_original_copy_addr__final_use_copy_addr_copy'
1672+ sil [ossa] @take_from_original_copy_addr__final_use_copy_addr_copy : $() -> @out Klass {
1673+ entry(%out : $*Klass):
1674+ %getKlass = function_ref @getKlass : $@convention(thin) () -> @owned Klass
1675+ %user = function_ref @inguaranteed_user_without_result : $@convention(thin) (@in_guaranteed Klass) -> ()
1676+ %instance_1 = apply %getKlass() : $@convention(thin) () -> @owned Klass
1677+ %src = alloc_stack $Klass
1678+ store %instance_1 to [init] %src : $*Klass
1679+ apply %user(%src) : $@convention(thin) (@in_guaranteed Klass) -> ()
1680+ %tmp = alloc_stack $Klass
1681+ copy_addr [take] %src to [init] %tmp : $*Klass
1682+ copy_addr %tmp to [init] %out : $*Klass
1683+ destroy_addr %tmp : $*Klass
1684+ dealloc_stack %tmp : $*Klass
1685+ dealloc_stack %src : $*Klass
1686+ %retval = tuple ()
1687+ return %retval : $()
1688+ }
1689+
1690+ // CHECK-LABEL: sil [ossa] @take_from_original_copy_addr__final_use_apply__move_only : {{.*}} {
1691+ // CHECK: [[GET:%[^,]+]] = function_ref @getMOS
1692+ // CHECK: [[USER:%[^,]+]] = function_ref @inguaranteed_user_without_result_MOS
1693+ // CHECK: [[INSTANCE:%[^,]+]] = apply [[GET]]()
1694+ // CHECK: [[SRC:%[^,]+]] = alloc_stack $MOS
1695+ // CHECK: store [[INSTANCE]] to [init] [[SRC]]
1696+ // CHECK: apply [[USER]]([[SRC]])
1697+ // CHECK: apply [[USER]]([[SRC]])
1698+ // CHECK: destroy_addr [[SRC]]
1699+ // CHECK: dealloc_stack [[SRC]]
1700+ // CHECK-LABEL: } // end sil function 'take_from_original_copy_addr__final_use_apply__move_only'
1701+ sil [ossa] @take_from_original_copy_addr__final_use_apply__move_only : $() -> () {
1702+ %getMOS = function_ref @getMOS : $@convention(thin) () -> @owned MOS
1703+ %user = function_ref @inguaranteed_user_without_result_MOS : $@convention(thin) (@in_guaranteed MOS) -> ()
1704+ %instance_1 = apply %getMOS() : $@convention(thin) () -> @owned MOS
1705+ %src = alloc_stack $MOS
1706+ store %instance_1 to [init] %src : $*MOS
1707+ apply %user(%src) : $@convention(thin) (@in_guaranteed MOS) -> ()
1708+ %tmp = alloc_stack $MOS
1709+ copy_addr [take] %src to [init] %tmp : $*MOS
1710+ apply %user(%tmp) : $@convention(thin) (@in_guaranteed MOS) -> ()
1711+ destroy_addr %tmp : $*MOS
1712+ dealloc_stack %tmp : $*MOS
1713+ dealloc_stack %src : $*MOS
1714+ %tuple = tuple ()
1715+ return %tuple : $()
1716+ }
1717+
15091718// This does not get optimized correctly because of the conservative treatment of load_borrow/end_borrow in MemBehavior
15101719// CHECK-LABEL: sil [ossa] @test_temprvoborrowboundary1 :
15111720// CHECK: copy_addr
@@ -1584,3 +1793,31 @@ entry(%instance : $*NonTrivialStruct):
15841793 %retval = tuple ()
15851794 return %retval : $()
15861795}
1796+
1797+ // Verify that no copy of an instance of the move-only type MOS is introduced.
1798+ // CHECK-LABEL: sil hidden [ossa] @dont_copy_move_only_struct : {{.*}} {
1799+ // CHECK: [[SRC:%[^,]+]] = alloc_stack $MOS
1800+ // CHECK: [[GET:%[^,]+]] = function_ref @getMOS
1801+ // CHECK: [[INSTANCE_1:%[^,]+]] = apply [[GET]]()
1802+ // CHECK: store [[INSTANCE_1]] to [init] [[SRC]]
1803+ // CHECK: [[INSTANCE_2:%[^,]+]] = load [take] [[SRC]]
1804+ // CHECK: store [[INSTANCE_2]] to [init] [[SRC]]
1805+ // CHECK: [[INSTANCE_3:%[^,]+]] = load [take] [[SRC]]
1806+ // CHECK: dealloc_stack [[SRC]]
1807+ // CHECK: return [[INSTANCE_3]]
1808+ // CHECK-LABEL: } // end sil function 'dont_copy_move_only_struct'
1809+ sil hidden [ossa] @dont_copy_move_only_struct : $@convention(thin) () -> @owned MOS {
1810+ bb0:
1811+ %src = alloc_stack $MOS
1812+ %getMOS = function_ref @getMOS : $@convention(thin) () -> @owned MOS
1813+ %instance_1 = apply %getMOS() : $@convention(thin) () -> @owned MOS
1814+ store %instance_1 to [init] %src : $*MOS
1815+ %tmp = alloc_stack $MOS
1816+ copy_addr [take] %src to [init] %tmp : $*MOS
1817+ %instance_2 = load [take] %tmp : $*MOS
1818+ store %instance_2 to [init] %src : $*MOS
1819+ %instance_3 = load [take] %src : $*MOS
1820+ dealloc_stack %tmp : $*MOS
1821+ dealloc_stack %src : $*MOS
1822+ return %instance_3 : $MOS
1823+ }
0 commit comments