Skip to content

Commit 35f941f

Browse files
committed
[sil-combine] Update unchecked_take_enum_data_addr -> unchecked_enum_data promotion for ownership.
1 parent ac2ef83 commit 35f941f

File tree

2 files changed

+102
-42
lines changed

2 files changed

+102
-42
lines changed

lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp

Lines changed: 61 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1644,40 +1644,49 @@ visitUnreachableInst(UnreachableInst *UI) {
16441644
///
16451645
/// Also remove dead unchecked_take_enum_data_addr:
16461646
/// (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) {
16531649
// If our TEDAI has no users, there is nothing to do.
1654-
if (TEDAI->use_empty())
1650+
if (tedai->use_empty())
16551651
return nullptr;
16561652

16571653
bool onlyLoads = true;
16581654
bool onlyDestroys = true;
1659-
for (auto U : getNonDebugUses(TEDAI)) {
1655+
for (auto U : getNonDebugUses(tedai)) {
16601656
// 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()))
16621658
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+
16631672
if (!isa<DestroyAddrInst>(U->getUser()))
16641673
onlyDestroys = false;
16651674
}
1666-
1675+
16671676
if (onlyDestroys) {
16681677
// The unchecked_take_enum_data_addr is dead: remove it and replace all
16691678
// 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();
16721681
SILInstruction *user = use->getUser();
16731682
if (auto *dai = dyn_cast<DestroyAddrInst>(user)) {
1674-
dai->setOperand(TEDAI->getOperand());
1683+
dai->setOperand(tedai->getOperand());
16751684
} else {
16761685
assert(user->isDebugInstruction());
16771686
eraseInstFromFunction(*user);
16781687
}
16791688
}
1680-
return eraseInstFromFunction(*TEDAI);
1689+
return eraseInstFromFunction(*tedai);
16811690
}
16821691

16831692
if (!onlyLoads)
@@ -1687,38 +1696,56 @@ visitUncheckedTakeEnumDataAddrInst(UncheckedTakeEnumDataAddrInst *TEDAI) {
16871696
// thing to remember is that an enum is address only if any of its cases are
16881697
// address only. So we *could* have a loadable payload resulting from the
16891698
// TEDAI without the TEDAI being loadable itself.
1690-
if (TEDAI->getOperand()->getType().isAddressOnly(*TEDAI->getFunction()))
1699+
if (tedai->getOperand()->getType().isAddressOnly(*tedai->getFunction()))
16911700
return nullptr;
16921701

16931702
// 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();
16991708

17001709
// Go back through a second time now that we know all of our users are
17011710
// 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+
}
17061720

17071721
// 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);
17111742

17121743
// 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);
17191746
}
17201747

1721-
return eraseInstFromFunction(*TEDAI);
1748+
return eraseInstFromFunction(*tedai);
17221749
}
17231750

17241751
SILInstruction *SILCombiner::visitStrongReleaseInst(StrongReleaseInst *SRI) {

test/SILOptimizer/sil_combine_ossa.sil

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,9 +1592,9 @@ bb0(%0 : @owned $E):
15921592
// CHECK-NEXT: switch_enum [[BORROW]]
15931593
// CHECK: bb1([[GUARANTEED:%.*]] : @guaranteed
15941594
// CHECK-NEXT: end_borrow [[BORROW]]
1595-
// XHECK-NEXT: load
1596-
// XHECK-NEXT: unchecked_enum_data
1597-
// XHECK-NEXT: return
1595+
// CHECK-NEXT: load [copy]
1596+
// CHECK-NEXT: unchecked_enum_data
1597+
// CHECK-NEXT: return
15981598
// CHECK: } /
15991599
sil [ossa] @unchecked_take_enum_data_addr_promotion : $@convention(thin) (@inout FakeOptional<B>) -> @owned B {
16001600
bb0(%0 : $*FakeOptional<B>):
@@ -1917,11 +1917,12 @@ bb1:
19171917
return %1a : $FakeOptional<Builtin.NativeObject>
19181918
}
19191919

1920-
// CHECK-LABEL: sil [ossa] @dead_unchecked_take_enum_data_addr
1921-
// XHECK: bb0(%0 : $*AddressOnlyEnum):
1922-
// XHECK-NEXT: destroy_addr %0
1923-
// XHECK-NEXT: tuple
1924-
// XHECK-NEXT: return
1920+
// CHECK-LABEL: sil [ossa] @dead_unchecked_take_enum_data_addr :
1921+
// CHECK: bb0(%0 : $*AddressOnlyEnum):
1922+
// CHECK-NEXT: destroy_addr %0
1923+
// CHECK-NEXT: tuple
1924+
// CHECK-NEXT: return
1925+
// CHECK: } // end sil function 'dead_unchecked_take_enum_data_addr'
19251926
sil [ossa] @dead_unchecked_take_enum_data_addr : $@convention(thin) (@in AddressOnlyEnum) -> () {
19261927
bb0(%0 : $*AddressOnlyEnum):
19271928
%1 = unchecked_take_enum_data_addr %0 : $*AddressOnlyEnum, #AddressOnlyEnum.Loadable!enumelt
@@ -4635,3 +4636,35 @@ bb0(%0 : @owned $E):
46354636
return %res : $()
46364637
}
46374638

4639+
// Make sure we optimize this and do not put the end_borrow on the
4640+
// unchecked_enum_data and thus have the verifier hit us.
4641+
//
4642+
// CHECK-LABEL: sil [ossa] @unchecked_take_enum_data_addr_load_borrow : $@convention(thin) (@inout Optional<Builtin.NativeObject>) -> @owned Builtin.NativeObject {
4643+
// CHECK-NOT: unchecked_take_enum_data_addr
4644+
// CHECK: unchecked_enum_data
4645+
// CHECK-NOT: unchecked_take_enum_data_addr
4646+
// CHECK: } // end sil function 'unchecked_take_enum_data_addr_load_borrow'
4647+
sil [ossa] @unchecked_take_enum_data_addr_load_borrow : $@convention(thin) (@inout Optional<Builtin.NativeObject>) -> @owned Builtin.NativeObject {
4648+
bb0(%0 : $*Optional<Builtin.NativeObject>):
4649+
%1 = unchecked_take_enum_data_addr %0 : $*Optional<Builtin.NativeObject>, #Optional.some!enumelt
4650+
%2 = load_borrow %1 : $*Builtin.NativeObject
4651+
%3 = copy_value %2 : $Builtin.NativeObject
4652+
end_borrow %2 : $Builtin.NativeObject
4653+
return %3 : $Builtin.NativeObject
4654+
}
4655+
4656+
// CHECK-LABEL: sil [ossa] @unchecked_take_enum_data_addr_load_borrow_no_reborrow : $@convention(thin) (@inout Optional<Builtin.NativeObject>) -> @owned Builtin.NativeObject {
4657+
// CHECK: unchecked_take_enum_data_addr
4658+
// CHECK: } // end sil function 'unchecked_take_enum_data_addr_load_borrow_no_reborrow'
4659+
sil [ossa] @unchecked_take_enum_data_addr_load_borrow_no_reborrow : $@convention(thin) (@inout Optional<Builtin.NativeObject>) -> @owned Builtin.NativeObject {
4660+
bb0(%0 : $*Optional<Builtin.NativeObject>):
4661+
%1 = unchecked_take_enum_data_addr %0 : $*Optional<Builtin.NativeObject>, #Optional.some!enumelt
4662+
%2 = load_borrow %1 : $*Builtin.NativeObject
4663+
br bb1(%2 : $Builtin.NativeObject)
4664+
4665+
bb1(%2a : @guaranteed $Builtin.NativeObject):
4666+
%3 = copy_value %2a : $Builtin.NativeObject
4667+
end_borrow %2a : $Builtin.NativeObject
4668+
return %3 : $Builtin.NativeObject
4669+
}
4670+

0 commit comments

Comments
 (0)