@@ -39,10 +39,18 @@ public enum FakeOptional<T> {
39
39
case some(T)
40
40
}
41
41
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
+
42
48
sil @unknown : $@convention(thin) () -> ()
43
49
44
50
sil [ossa] @guaranteed_user : $@convention(thin) (@guaranteed Klass) -> ()
45
51
sil [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) -> ()
46
54
47
55
sil [ossa] @inguaranteed_user_without_result : $@convention(thin) (@in_guaranteed Klass) -> () {
48
56
bb0(%0 : $*Klass):
@@ -764,8 +772,7 @@ bb0(%0 : $*Builtin.NativeObject):
764
772
//
765
773
// CHECK-LABEL: sil [ossa] @takeWithLoadRelease : $@convention(thin) (@in Builtin.NativeObject) -> () {
766
774
// 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
769
776
// CHECK: apply %{{.*}}([[V]]) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
770
777
// CHECK: destroy_value [[V]] : $Builtin.NativeObject
771
778
// CHECK-LABEL: } // end sil function 'takeWithLoadRelease'
@@ -1506,6 +1513,208 @@ bb2:
1506
1513
unwind
1507
1514
}
1508
1515
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
+
1509
1718
// This does not get optimized correctly because of the conservative treatment of load_borrow/end_borrow in MemBehavior
1510
1719
// CHECK-LABEL: sil [ossa] @test_temprvoborrowboundary1 :
1511
1720
// CHECK: copy_addr
@@ -1584,3 +1793,31 @@ entry(%instance : $*NonTrivialStruct):
1584
1793
%retval = tuple ()
1585
1794
return %retval : $()
1586
1795
}
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