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:
@@ -716,6 +716,27 @@ public:
|
||||
BeginBorrowInst(getSILDebugLocation(Loc), LV));
|
||||
}
|
||||
|
||||
SILValue emitLoadBorrowOperation(SILLocation loc, SILValue v) {
|
||||
if (!hasOwnership()) {
|
||||
return emitLoadValueOperation(loc, v,
|
||||
LoadOwnershipQualifier::Unqualified);
|
||||
}
|
||||
return createLoadBorrow(loc, v);
|
||||
}
|
||||
|
||||
SILValue emitBeginBorrowOperation(SILLocation loc, SILValue v) {
|
||||
if (!hasOwnership() ||
|
||||
v.getOwnershipKind().isCompatibleWith(ValueOwnershipKind::Guaranteed))
|
||||
return v;
|
||||
return createBeginBorrow(loc, v);
|
||||
}
|
||||
|
||||
void emitEndBorrowOperation(SILLocation loc, SILValue v) {
|
||||
if (!hasOwnership())
|
||||
return;
|
||||
createEndBorrow(loc, v);
|
||||
}
|
||||
|
||||
// Pass in an address or value, perform a begin_borrow/load_borrow and pass
|
||||
// the value to the passed in closure. After the closure has finished
|
||||
// executing, automatically insert the end_borrow. The closure can assume that
|
||||
|
||||
@@ -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);
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ sil @partial_apply_user : $@convention(thin) (@owned @callee_owned (@owned Built
|
||||
sil @fromLiteral : $@convention(thin) (Builtin.Int128, @thin Int64.Type) -> Int64
|
||||
sil @use_nativeobject : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
||||
|
||||
class Klass {}
|
||||
|
||||
//////////////////////////////////////
|
||||
// Multiple Inline in a Block Tests //
|
||||
//////////////////////////////////////
|
||||
|
||||
@@ -293,3 +293,167 @@ bb0(%0 : $Builtin.NativeObject, %1 : $FakeOptional<Klass>):
|
||||
%9999 = tuple()
|
||||
return %9999 : $()
|
||||
}
|
||||
|
||||
sil [transparent] [ossa] @term_ossa_checked_cast_addr_br_takealways_callee : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
bb0(%0 : @owned $Builtin.NativeObject):
|
||||
%1 = alloc_stack $Builtin.NativeObject
|
||||
%2 = alloc_stack $Klass
|
||||
store %0 to [init] %1 : $*Builtin.NativeObject
|
||||
checked_cast_addr_br take_always Builtin.NativeObject in %1 : $*Builtin.NativeObject to Klass in %2 : $*Klass, bb1, bb2
|
||||
|
||||
bb1:
|
||||
destroy_addr %2 : $*Klass
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
br bb3
|
||||
|
||||
bb3:
|
||||
dealloc_stack %2 : $*Klass
|
||||
dealloc_stack %1 : $*Builtin.NativeObject
|
||||
%9999 = tuple()
|
||||
return %9999 : $()
|
||||
}
|
||||
|
||||
|
||||
// CHECK-LABEL: sil @term_nonossa_checked_cast_addr_br_takealways_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
// CHECK: bb0([[ARG:%.*]] :
|
||||
// CHECK-NEXT: strong_retain [[ARG]]
|
||||
// CHECK-NEXT: [[SRC_ADDR:%.*]] = alloc_stack $Builtin.NativeObject
|
||||
// CHECK-NEXT: [[DEST_ADDR:%.*]] = alloc_stack $Klass
|
||||
// CHECK-NEXT: store [[ARG]] to [[SRC_ADDR]]
|
||||
// CHECK-NEXT: [[RELOADED_ARG:%.*]] = load [[SRC_ADDR]]
|
||||
// CHECK-NEXT: checked_cast_br [[RELOADED_ARG]] : $Builtin.NativeObject to $Klass, [[SUCCESS_BB:bb[0-9]+]], [[FAILURE_BB:bb[0-9]+]]
|
||||
//
|
||||
// ==> On success, we store the value into dest. The destroy is not from the
|
||||
// ==> optimizer, but from the code.
|
||||
// CHECK: [[SUCCESS_BB]]([[CAST_VALUE:%.*]] :
|
||||
// CHECK-NEXT: store [[CAST_VALUE]] to [[DEST_ADDR]]
|
||||
// CHECK-NEXT: destroy_addr [[DEST_ADDR]]
|
||||
// CHECK-NEXT: br [[CONT_BB:bb[0-9]+]]
|
||||
//
|
||||
// ==> take_always implies we destroy in failure
|
||||
// CHECK: [[FAILURE_BB]]:
|
||||
// CHECK-NEXT: strong_release [[RELOADED_ARG]]
|
||||
// CHECK-NEXT: br [[CONT_BB]]
|
||||
//
|
||||
// CHECK: [[CONT_BB]]:
|
||||
// CHECK: strong_release [[ARG]]
|
||||
// CHECK: } // end sil function 'term_nonossa_checked_cast_addr_br_takealways_caller'
|
||||
sil @term_nonossa_checked_cast_addr_br_takealways_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
bb0(%0 : $Builtin.NativeObject):
|
||||
%3 = function_ref @term_ossa_checked_cast_addr_br_takealways_callee : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
||||
strong_retain %0 : $Builtin.NativeObject
|
||||
apply %3(%0) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
||||
strong_release %0 : $Builtin.NativeObject
|
||||
%9999 = tuple()
|
||||
return %9999 : $()
|
||||
}
|
||||
|
||||
sil [transparent] [ossa] @term_ossa_checked_cast_addr_br_takeonsuccess_callee : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
bb0(%0 : @owned $Builtin.NativeObject):
|
||||
%1 = alloc_stack $Builtin.NativeObject
|
||||
%2 = alloc_stack $Klass
|
||||
store %0 to [init] %1 : $*Builtin.NativeObject
|
||||
checked_cast_addr_br take_on_success Builtin.NativeObject in %1 : $*Builtin.NativeObject to Klass in %2 : $*Klass, bb1, bb2
|
||||
|
||||
bb1:
|
||||
destroy_addr %2 : $*Klass
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
destroy_addr %1 : $*Builtin.NativeObject
|
||||
br bb3
|
||||
|
||||
bb3:
|
||||
dealloc_stack %2 : $*Klass
|
||||
dealloc_stack %1 : $*Builtin.NativeObject
|
||||
%9999 = tuple()
|
||||
return %9999 : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil @term_nonossa_checked_cast_addr_br_takeonsuccess_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
// CHECK: bb0([[ARG:%.*]] :
|
||||
// CHECK-NEXT: strong_retain [[ARG]]
|
||||
// CHECK-NEXT: [[SRC_ADDR:%.*]] = alloc_stack $Builtin.NativeObject
|
||||
// CHECK-NEXT: [[DEST_ADDR:%.*]] = alloc_stack $Klass
|
||||
// CHECK-NEXT: store [[ARG]] to [[SRC_ADDR]]
|
||||
// CHECK-NEXT: [[RELOADED_ARG:%.*]] = load [[SRC_ADDR]]
|
||||
// CHECK-NEXT: checked_cast_br [[RELOADED_ARG]] : $Builtin.NativeObject to $Klass, [[SUCCESS_BB:bb[0-9]+]], [[FAILURE_BB:bb[0-9]+]]
|
||||
//
|
||||
// CHECK: [[SUCCESS_BB]]([[CAST_VALUE:%.*]] :
|
||||
// ==> On success, we store into dest and destroy dest.
|
||||
// CHECK-NEXT: store [[CAST_VALUE]] to [[DEST_ADDR]]
|
||||
// CHECK-NEXT: destroy_addr [[DEST_ADDR]]
|
||||
// CHECK-NEXT: br [[CONT_BB:bb[0-9]+]]
|
||||
//
|
||||
// ==> Since we are doing a take on success and we failed... store the original
|
||||
// ==> value back into the memory slot.
|
||||
// CHECK: [[FAILURE_BB]]:
|
||||
// CHECK-NEXT: store [[RELOADED_ARG]] to [[SRC_ADDR]]
|
||||
// CHECK-NEXT: destroy_addr [[SRC_ADDR]]
|
||||
// CHECK-NEXT: br [[CONT_BB]]
|
||||
// CHECK: } // end sil function 'term_nonossa_checked_cast_addr_br_takeonsuccess_caller'
|
||||
sil @term_nonossa_checked_cast_addr_br_takeonsuccess_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
bb0(%0 : $Builtin.NativeObject):
|
||||
%2 = function_ref @term_ossa_checked_cast_addr_br_takeonsuccess_callee : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
||||
strong_retain %0 : $Builtin.NativeObject
|
||||
apply %2(%0) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
||||
strong_release %0 : $Builtin.NativeObject
|
||||
%9999 = tuple()
|
||||
return %9999 : $()
|
||||
}
|
||||
|
||||
sil [transparent] [ossa] @term_ossa_checked_cast_addr_br_copyonsuccess_callee : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
bb0(%0 : @owned $Builtin.NativeObject):
|
||||
%1 = alloc_stack $Builtin.NativeObject
|
||||
%2 = alloc_stack $Klass
|
||||
store %0 to [init] %1 : $*Builtin.NativeObject
|
||||
checked_cast_addr_br copy_on_success Builtin.NativeObject in %1 : $*Builtin.NativeObject to Klass in %2 : $*Klass, bb1, bb2
|
||||
|
||||
bb1:
|
||||
destroy_addr %2 : $*Klass
|
||||
destroy_addr %1 : $*Builtin.NativeObject
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
destroy_addr %1 : $*Builtin.NativeObject
|
||||
br bb3
|
||||
|
||||
bb3:
|
||||
dealloc_stack %2 : $*Klass
|
||||
dealloc_stack %1 : $*Builtin.NativeObject
|
||||
%9999 = tuple()
|
||||
return %9999 : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil @term_nonossa_checked_cast_addr_br_copyonsuccess_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
// CHECK: bb0([[ARG:%.*]] :
|
||||
// CHECK-NEXT: strong_retain [[ARG]]
|
||||
// CHECK-NEXT: [[SRC_ADDR:%.*]] = alloc_stack $Builtin.NativeObject
|
||||
// CHECK-NEXT: [[DEST_ADDR:%.*]] = alloc_stack $Klass
|
||||
// CHECK-NEXT: store [[ARG]] to [[SRC_ADDR]]
|
||||
// CHECK-NEXT: [[RELOADED_ARG:%.*]] = load [[SRC_ADDR]]
|
||||
// CHECK-NEXT: checked_cast_br [[RELOADED_ARG]] : $Builtin.NativeObject to $Klass, [[SUCCESS_BB:bb[0-9]+]], [[FAILURE_BB:bb[0-9]+]]
|
||||
//
|
||||
// CHECK: [[SUCCESS_BB]]([[CAST_VALUE:%.*]] :
|
||||
// CHECK-NEXT: strong_retain [[CAST_VALUE]]
|
||||
// CHECK-NEXT: store [[CAST_VALUE]] to [[DEST_ADDR]]
|
||||
// CHECK-NEXT: destroy_addr [[DEST_ADDR]]
|
||||
// CHECK-NEXT: destroy_addr [[SRC_ADDR]]
|
||||
// CHECK-NEXT: br [[CONT_BB:bb[0-9]+]]
|
||||
//
|
||||
// CHECK: [[FAILURE_BB]]:
|
||||
// CHECK-NEXT: destroy_addr [[SRC_ADDR]]
|
||||
// CHECK-NEXT: br [[CONT_BB]]
|
||||
//
|
||||
// CHECK: } // end sil function 'term_nonossa_checked_cast_addr_br_copyonsuccess_caller'
|
||||
sil @term_nonossa_checked_cast_addr_br_copyonsuccess_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
bb0(%0 : $Builtin.NativeObject):
|
||||
%1 = function_ref @term_ossa_checked_cast_addr_br_copyonsuccess_callee : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
||||
strong_retain %0 : $Builtin.NativeObject
|
||||
apply %1(%0) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
||||
strong_release %0 : $Builtin.NativeObject
|
||||
%9999 = tuple()
|
||||
return %9999 : $()
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ class C {
|
||||
init(i: Builtin.Int64)
|
||||
}
|
||||
|
||||
class Klass {}
|
||||
|
||||
sil [transparent] [ossa] @calleeWithGuaranteed : $@convention(thin) (@guaranteed C) -> Builtin.Int64 {
|
||||
bb(%0 : @guaranteed $C):
|
||||
%1 = ref_element_addr %0 : $C, #C.i
|
||||
@@ -142,3 +144,173 @@ bb3:
|
||||
destroy_value %0 : $Builtin.NativeObject
|
||||
return %13 : $Builtin.NativeObject
|
||||
}
|
||||
|
||||
|
||||
sil [transparent] [ossa] @term_ossa_checked_cast_addr_br_takealways_callee : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
bb0(%0 : @owned $Builtin.NativeObject):
|
||||
%1 = alloc_stack $Builtin.NativeObject
|
||||
%2 = alloc_stack $Klass
|
||||
store %0 to [init] %1 : $*Builtin.NativeObject
|
||||
checked_cast_addr_br take_always Builtin.NativeObject in %1 : $*Builtin.NativeObject to Klass in %2 : $*Klass, bb1, bb2
|
||||
|
||||
bb1:
|
||||
destroy_addr %2 : $*Klass
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
br bb3
|
||||
|
||||
bb3:
|
||||
dealloc_stack %2 : $*Klass
|
||||
dealloc_stack %1 : $*Builtin.NativeObject
|
||||
%9999 = tuple()
|
||||
return %9999 : $()
|
||||
}
|
||||
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @term_nonossa_checked_cast_addr_br_takealways_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
// CHECK: bb0([[ARG:%.*]] :
|
||||
// CHECK-NEXT: [[ARG_COPY:%.*]] = copy_value [[ARG]]
|
||||
// CHECK-NEXT: [[SRC_ADDR:%.*]] = alloc_stack $Builtin.NativeObject
|
||||
// CHECK-NEXT: [[DEST_ADDR:%.*]] = alloc_stack $Klass
|
||||
// CHECK-NEXT: store [[ARG_COPY]] to [init] [[SRC_ADDR]]
|
||||
// CHECK-NEXT: [[RELOADED_ARG:%.*]] = load [take] [[SRC_ADDR]]
|
||||
// CHECK-NEXT: checked_cast_br [[RELOADED_ARG]] : $Builtin.NativeObject to $Klass, [[SUCCESS_BB:bb[0-9]+]], [[FAILURE_BB:bb[0-9]+]]
|
||||
//
|
||||
// ==> On success, we store the value into dest. The destroy is not from the
|
||||
// ==> optimizer, but from the code.
|
||||
// CHECK: [[SUCCESS_BB]]([[CAST_VALUE:%.*]] :
|
||||
// CHECK-NEXT: store [[CAST_VALUE]] to [init] [[DEST_ADDR]]
|
||||
// CHECK-NEXT: destroy_addr [[DEST_ADDR]]
|
||||
// CHECK-NEXT: br [[CONT_BB:bb[0-9]+]]
|
||||
//
|
||||
// ==> take_always implies we destroy in failure
|
||||
// CHECK: [[FAILURE_BB]]([[FAILURE_ARG:%.*]] :
|
||||
// CHECK-NEXT: destroy_value [[FAILURE_ARG]]
|
||||
// CHECK-NEXT: br [[CONT_BB]]
|
||||
//
|
||||
// CHECK: [[CONT_BB]]:
|
||||
// CHECK: destroy_value [[ARG]]
|
||||
// CHECK: } // end sil function 'term_nonossa_checked_cast_addr_br_takealways_caller'
|
||||
sil [ossa] @term_nonossa_checked_cast_addr_br_takealways_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
bb0(%0 : @owned $Builtin.NativeObject):
|
||||
%3 = function_ref @term_ossa_checked_cast_addr_br_takealways_callee : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
||||
%1 = copy_value %0 : $Builtin.NativeObject
|
||||
apply %3(%1) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
||||
destroy_value %0 : $Builtin.NativeObject
|
||||
%9999 = tuple()
|
||||
return %9999 : $()
|
||||
}
|
||||
|
||||
sil [transparent] [ossa] @term_ossa_checked_cast_addr_br_takeonsuccess_callee : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
bb0(%0 : @owned $Builtin.NativeObject):
|
||||
%1 = alloc_stack $Builtin.NativeObject
|
||||
%2 = alloc_stack $Klass
|
||||
store %0 to [init] %1 : $*Builtin.NativeObject
|
||||
checked_cast_addr_br take_on_success Builtin.NativeObject in %1 : $*Builtin.NativeObject to Klass in %2 : $*Klass, bb1, bb2
|
||||
|
||||
bb1:
|
||||
destroy_addr %2 : $*Klass
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
destroy_addr %1 : $*Builtin.NativeObject
|
||||
br bb3
|
||||
|
||||
bb3:
|
||||
dealloc_stack %2 : $*Klass
|
||||
dealloc_stack %1 : $*Builtin.NativeObject
|
||||
%9999 = tuple()
|
||||
return %9999 : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @checked_cast_addr_br_takeonsuccess_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
// CHECK: bb0([[ARG:%.*]] :
|
||||
// CHECK-NEXT: [[ARG_COPY:%.*]] = copy_value [[ARG]]
|
||||
// CHECK-NEXT: [[SRC_ADDR:%.*]] = alloc_stack $Builtin.NativeObject
|
||||
// CHECK-NEXT: [[DEST_ADDR:%.*]] = alloc_stack $Klass
|
||||
// CHECK-NEXT: store [[ARG_COPY]] to [init] [[SRC_ADDR]]
|
||||
// CHECK-NEXT: [[RELOADED_ARG:%.*]] = load [take] [[SRC_ADDR]]
|
||||
// CHECK-NEXT: checked_cast_br [[RELOADED_ARG]] : $Builtin.NativeObject to $Klass, [[SUCCESS_BB:bb[0-9]+]], [[FAILURE_BB:bb[0-9]+]]
|
||||
//
|
||||
// CHECK: [[SUCCESS_BB]]([[CAST_VALUE:%.*]] :
|
||||
// ==> On success, we store into dest and destroy dest.
|
||||
// CHECK-NEXT: store [[CAST_VALUE]] to [init] [[DEST_ADDR]]
|
||||
// CHECK-NEXT: destroy_addr [[DEST_ADDR]]
|
||||
// CHECK-NEXT: br [[CONT_BB:bb[0-9]+]]
|
||||
//
|
||||
// ==> Since we are doing a take on success and we failed... store the original
|
||||
// ==> value back into the memory slot.
|
||||
// CHECK: [[FAILURE_BB]]([[FAIL_ARG:%.*]] :
|
||||
// CHECK-NEXT: store [[FAIL_ARG]] to [init] [[SRC_ADDR]]
|
||||
// CHECK-NEXT: destroy_addr [[SRC_ADDR]]
|
||||
// CHECK-NEXT: br [[CONT_BB]]
|
||||
//
|
||||
// CHECK: } // end sil function 'checked_cast_addr_br_takeonsuccess_caller'
|
||||
sil [ossa] @checked_cast_addr_br_takeonsuccess_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
bb0(%0 : @owned $Builtin.NativeObject):
|
||||
%2 = function_ref @term_ossa_checked_cast_addr_br_takeonsuccess_callee : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
||||
%1 = copy_value %0 : $Builtin.NativeObject
|
||||
apply %2(%1) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
||||
destroy_value %0 : $Builtin.NativeObject
|
||||
%9999 = tuple()
|
||||
return %9999 : $()
|
||||
}
|
||||
|
||||
sil [transparent] [ossa] @term_ossa_checked_cast_addr_br_copyonsuccess_callee : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
bb0(%0 : @owned $Builtin.NativeObject):
|
||||
%1 = alloc_stack $Builtin.NativeObject
|
||||
%2 = alloc_stack $Klass
|
||||
store %0 to [init] %1 : $*Builtin.NativeObject
|
||||
checked_cast_addr_br copy_on_success Builtin.NativeObject in %1 : $*Builtin.NativeObject to Klass in %2 : $*Klass, bb1, bb2
|
||||
|
||||
bb1:
|
||||
destroy_addr %2 : $*Klass
|
||||
destroy_addr %1 : $*Builtin.NativeObject
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
destroy_addr %1 : $*Builtin.NativeObject
|
||||
br bb3
|
||||
|
||||
bb3:
|
||||
dealloc_stack %2 : $*Klass
|
||||
dealloc_stack %1 : $*Builtin.NativeObject
|
||||
%9999 = tuple()
|
||||
return %9999 : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @checked_cast_addr_br_copyonsuccess_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
// CHECK: bb0([[ARG:%.*]] :
|
||||
// CHECK-NEXT: [[ARG_COPY:%.*]] = copy_value [[ARG]]
|
||||
// CHECK-NEXT: [[SRC_ADDR:%.*]] = alloc_stack $Builtin.NativeObject
|
||||
// CHECK-NEXT: [[DEST_ADDR:%.*]] = alloc_stack $Klass
|
||||
// CHECK-NEXT: store [[ARG_COPY]] to [init] [[SRC_ADDR]]
|
||||
// CHECK-NEXT: [[RELOADED_ARG:%.*]] = load_borrow [[SRC_ADDR]]
|
||||
// CHECK-NEXT: checked_cast_br [[RELOADED_ARG]] : $Builtin.NativeObject to $Klass, [[SUCCESS_BB:bb[0-9]+]], [[FAILURE_BB:bb[0-9]+]]
|
||||
//
|
||||
// CHECK: [[SUCCESS_BB]]([[CAST_VALUE:%.*]] : @guaranteed
|
||||
// CHECK-NEXT: [[CAST_VALUE_COPY:%.*]] = copy_value [[CAST_VALUE]]
|
||||
// CHECK-NEXT: end_borrow [[CAST_VALUE]]
|
||||
// CHECK-NEXT: end_borrow [[RELOADED_ARG]]
|
||||
// CHECK-NEXT: store [[CAST_VALUE_COPY]] to [init] [[DEST_ADDR]]
|
||||
// CHECK-NEXT: destroy_addr [[DEST_ADDR]]
|
||||
// CHECK-NEXT: destroy_addr [[SRC_ADDR]]
|
||||
// CHECK-NEXT: br [[CONT_BB:bb[0-9]+]]
|
||||
//
|
||||
// CHECK: [[FAILURE_BB]]([[FAILURE_BORROWED_ARG:%.*]] :
|
||||
// CHECK-NEXT: end_borrow [[FAILURE_BORROWED_ARG]]
|
||||
// CHECK-NEXT: end_borrow [[RELOADED_ARG]]
|
||||
// CHECK-NEXT: destroy_addr [[SRC_ADDR]]
|
||||
// CHECK-NEXT: br [[CONT_BB]]
|
||||
//
|
||||
// CHECK: } // end sil function 'checked_cast_addr_br_copyonsuccess_caller'
|
||||
sil [ossa] @checked_cast_addr_br_copyonsuccess_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
|
||||
bb0(%0 : @owned $Builtin.NativeObject):
|
||||
%1 = function_ref @term_ossa_checked_cast_addr_br_copyonsuccess_callee : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
||||
%2 = copy_value %0 : $Builtin.NativeObject
|
||||
apply %1(%2) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
|
||||
destroy_value %0 : $Builtin.NativeObject
|
||||
%9999 = tuple()
|
||||
return %9999 : $()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user