@@ -1644,40 +1644,49 @@ visitUnreachableInst(UnreachableInst *UI) {
1644
1644
// /
1645
1645
// / Also remove dead unchecked_take_enum_data_addr:
1646
1646
// / (destroy_addr (unchecked_take_enum_data_addr x)) -> (destroy_addr x)
1647
- SILInstruction *
1648
- SILCombiner::
1649
- visitUncheckedTakeEnumDataAddrInst (UncheckedTakeEnumDataAddrInst *TEDAI) {
1650
- if (TEDAI->getFunction ()->hasOwnership ())
1651
- return nullptr ;
1652
-
1647
+ SILInstruction *SILCombiner::visitUncheckedTakeEnumDataAddrInst (
1648
+ UncheckedTakeEnumDataAddrInst *tedai) {
1653
1649
// If our TEDAI has no users, there is nothing to do.
1654
- if (TEDAI ->use_empty ())
1650
+ if (tedai ->use_empty ())
1655
1651
return nullptr ;
1656
1652
1657
1653
bool onlyLoads = true ;
1658
1654
bool onlyDestroys = true ;
1659
- for (auto U : getNonDebugUses (TEDAI )) {
1655
+ for (auto U : getNonDebugUses (tedai )) {
1660
1656
// Check if it is load. If it is not a load, bail...
1661
- if (!isa<LoadInst>(U->getUser ()))
1657
+ if (!isa<LoadInst>(U->getUser ()) && !isa<LoadBorrowInst>(U-> getUser ()) )
1662
1658
onlyLoads = false ;
1659
+
1660
+ // If we have a load_borrow, perform an additional check that we do not have
1661
+ // any reborrow uses. We do not handle reborrows in this optimization.
1662
+ if (auto *lbi = dyn_cast<LoadBorrowInst>(U->getUser ())) {
1663
+ // false if any consuming use is not an end_borrow.
1664
+ for (auto *use : lbi->getConsumingUses ()) {
1665
+ if (!isa<EndBorrowInst>(use->getUser ())) {
1666
+ onlyLoads = false ;
1667
+ break ;
1668
+ }
1669
+ }
1670
+ }
1671
+
1663
1672
if (!isa<DestroyAddrInst>(U->getUser ()))
1664
1673
onlyDestroys = false ;
1665
1674
}
1666
-
1675
+
1667
1676
if (onlyDestroys) {
1668
1677
// The unchecked_take_enum_data_addr is dead: remove it and replace all
1669
1678
// destroys with a destroy of its operand.
1670
- while (!TEDAI ->use_empty ()) {
1671
- Operand *use = *TEDAI ->use_begin ();
1679
+ while (!tedai ->use_empty ()) {
1680
+ Operand *use = *tedai ->use_begin ();
1672
1681
SILInstruction *user = use->getUser ();
1673
1682
if (auto *dai = dyn_cast<DestroyAddrInst>(user)) {
1674
- dai->setOperand (TEDAI ->getOperand ());
1683
+ dai->setOperand (tedai ->getOperand ());
1675
1684
} else {
1676
1685
assert (user->isDebugInstruction ());
1677
1686
eraseInstFromFunction (*user);
1678
1687
}
1679
1688
}
1680
- return eraseInstFromFunction (*TEDAI );
1689
+ return eraseInstFromFunction (*tedai );
1681
1690
}
1682
1691
1683
1692
if (!onlyLoads)
@@ -1687,38 +1696,56 @@ visitUncheckedTakeEnumDataAddrInst(UncheckedTakeEnumDataAddrInst *TEDAI) {
1687
1696
// thing to remember is that an enum is address only if any of its cases are
1688
1697
// address only. So we *could* have a loadable payload resulting from the
1689
1698
// TEDAI without the TEDAI being loadable itself.
1690
- if (TEDAI ->getOperand ()->getType ().isAddressOnly (*TEDAI ->getFunction ()))
1699
+ if (tedai ->getOperand ()->getType ().isAddressOnly (*tedai ->getFunction ()))
1691
1700
return nullptr ;
1692
1701
1693
1702
// Grab the EnumAddr.
1694
- SILLocation Loc = TEDAI ->getLoc ();
1695
- Builder.setCurrentDebugScope (TEDAI ->getDebugScope ());
1696
- SILValue EnumAddr = TEDAI ->getOperand ();
1697
- EnumElementDecl *EnumElt = TEDAI ->getElement ();
1698
- SILType PayloadType = TEDAI ->getType ().getObjectType ();
1703
+ SILLocation loc = tedai ->getLoc ();
1704
+ Builder.setCurrentDebugScope (tedai ->getDebugScope ());
1705
+ SILValue enumAddr = tedai ->getOperand ();
1706
+ EnumElementDecl *enumElt = tedai ->getElement ();
1707
+ SILType payloadType = tedai ->getType ().getObjectType ();
1699
1708
1700
1709
// Go back through a second time now that we know all of our users are
1701
1710
// loads. Perform the transformation on each load.
1702
- SmallVector<LoadInst*, 4 > ToRemove;
1703
- for (auto U : getNonDebugUses (TEDAI)) {
1704
- // Grab the load.
1705
- LoadInst *L = cast<LoadInst>(U->getUser ());
1711
+ while (!tedai->use_empty ()) {
1712
+ auto *use = *tedai->use_begin ();
1713
+ auto *user = use->getUser ();
1714
+
1715
+ // Delete debug insts.
1716
+ if (user->isDebugInstruction ()) {
1717
+ eraseInstFromFunction (*user);
1718
+ continue ;
1719
+ }
1706
1720
1707
1721
// Insert a new Load of the enum and extract the data from that.
1708
- auto *Ld =
1709
- Builder.createLoad (Loc, EnumAddr, LoadOwnershipQualifier::Unqualified);
1710
- auto *D = Builder.createUncheckedEnumData (Loc, Ld, EnumElt, PayloadType);
1722
+ auto *svi = cast<SingleValueInstruction>(user);
1723
+ SILValue newValue;
1724
+ if (auto *oldLoad = dyn_cast<LoadInst>(svi)) {
1725
+ auto newLoad = Builder.emitLoadValueOperation (
1726
+ loc, enumAddr, oldLoad->getOwnershipQualifier ());
1727
+ newValue =
1728
+ Builder.createUncheckedEnumData (loc, newLoad, enumElt, payloadType);
1729
+ } else if (auto *lbi = cast<LoadBorrowInst>(svi)) {
1730
+ auto newLoad = Builder.emitLoadBorrowOperation (loc, enumAddr);
1731
+ for (auto ui = lbi->consuming_use_begin (), ue = lbi->consuming_use_end ();
1732
+ ui != ue; ui = lbi->consuming_use_begin ()) {
1733
+ // We already checked that all of our uses here are end_borrow above.
1734
+ assert (isa<EndBorrowInst>(ui->getUser ()) &&
1735
+ " Expected only end_borrow consuming uses" );
1736
+ ui->set (newLoad);
1737
+ }
1738
+ newValue =
1739
+ Builder.createUncheckedEnumData (loc, newLoad, enumElt, payloadType);
1740
+ }
1741
+ assert (newValue);
1711
1742
1712
1743
// Replace all uses of the old load with the data and erase the old load.
1713
- replaceInstUsesWith (*L, D);
1714
- ToRemove.push_back (L);
1715
- }
1716
-
1717
- for (auto *LD : ToRemove) {
1718
- eraseInstFromFunction (*LD);
1744
+ replaceInstUsesWith (*svi, newValue);
1745
+ eraseInstFromFunction (*svi);
1719
1746
}
1720
1747
1721
- return eraseInstFromFunction (*TEDAI );
1748
+ return eraseInstFromFunction (*tedai );
1722
1749
}
1723
1750
1724
1751
SILInstruction *SILCombiner::visitStrongReleaseInst (StrongReleaseInst *SRI) {
0 commit comments