Skip to content

Commit 6c960af

Browse files
committed
[sil-combine] Enable unchecked_ref_cast formation from rawpointer_to_ref round trips when compiling with ownership.
1 parent 29d2458 commit 6c960af

File tree

2 files changed

+77
-18
lines changed

2 files changed

+77
-18
lines changed

lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -703,18 +703,45 @@ visitUnconditionalCheckedCastInst(UnconditionalCheckedCastInst *UCCI) {
703703
}
704704

705705
SILInstruction *
706-
SILCombiner::
707-
visitRawPointerToRefInst(RawPointerToRefInst *RawToRef) {
708-
if (RawToRef->getFunction()->hasOwnership())
709-
return nullptr;
710-
706+
SILCombiner::visitRawPointerToRefInst(RawPointerToRefInst *rawToRef) {
711707
// (raw_pointer_to_ref (ref_to_raw_pointer x X->Y) Y->Z)
712708
// ->
713-
// (unchecked_ref_cast X->Z)
714-
if (auto *RefToRaw = dyn_cast<RefToRawPointerInst>(RawToRef->getOperand())) {
715-
return Builder.createUncheckedRefCast(RawToRef->getLoc(),
716-
RefToRaw->getOperand(),
717-
RawToRef->getType());
709+
// (unchecked_ref_cast x X->Z)
710+
if (auto *refToRaw = dyn_cast<RefToRawPointerInst>(rawToRef->getOperand())) {
711+
if (!hasOwnership()) {
712+
return Builder.createUncheckedRefCast(
713+
rawToRef->getLoc(), refToRaw->getOperand(), rawToRef->getType());
714+
}
715+
716+
// raw_pointer_to_ref produces an unowned value. So we need to handle it
717+
// especially with ownership.
718+
{
719+
SILValue originalRef = refToRaw->getOperand();
720+
OwnershipRAUWHelper helper(ownershipFixupContext, rawToRef, originalRef);
721+
if (helper) {
722+
// We use the refToRaw's insertion point to insert our
723+
// unchecked_ref_cast, since we don't know if our guaranteed value
724+
SILBuilderWithScope localBuilder(std::next(refToRaw->getIterator()),
725+
Builder);
726+
// Since we are using std::next, we use getAutogeneratedLocation to
727+
// avoid any issues if our next insertion point is a terminator.
728+
auto loc = RegularLocation::getAutoGeneratedLocation();
729+
auto *newInst = localBuilder.createUncheckedRefCast(
730+
loc, originalRef, rawToRef->getType());
731+
// If we have an operand with ownership, we need to change our
732+
// unchecked_ref_cast to produce an unowned value. This is because
733+
// otherwise, our unchecked_ref_cast will consume the underlying owned
734+
// value, changing a BitwiseEscape to a LifetimeEnding use?! In
735+
// contrast, for guaranteed, we are replacing a BitwiseEscape use
736+
// (ref_to_rawpointer) with a ForwardedBorrowingUse (unchecked_ref_cast)
737+
// which is safe.
738+
if (newInst->getOwnershipKind() == OwnershipKind::Owned) {
739+
newInst->setOwnershipKind(OwnershipKind::Unowned);
740+
}
741+
helper.perform(newInst);
742+
return nullptr;
743+
}
744+
}
718745
}
719746

720747
return nullptr;

test/SILOptimizer/sil_combine_ossa.sil

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,14 +1493,15 @@ bb0(%0 : @owned $B):
14931493
return %2 : $F
14941494
}
14951495

1496-
// We do not support this in OSSA today.
1497-
//
1498-
// CHECK-LABEL: sil [ossa] @unchecked_ref_cast_formation : $@convention(thin) (@owned B) -> @owned F {
1499-
// XHECK: bb0([[INPUT_REF:%[0-9]+]] : @owned $B):
1500-
// XHECK: ref_to_raw_pointer
1501-
// XHECK: raw_pointer_to_ref
1502-
// XHECK: } // end sil function 'unchecked_ref_cast_formation'
1503-
sil [ossa] @unchecked_ref_cast_formation : $@convention(thin) (@owned B) -> @owned F {
1496+
// CHECK-LABEL: sil [ossa] @unchecked_ref_cast_formation_owned : $@convention(thin) (@owned B) -> @owned F {
1497+
// CHECK: bb0([[INPUT_REF:%[0-9]+]] : @owned $B):
1498+
// CHECK-NOT: ref_to_raw_pointer
1499+
// CHECK-NOT: raw_pointer_to_ref
1500+
// CHECK: unchecked_ref_cast
1501+
// CHECK-NOT: ref_to_raw_pointer
1502+
// CHECK-NOT: raw_pointer_to_ref
1503+
// CHECK: } // end sil function 'unchecked_ref_cast_formation_owned'
1504+
sil [ossa] @unchecked_ref_cast_formation_owned : $@convention(thin) (@owned B) -> @owned F {
15041505
bb0(%0 : @owned $B):
15051506
%1 = ref_to_raw_pointer %0 : $B to $Builtin.RawPointer
15061507
%2 = raw_pointer_to_ref %1 : $Builtin.RawPointer to $F
@@ -1509,6 +1510,37 @@ bb0(%0 : @owned $B):
15091510
return %3 : $F
15101511
}
15111512

1513+
// CHECK-LABEL: sil [ossa] @unchecked_ref_cast_formation_guaranteed : $@convention(thin) (@guaranteed B) -> @owned F {
1514+
// CHECK: bb0([[INPUT_REF:%[0-9]+]] : @guaranteed $B):
1515+
// CHECK-NOT: ref_to_raw_pointer
1516+
// CHECK-NOT: raw_pointer_to_ref
1517+
// CHECK: unchecked_ref_cast
1518+
// CHECK-NOT: ref_to_raw_pointer
1519+
// CHECK-NOT: raw_pointer_to_ref
1520+
// CHECK: } // end sil function 'unchecked_ref_cast_formation_guaranteed'
1521+
sil [ossa] @unchecked_ref_cast_formation_guaranteed : $@convention(thin) (@guaranteed B) -> @owned F {
1522+
bb0(%0 : @guaranteed $B):
1523+
%1 = ref_to_raw_pointer %0 : $B to $Builtin.RawPointer
1524+
%2 = raw_pointer_to_ref %1 : $Builtin.RawPointer to $F
1525+
%3 = copy_value %2 : $F
1526+
return %3 : $F
1527+
}
1528+
1529+
// CHECK-LABEL: sil [ossa] @unchecked_ref_cast_formation_unowned : $@convention(thin) (B) -> F {
1530+
// CHECK: bb0([[INPUT_REF:%[0-9]+]] :
1531+
// CHECK-NOT: ref_to_raw_pointer
1532+
// CHECK-NOT: raw_pointer_to_ref
1533+
// CHECK: unchecked_ref_cast
1534+
// CHECK-NOT: ref_to_raw_pointer
1535+
// CHECK-NOT: raw_pointer_to_ref
1536+
// CHECK: } // end sil function 'unchecked_ref_cast_formation_unowned'
1537+
sil [ossa] @unchecked_ref_cast_formation_unowned : $@convention(thin) (B) -> F {
1538+
bb0(%0 : @unowned $B):
1539+
%1 = ref_to_raw_pointer %0 : $B to $Builtin.RawPointer
1540+
%2 = raw_pointer_to_ref %1 : $Builtin.RawPointer to $F
1541+
return %2 : $F
1542+
}
1543+
15121544
// CHECK-LABEL: sil [ossa] @upcast_unchecked_ref_cast_roundtrip : $@convention(thin) (@owned B) -> @owned B {
15131545
// CHECK-NOT: unchecked_ref_cast
15141546
// CHECK-NOT: upcast

0 commit comments

Comments
 (0)