Skip to content

Commit 2740d1e

Browse files
authored
Merge pull request #35804 from gottesmm/pr-0bd4a6dafe939618a9f1dfbd0498451d191c9b66
[sil-combine] Leave the new load at the old load site when promoting unchecked_take_enum_data_addr + load -> load + unchecked_enum_data.
2 parents faec07e + d1e462c commit 2740d1e

File tree

2 files changed

+78
-12
lines changed

2 files changed

+78
-12
lines changed

lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1751,7 +1751,9 @@ SILInstruction *SILCombiner::visitUncheckedTakeEnumDataAddrInst(
17511751
SILType payloadType = tedai->getType().getObjectType();
17521752

17531753
// 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.
17551757
while (!tedai->use_empty()) {
17561758
auto *use = *tedai->use_begin();
17571759
auto *user = use->getUser();
@@ -1763,40 +1765,52 @@ SILInstruction *SILCombiner::visitUncheckedTakeEnumDataAddrInst(
17631765
}
17641766

17651767
// 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.
17661771
auto *svi = cast<SingleValueInstruction>(user);
17671772
SILValue newValue;
17681773
if (auto *oldLoad = dyn_cast<LoadInst>(svi)) {
1774+
SILBuilderWithScope localBuilder(oldLoad, Builder);
17691775
// If the old load is trivial and our enum addr is non-trivial, we need to
17701776
// use a load_borrow here. We know that the unchecked_enum_data will
17711777
// produce a trivial value meaning that we can just do a
17721778
// load_borrow/immediately end the lifetime here.
17731779
if (oldLoad->getOwnershipQualifier() == LoadOwnershipQualifier::Trivial &&
17741780
!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+
});
17791786
} else {
1780-
auto newLoad = Builder.emitLoadValueOperation(
1787+
auto newLoad = localBuilder.emitLoadValueOperation(
17811788
loc, enumAddr, oldLoad->getOwnershipQualifier());
1782-
newValue =
1783-
Builder.createUncheckedEnumData(loc, newLoad, enumElt, payloadType);
1789+
newValue = localBuilder.createUncheckedEnumData(loc, newLoad, enumElt,
1790+
payloadType);
17841791
}
17851792
} 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);
17871795
for (auto ui = lbi->consuming_use_begin(), ue = lbi->consuming_use_end();
17881796
ui != ue; ui = lbi->consuming_use_begin()) {
17891797
// We already checked that all of our uses here are end_borrow above.
17901798
assert(isa<EndBorrowInst>(ui->getUser()) &&
17911799
"Expected only end_borrow consuming uses");
17921800
ui->set(newLoad);
17931801
}
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);
17961809
}
17971810
assert(newValue);
17981811

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.
18001814
replaceInstUsesWith(*svi, newValue);
18011815
eraseInstFromFunction(*svi);
18021816
}

test/SILOptimizer/sil_combine_ossa.sil

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ sil @use_anyobject_guaranteed : $@convention(thin) (@guaranteed AnyObject) -> ()
6868
sil @use_generic_obj_guaranteed : $@convention(thin) <τ_0_0> (@guaranteed τ_0_0) -> ()
6969
sil [ossa] @unknown : $@convention(thin) () -> ()
7070

71+
enum KlassNativeObjEither {
72+
case lhs(Klass)
73+
case rhs(Builtin.NativeObject)
74+
}
75+
7176
//////////////////////
7277
// Simple DCE Tests //
7378
//////////////////////
@@ -4824,3 +4829,50 @@ bb1:
48244829
bb2:
48254830
unreachable
48264831
}
4832+
4833+
// Make sure that when we promote the unchecked_take_enum_data_uses in bb1, bb2,
4834+
// we keep the loads in bb1, bb2 instead of hoisting them to the
4835+
// unchecked_take_enum_data_addr that we are optimizing.
4836+
//
4837+
// CHECK-LABEL: sil [ossa] @unchecked_take_enum_data_addr_promotion_host_load : $@convention(thin) (@inout FakeOptional<KlassNativeObjEither>) -> @owned KlassNativeObjEither {
4838+
// CHECK: bb0([[ARG:%.*]] : $*
4839+
// CHECK: [[LOADED_ARG:%.*]] = load_borrow [[ARG]]
4840+
// CHECK: [[FOR_SWITCH:%.*]] = unchecked_enum_data [[LOADED_ARG]]
4841+
// CHECK: switch_enum [[FOR_SWITCH]] :
4842+
//
4843+
// CHECK: bb1(
4844+
// CHECK-NEXT: end_borrow [[LOADED_ARG]]
4845+
// CHECK-NEXT: [[LOADED_ARG_2:%.*]] = load [copy] [[ARG]]
4846+
// CHECK-NEXT: [[LOADED_ARG_2_EXT:%.*]] = unchecked_enum_data [[LOADED_ARG_2]]
4847+
// CHECK-NEXT: br bb3([[LOADED_ARG_2_EXT]] :
4848+
//
4849+
// CHECK: bb2(
4850+
// CHECK-NEXT: end_borrow [[LOADED_ARG]]
4851+
// CHECK-NEXT: [[LOADED_ARG_3:%.*]] = load [take] [[ARG]]
4852+
// CHECK-NEXT: [[LOADED_ARG_3_EXT:%.*]] = unchecked_enum_data [[LOADED_ARG_3]]
4853+
// CHECK-NEXT: [[NONE:%.*]] = enum $FakeOptional<
4854+
// CHECK-NEXT: store [[NONE]] to [init] [[ARG]]
4855+
// CHECK-NEXT: br bb3([[LOADED_ARG_3_EXT]] :
4856+
//
4857+
// CHECK: bb3([[RESULT:%.*]] : @owned
4858+
// CHECK-NEXT: return [[RESULT]]
4859+
// CHECK: } // end sil function 'unchecked_take_enum_data_addr_promotion_host_load'
4860+
sil [ossa] @unchecked_take_enum_data_addr_promotion_host_load : $@convention(thin) (@inout FakeOptional<KlassNativeObjEither>) -> @owned KlassNativeObjEither {
4861+
bb0(%0 : $*FakeOptional<KlassNativeObjEither>):
4862+
%1 = unchecked_take_enum_data_addr %0 : $*FakeOptional<KlassNativeObjEither>, #FakeOptional.some!enumelt
4863+
switch_enum_addr %1 : $*KlassNativeObjEither, case #KlassNativeObjEither.lhs!enumelt: bb1, case #KlassNativeObjEither.rhs!enumelt: bb2
4864+
4865+
bb1:
4866+
%2 = load [copy] %1 : $*KlassNativeObjEither
4867+
br bb3(%2 : $KlassNativeObjEither)
4868+
4869+
bb2:
4870+
%3 = load [take] %1 : $*KlassNativeObjEither
4871+
%nil = enum $FakeOptional<KlassNativeObjEither>, #FakeOptional.none!enumelt
4872+
store %nil to [init] %0 : $*FakeOptional<KlassNativeObjEither>
4873+
br bb3(%3 : $KlassNativeObjEither)
4874+
4875+
bb3(%4 : @owned $KlassNativeObjEither):
4876+
return %4 : $KlassNativeObjEither
4877+
}
4878+

0 commit comments

Comments
 (0)