Skip to content

Commit 2a3e7ba

Browse files
Merge pull request #65052 from nate-chandler/rdar104729396
[TempRValueOpt] Fold added destroy_addrs into loads/copy_addrs.
2 parents 4b3c51f + 1021519 commit 2a3e7ba

File tree

2 files changed

+279
-10
lines changed

2 files changed

+279
-10
lines changed

lib/SILOptimizer/Transforms/TempRValueElimination.cpp

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -535,10 +535,11 @@ void TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) {
535535
SILValue copySrc = copyInst->getSrc();
536536
assert(tempObj != copySrc && "can't initialize temporary with itself");
537537

538-
// If the source of the copyInst is taken, we must insert a compensating
539-
// destroy_addr. This must be done at the right spot: after the last use
540-
// tempObj, but before any (potential) re-initialization of the source.
541-
bool needToInsertDestroy = copyInst->isTakeOfSrc();
538+
// If the source of the copyInst is taken, it must be deinitialized (via
539+
// destroy_addr, load [take], copy_addr [take]). This must be done at the
540+
// right spot: after the last use tempObj, but before any (potential)
541+
// re-initialization of the source.
542+
bool needFinalDeinit = copyInst->isTakeOfSrc();
542543

543544
// Scan all uses of the temporary storage (tempObj) to verify they all refer
544545
// to the value initialized by this copy. It is sufficient to check that the
@@ -557,7 +558,7 @@ void TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) {
557558

558559
// Also, destroys are allowed to be in a different block.
559560
if (isa<DestroyAddrInst>(user)) {
560-
if (!isOSSA && needToInsertDestroy) {
561+
if (!isOSSA && needFinalDeinit) {
561562
// In non-OSSA mode, for the purpose of inserting the destroy of
562563
// copySrc, we have to be conservative and assume that the lifetime of
563564
// tempObj goes beyond it's last use - until the final destroy_addr.
@@ -588,7 +589,7 @@ void TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) {
588589
// Example:
589590
// copy_addr [take] %copySrc to [init] %tempObj // copyInst
590591
// copy_addr [take] %tempObj to [init] %copySrc // lastLoadInst
591-
if (needToInsertDestroy && lastLoadInst != copyInst &&
592+
if (needFinalDeinit && lastLoadInst != copyInst &&
592593
!isa<DestroyAddrInst>(lastLoadInst) &&
593594
aa->mayWriteToMemory(lastLoadInst, copySrc))
594595
return;
@@ -601,6 +602,34 @@ void TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) {
601602

602603
LLVM_DEBUG(llvm::dbgs() << " Success: replace temp" << *tempObj);
603604

605+
// If copyInst's source must be deinitialized, whether that must be done via
606+
// a newly created destroy_addr.
607+
//
608+
// If lastLoadInst is a load or a copy_addr, then the deinitialization can be
609+
// done in that instruction.
610+
//
611+
// This is necessary for correctness: otherwise, copies of move-only values
612+
// would be introduced.
613+
bool needToInsertDestroy = [&]() {
614+
if (!needFinalDeinit)
615+
return false;
616+
if (lastLoadInst == copyInst)
617+
return true;
618+
if (auto *cai = dyn_cast<CopyAddrInst>(lastLoadInst)) {
619+
auto retval = cai->getSrc() != tempObj || !cai->isTakeOfSrc();
620+
assert(!tempObj->getType().isMoveOnly() ||
621+
!retval && "introducing copy of move-only value!?");
622+
return retval;
623+
}
624+
if (auto *li = dyn_cast<LoadInst>(lastLoadInst)) {
625+
auto retval = li->getOperand() != tempObj ||
626+
li->getOwnershipQualifier() != LoadOwnershipQualifier::Take;
627+
assert(!tempObj->getType().isMoveOnly() ||
628+
!retval && "introducing copy of move-only value!?");
629+
return retval;
630+
}
631+
return true;
632+
}();
604633
if (needToInsertDestroy) {
605634
// Compensate the [take] of the original copyInst.
606635
SILBuilderWithScope::insertAfter(lastLoadInst, [&] (SILBuilder &builder) {
@@ -630,16 +659,19 @@ void TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) {
630659
auto *cai = cast<CopyAddrInst>(user);
631660
if (cai != copyInst) {
632661
assert(cai->getSrc() == tempObj);
633-
if (cai->isTakeOfSrc())
662+
if (cai->isTakeOfSrc() && (!needFinalDeinit || lastLoadInst != cai)) {
634663
cai->setIsTakeOfSrc(IsNotTake);
664+
}
635665
}
636666
use->set(copySrc);
637667
break;
638668
}
639669
case SILInstructionKind::LoadInst: {
640670
auto *li = cast<LoadInst>(user);
641-
if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Take)
671+
if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Take &&
672+
(!needFinalDeinit || li != lastLoadInst)) {
642673
li->setOwnershipQualifier(LoadOwnershipQualifier::Copy);
674+
}
643675
use->set(copySrc);
644676
break;
645677
}

test/SILOptimizer/temp_rvalue_opt_ossa.sil

Lines changed: 239 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
4248
sil @unknown : $@convention(thin) () -> ()
4349

4450
sil [ossa] @guaranteed_user : $@convention(thin) (@guaranteed Klass) -> ()
4551
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) -> ()
4654

4755
sil [ossa] @inguaranteed_user_without_result : $@convention(thin) (@in_guaranteed Klass) -> () {
4856
bb0(%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

Comments
 (0)