@@ -1751,7 +1751,9 @@ SILInstruction *SILCombiner::visitUncheckedTakeEnumDataAddrInst(
1751
1751
SILType payloadType = tedai->getType ().getObjectType ();
1752
1752
1753
1753
// Go back through a second time now that we know all of our users are
1754
- // loads. Perform the transformation on each load.
1754
+ // loads. Perform the transformation on each load at the load's use site. The
1755
+ // reason that we have to do this is that otherwise we would be hoisting the
1756
+ // loads causing us to need to consider additional ARC issues.
1755
1757
while (!tedai->use_empty ()) {
1756
1758
auto *use = *tedai->use_begin ();
1757
1759
auto *user = use->getUser ();
@@ -1763,40 +1765,52 @@ SILInstruction *SILCombiner::visitUncheckedTakeEnumDataAddrInst(
1763
1765
}
1764
1766
1765
1767
// Insert a new Load of the enum and extract the data from that.
1768
+ //
1769
+ // NOTE: This is potentially hoisting the load, so we need to insert
1770
+ // compensating destroys.
1766
1771
auto *svi = cast<SingleValueInstruction>(user);
1767
1772
SILValue newValue;
1768
1773
if (auto *oldLoad = dyn_cast<LoadInst>(svi)) {
1774
+ SILBuilderWithScope localBuilder (oldLoad, Builder);
1769
1775
// If the old load is trivial and our enum addr is non-trivial, we need to
1770
1776
// use a load_borrow here. We know that the unchecked_enum_data will
1771
1777
// produce a trivial value meaning that we can just do a
1772
1778
// load_borrow/immediately end the lifetime here.
1773
1779
if (oldLoad->getOwnershipQualifier () == LoadOwnershipQualifier::Trivial &&
1774
1780
!enumAddr->getType ().isTrivial (Builder.getFunction ())) {
1775
- Builder.emitScopedBorrowOperation (loc, enumAddr, [&](SILValue newLoad) {
1776
- newValue = Builder.createUncheckedEnumData (loc, newLoad, enumElt,
1777
- payloadType);
1778
- });
1781
+ localBuilder.emitScopedBorrowOperation (
1782
+ loc, enumAddr, [&](SILValue newLoad) {
1783
+ newValue = localBuilder.createUncheckedEnumData (
1784
+ loc, newLoad, enumElt, payloadType);
1785
+ });
1779
1786
} else {
1780
- auto newLoad = Builder .emitLoadValueOperation (
1787
+ auto newLoad = localBuilder .emitLoadValueOperation (
1781
1788
loc, enumAddr, oldLoad->getOwnershipQualifier ());
1782
- newValue =
1783
- Builder. createUncheckedEnumData (loc, newLoad, enumElt, payloadType);
1789
+ newValue = localBuilder. createUncheckedEnumData (loc, newLoad, enumElt,
1790
+ payloadType);
1784
1791
}
1785
1792
} else if (auto *lbi = cast<LoadBorrowInst>(svi)) {
1786
- auto newLoad = Builder.emitLoadBorrowOperation (loc, enumAddr);
1793
+ SILBuilderWithScope localBuilder (lbi, Builder);
1794
+ auto newLoad = localBuilder.emitLoadBorrowOperation (loc, enumAddr);
1787
1795
for (auto ui = lbi->consuming_use_begin (), ue = lbi->consuming_use_end ();
1788
1796
ui != ue; ui = lbi->consuming_use_begin ()) {
1789
1797
// We already checked that all of our uses here are end_borrow above.
1790
1798
assert (isa<EndBorrowInst>(ui->getUser ()) &&
1791
1799
" Expected only end_borrow consuming uses" );
1792
1800
ui->set (newLoad);
1793
1801
}
1794
- newValue =
1795
- Builder.createUncheckedEnumData (loc, newLoad, enumElt, payloadType);
1802
+ // Any lifetime ending uses of our original load_borrow have been
1803
+ // rewritten by the previous loop to be on the new load_borrow. The reason
1804
+ // that we must do this is end_borrows only are placed on borrow
1805
+ // introducing guaranteed values and our unchecked_enum_data (unlike the
1806
+ // old load_borrow of the same type) is not one.
1807
+ newValue = localBuilder.createUncheckedEnumData (loc, newLoad, enumElt,
1808
+ payloadType);
1796
1809
}
1797
1810
assert (newValue);
1798
1811
1799
- // Replace all uses of the old load with the data and erase the old load.
1812
+ // Replace all uses of the old load with the newValue and erase the old
1813
+ // load.
1800
1814
replaceInstUsesWith (*svi, newValue);
1801
1815
eraseInstFromFunction (*svi);
1802
1816
}
0 commit comments