Skip to content

Commit 8db4bb5

Browse files
committed
Fix SILCombine to use OSSA RAUW prepareReplacement
These SILCombine patterns produce new instructions that use the the original value after it is updated for OSSA. The RAUW utility needs to copy/borrow the original value before SILCombine can generate the new replacement. Then SILCombine can pass that replacement back to RAUW to perform the final replaceAllUsesWith. 1. PointerToAddress and RawPointerToRef Fixes bugs where RAUW inserts borrows in the wrong place. 2. UncheckedBitwiseCast The OSSA RAUW helper is incorrect here for producing a new UncheckedRefCast. Simply don't use it. Since a bitwise cast is an "Unowned" pointer escape, simply convert the unchecked_bitwise_cast opcode to unchecked_ref_cast with Unowned forwarding ownership. 3. ConvertFunction Make sure RAUW is never called with a replacement value that has different ownership than the original.
1 parent 36fb073 commit 8db4bb5

File tree

1 file changed

+35
-33
lines changed

1 file changed

+35
-33
lines changed

lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -237,13 +237,17 @@ visitPointerToAddressInst(PointerToAddressInst *PTAI) {
237237
// handle issues around interior pointers and expanding borrow scopes.
238238
if (auto *ATPI = dyn_cast<AddressToPointerInst>(PTAI->getOperand())) {
239239
if (!hasOwnership()) {
240-
return Builder.createUncheckedAddrCast(PTAI->getLoc(), ATPI->getOperand(),
240+
return Builder.createUncheckedAddrCast(PTAI->getLoc(),
241+
ATPI->getOperand(),
241242
PTAI->getType());
242243
}
243244

244-
OwnershipRAUWHelper helper(ownershipFixupContext, PTAI, ATPI->getOperand());
245+
OwnershipRAUWHelper helper(ownershipFixupContext, PTAI,
246+
ATPI->getOperand());
245247
if (helper) {
246-
auto *newInst = Builder.createUncheckedAddrCast(PTAI->getLoc(), ATPI->getOperand(),
248+
auto replacement = helper.prepareReplacement();
249+
auto *newInst = Builder.createUncheckedAddrCast(PTAI->getLoc(),
250+
replacement,
247251
PTAI->getType());
248252
helper.perform(newInst);
249253
return nullptr;
@@ -726,8 +730,9 @@ SILCombiner::visitRawPointerToRefInst(RawPointerToRefInst *rawToRef) {
726730
// Since we are using std::next, we use getAutogeneratedLocation to
727731
// avoid any issues if our next insertion point is a terminator.
728732
auto loc = RegularLocation::getAutoGeneratedLocation();
733+
auto replacement = helper.prepareReplacement();
729734
auto *newInst = localBuilder.createUncheckedRefCast(
730-
loc, originalRef, rawToRef->getType());
735+
loc, replacement, rawToRef->getType());
731736
// If we have an operand with ownership, we need to change our
732737
// unchecked_ref_cast to produce an unowned value. This is because
733738
// otherwise, our unchecked_ref_cast will consume the underlying owned
@@ -800,8 +805,9 @@ visitUncheckedBitwiseCastInst(UncheckedBitwiseCastInst *UBCI) {
800805

801806
OwnershipRAUWHelper helper(ownershipFixupContext, UBCI, Oper);
802807
if (helper) {
808+
auto replacement = helper.prepareReplacement();
803809
auto *transformedOper = Builder.createUncheckedBitwiseCast(
804-
UBCI->getLoc(), Oper, UBCI->getType());
810+
UBCI->getLoc(), replacement, UBCI->getType());
805811
helper.perform(transformedOper);
806812
return nullptr;
807813
}
@@ -817,31 +823,21 @@ visitUncheckedBitwiseCastInst(UncheckedBitwiseCastInst *UBCI) {
817823
Builder.getModule()))
818824
return nullptr;
819825

820-
if (!Builder.hasOwnership()) {
821-
return Builder.createUncheckedRefCast(UBCI->getLoc(), UBCI->getOperand(),
822-
UBCI->getType());
826+
// Normally, OwnershipRAUWHelper needs to be called to handle ownership of
827+
// UBCI->getOperand(). However, we know that UBCI->getOperand() is already
828+
// available at the point of the cast, and by forcing the cast to be Unowned,
829+
// we ensure that no ownership adjustment is needed. So we can skip
830+
// prepareReplacement completely and just drop in the replacement. That avoids
831+
// an extra copy in the case that UBCI->getOperand() is Owned.
832+
auto *refCast = Builder.createUncheckedRefCast(
833+
UBCI->getLoc(), UBCI->getOperand(), UBCI->getType());
834+
if (Builder.hasOwnership()) {
835+
// A bitwise cast is always unowned, so we can safely force the reference
836+
// cast to forward as unowned and no ownership adjustment is needed.
837+
assert(UBCI->getOwnershipKind() == OwnershipKind::Unowned);
838+
refCast->setForwardingOwnershipKind(OwnershipKind::Unowned);
823839
}
824-
825-
{
826-
OwnershipRAUWHelper helper(ownershipFixupContext, UBCI, UBCI->getOperand());
827-
if (helper) {
828-
auto *newInst = Builder.createUncheckedRefCast(UBCI->getLoc(), UBCI->getOperand(),
829-
UBCI->getType());
830-
// If we have an operand with owned ownership, we change our
831-
// unchecked_ref_cast to explicitly pass the owned operand as an unowned
832-
// value. This is because otherwise, we would consume the owned value
833-
// creating breaking OSSA. In contrast, if we have a guaranteed value, we
834-
// are going to be replacing an UnownedInstantaneousUse with an
835-
// InstantaneousUse which is always safe for a guaranteed value.
836-
if (newInst->getForwardingOwnershipKind() == OwnershipKind::Owned) {
837-
newInst->setForwardingOwnershipKind(OwnershipKind::Unowned);
838-
}
839-
helper.perform(newInst);
840-
return nullptr;
841-
}
842-
}
843-
844-
return nullptr;
840+
return refCast;
845841
}
846842

847843
SILInstruction *
@@ -1064,10 +1060,11 @@ SILCombiner::visitConvertFunctionInst(ConvertFunctionInst *cfi) {
10641060
continue;
10651061
}
10661062

1067-
OwnershipRAUWHelper helper(ownershipFixupContext, pa,
1068-
cfi->getConverted());
1069-
if (!helper)
1063+
OwnershipRAUWHelper checkRAUW(ownershipFixupContext, pa,
1064+
cfi->getConverted());
1065+
if (!checkRAUW)
10701066
continue;
1067+
10711068
SmallVector<SILValue, 4> args(pa->getArguments().begin(),
10721069
pa->getArguments().end());
10731070
auto newValue = makeCopiedValueAvailable(cfi->getConverted(),
@@ -1085,7 +1082,12 @@ SILCombiner::visitConvertFunctionInst(ConvertFunctionInst *cfi) {
10851082
// We need to end the lifetime of the convert_function/partial_apply since
10861083
// the helper assumes that ossa is correct upon input.
10871084
localBuilder.emitDestroyValueOperation(pa->getLoc(), newConvert);
1088-
helper.perform(newConvert);
1085+
// 'newConvert' may have different ownership than then 'cfi'. newConvert
1086+
// is always owned, while 'cfi' may have been guaranteed. OSSA-RAUW
1087+
// validity depends on the ownership kind. Reinstantiate
1088+
// OwnershipRAUWHelper to verify that it is still valid
1089+
// (a very fast check in this case).
1090+
OwnershipRAUWHelper(ownershipFixupContext, pa, newConvert).perform();
10891091
}
10901092
}
10911093

0 commit comments

Comments
 (0)