@@ -237,13 +237,17 @@ visitPointerToAddressInst(PointerToAddressInst *PTAI) {
237
237
// handle issues around interior pointers and expanding borrow scopes.
238
238
if (auto *ATPI = dyn_cast<AddressToPointerInst>(PTAI->getOperand ())) {
239
239
if (!hasOwnership ()) {
240
- return Builder.createUncheckedAddrCast (PTAI->getLoc (), ATPI->getOperand (),
240
+ return Builder.createUncheckedAddrCast (PTAI->getLoc (),
241
+ ATPI->getOperand (),
241
242
PTAI->getType ());
242
243
}
243
244
244
- OwnershipRAUWHelper helper (ownershipFixupContext, PTAI, ATPI->getOperand ());
245
+ OwnershipRAUWHelper helper (ownershipFixupContext, PTAI,
246
+ ATPI->getOperand ());
245
247
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,
247
251
PTAI->getType ());
248
252
helper.perform (newInst);
249
253
return nullptr ;
@@ -726,8 +730,9 @@ SILCombiner::visitRawPointerToRefInst(RawPointerToRefInst *rawToRef) {
726
730
// Since we are using std::next, we use getAutogeneratedLocation to
727
731
// avoid any issues if our next insertion point is a terminator.
728
732
auto loc = RegularLocation::getAutoGeneratedLocation ();
733
+ auto replacement = helper.prepareReplacement ();
729
734
auto *newInst = localBuilder.createUncheckedRefCast (
730
- loc, originalRef , rawToRef->getType ());
735
+ loc, replacement , rawToRef->getType ());
731
736
// If we have an operand with ownership, we need to change our
732
737
// unchecked_ref_cast to produce an unowned value. This is because
733
738
// otherwise, our unchecked_ref_cast will consume the underlying owned
@@ -800,8 +805,9 @@ visitUncheckedBitwiseCastInst(UncheckedBitwiseCastInst *UBCI) {
800
805
801
806
OwnershipRAUWHelper helper (ownershipFixupContext, UBCI, Oper);
802
807
if (helper) {
808
+ auto replacement = helper.prepareReplacement ();
803
809
auto *transformedOper = Builder.createUncheckedBitwiseCast (
804
- UBCI->getLoc (), Oper , UBCI->getType ());
810
+ UBCI->getLoc (), replacement , UBCI->getType ());
805
811
helper.perform (transformedOper);
806
812
return nullptr ;
807
813
}
@@ -817,31 +823,21 @@ visitUncheckedBitwiseCastInst(UncheckedBitwiseCastInst *UBCI) {
817
823
Builder.getModule ()))
818
824
return nullptr ;
819
825
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);
823
839
}
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;
845
841
}
846
842
847
843
SILInstruction *
@@ -1064,10 +1060,11 @@ SILCombiner::visitConvertFunctionInst(ConvertFunctionInst *cfi) {
1064
1060
continue ;
1065
1061
}
1066
1062
1067
- OwnershipRAUWHelper helper (ownershipFixupContext, pa,
1068
- cfi->getConverted ());
1069
- if (!helper )
1063
+ OwnershipRAUWHelper checkRAUW (ownershipFixupContext, pa,
1064
+ cfi->getConverted ());
1065
+ if (!checkRAUW )
1070
1066
continue ;
1067
+
1071
1068
SmallVector<SILValue, 4 > args (pa->getArguments ().begin (),
1072
1069
pa->getArguments ().end ());
1073
1070
auto newValue = makeCopiedValueAvailable (cfi->getConverted (),
@@ -1085,7 +1082,12 @@ SILCombiner::visitConvertFunctionInst(ConvertFunctionInst *cfi) {
1085
1082
// We need to end the lifetime of the convert_function/partial_apply since
1086
1083
// the helper assumes that ossa is correct upon input.
1087
1084
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 ();
1089
1091
}
1090
1092
}
1091
1093
0 commit comments