@@ -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
847843SILInstruction *
@@ -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