mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[ownership] Update emitIndirectConditionalCastWithScalar for ownership.
This comes up because when we perform mandatory inlining, we perform the transform as we inline. So the tests for this are in mandatory_inlining naturally.
This commit is contained in:
@@ -1182,51 +1182,103 @@ bool swift::canUseScalarCheckedCastInstructions(SILModule &M,
|
||||
/// using a scalar cast operation.
|
||||
void swift::emitIndirectConditionalCastWithScalar(
|
||||
SILBuilder &B, ModuleDecl *M, SILLocation loc,
|
||||
CastConsumptionKind consumption, SILValue src, CanType sourceType,
|
||||
SILValue dest, CanType targetType, SILBasicBlock *indirectSuccBB,
|
||||
CastConsumptionKind consumption, SILValue srcAddr, CanType sourceType,
|
||||
SILValue destAddr, CanType targetType, SILBasicBlock *indirectSuccBB,
|
||||
SILBasicBlock *indirectFailBB, ProfileCounter TrueCount,
|
||||
ProfileCounter FalseCount) {
|
||||
assert(canUseScalarCheckedCastInstructions(B.getModule(),
|
||||
sourceType, targetType));
|
||||
|
||||
// We only need a different failure block if the cast consumption
|
||||
// requires us to destroy the source value.
|
||||
SILBasicBlock *scalarFailBB;
|
||||
if (!shouldDestroyOnFailure(consumption)) {
|
||||
scalarFailBB = indirectFailBB;
|
||||
} else {
|
||||
scalarFailBB = B.splitBlockForFallthrough();
|
||||
}
|
||||
|
||||
// We always need a different success block.
|
||||
// Create our successor and fail blocks.
|
||||
SILBasicBlock *scalarFailBB = B.splitBlockForFallthrough();
|
||||
SILBasicBlock *scalarSuccBB = B.splitBlockForFallthrough();
|
||||
|
||||
auto &srcTL = B.getModule().Types.getTypeLowering(src->getType());
|
||||
// Always take; this works under an assumption that retaining the result is
|
||||
// equivalent to retaining the source. That means that these casts would not
|
||||
// be appropriate for bridging-like conversions.
|
||||
//
|
||||
// Our plan is:
|
||||
//
|
||||
// 1. If the original cast was a take_always cast, then we take from our
|
||||
// memory location in the caller, store the value into dest in the success
|
||||
// block, and perform a destroy of our default argument in the failure block.
|
||||
//
|
||||
// 2. If the original cast was copy_on_success, then with ownership we borrow,
|
||||
// copy in the success path and store back into the source slot after copying.
|
||||
//
|
||||
// 3. If the original cast was take_on_success, then on success we place the
|
||||
// casted value into dest and on failure, store the original value back into
|
||||
// src.
|
||||
SILType targetValueType = destAddr->getType().getObjectType();
|
||||
// Inline constructor
|
||||
auto srcValue = ([&]() -> SILValue {
|
||||
if (consumption == CastConsumptionKind::CopyOnSuccess)
|
||||
return B.emitLoadBorrowOperation(loc, srcAddr);
|
||||
return B.emitLoadValueOperation(loc, srcAddr, LoadOwnershipQualifier::Take);
|
||||
})();
|
||||
|
||||
// Always take; this works under an assumption that retaining the
|
||||
// result is equivalent to retaining the source. That means that
|
||||
// these casts would not be appropriate for bridging-like conversions.
|
||||
SILValue srcValue = srcTL.emitLoadOfCopy(B, loc, src, IsTake);
|
||||
|
||||
SILType targetValueType = dest->getType().getObjectType();
|
||||
B.createCheckedCastBranch(loc, /*exact*/ false, srcValue, targetValueType,
|
||||
scalarSuccBB, scalarFailBB, TrueCount, FalseCount);
|
||||
|
||||
// Emit the success block.
|
||||
B.setInsertionPoint(scalarSuccBB); {
|
||||
auto &targetTL = B.getModule().Types.getTypeLowering(targetValueType);
|
||||
SILValue succValue = scalarSuccBB->createPhiArgument(
|
||||
targetValueType, ValueOwnershipKind::Owned);
|
||||
if (!shouldTakeOnSuccess(consumption))
|
||||
targetTL.emitCopyValue(B, loc, succValue);
|
||||
targetTL.emitStoreOfCopy(B, loc, succValue, dest, IsInitialization);
|
||||
targetValueType, srcValue.getOwnershipKind());
|
||||
|
||||
switch (consumption) {
|
||||
// On success, we take with both take_always and take_on_success.
|
||||
case CastConsumptionKind::TakeAlways:
|
||||
case CastConsumptionKind::TakeOnSuccess:
|
||||
break;
|
||||
case CastConsumptionKind::CopyOnSuccess: {
|
||||
SILValue originalSuccValue = succValue;
|
||||
succValue = B.emitCopyValueOperation(loc, succValue);
|
||||
B.emitEndBorrowOperation(loc, originalSuccValue);
|
||||
B.emitEndBorrowOperation(loc, srcValue);
|
||||
break;
|
||||
}
|
||||
case CastConsumptionKind::BorrowAlways:
|
||||
llvm_unreachable("should never see a borrow_always here");
|
||||
}
|
||||
|
||||
// And then store the succValue into dest.
|
||||
B.emitStoreValueOperation(loc, succValue, destAddr,
|
||||
StoreOwnershipQualifier::Init);
|
||||
B.createBranch(loc, indirectSuccBB);
|
||||
}
|
||||
|
||||
// Emit the failure block.
|
||||
if (shouldDestroyOnFailure(consumption)) {
|
||||
B.setInsertionPoint(scalarFailBB);
|
||||
srcTL.emitDestroyValue(B, loc, srcValue);
|
||||
B.setInsertionPoint(scalarFailBB);
|
||||
{
|
||||
SILValue failValue = srcValue;
|
||||
|
||||
// If we have ownership, we need to create something for the default
|
||||
// argument. Otherwise, we just use the input argument to the
|
||||
// checked_cast_br.
|
||||
if (B.hasOwnership()) {
|
||||
failValue = scalarFailBB->createPhiArgument(srcValue->getType(),
|
||||
srcValue.getOwnershipKind());
|
||||
}
|
||||
|
||||
switch (consumption) {
|
||||
case CastConsumptionKind::TakeAlways:
|
||||
// We need to destroy the fail value if we have take_always.
|
||||
B.emitDestroyValueOperation(loc, failValue);
|
||||
break;
|
||||
case CastConsumptionKind::TakeOnSuccess:
|
||||
// If we have take_on_success, since we failed, just store the value back
|
||||
// into the src location that we originally took from.
|
||||
B.emitStoreValueOperation(loc, failValue, srcAddr,
|
||||
StoreOwnershipQualifier::Init);
|
||||
break;
|
||||
case CastConsumptionKind::CopyOnSuccess:
|
||||
B.emitEndBorrowOperation(loc, failValue);
|
||||
B.emitEndBorrowOperation(loc, srcValue);
|
||||
break;
|
||||
case CastConsumptionKind::BorrowAlways:
|
||||
llvm_unreachable("borrow_on_success should never appear here");
|
||||
}
|
||||
|
||||
B.createBranch(loc, indirectFailBB);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user