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));
|
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
|
// 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
|
// the value to the passed in closure. After the closure has finished
|
||||||
// executing, automatically insert the end_borrow. The closure can assume that
|
// 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.
|
/// using a scalar cast operation.
|
||||||
void swift::emitIndirectConditionalCastWithScalar(
|
void swift::emitIndirectConditionalCastWithScalar(
|
||||||
SILBuilder &B, ModuleDecl *M, SILLocation loc,
|
SILBuilder &B, ModuleDecl *M, SILLocation loc,
|
||||||
CastConsumptionKind consumption, SILValue src, CanType sourceType,
|
CastConsumptionKind consumption, SILValue srcAddr, CanType sourceType,
|
||||||
SILValue dest, CanType targetType, SILBasicBlock *indirectSuccBB,
|
SILValue destAddr, CanType targetType, SILBasicBlock *indirectSuccBB,
|
||||||
SILBasicBlock *indirectFailBB, ProfileCounter TrueCount,
|
SILBasicBlock *indirectFailBB, ProfileCounter TrueCount,
|
||||||
ProfileCounter FalseCount) {
|
ProfileCounter FalseCount) {
|
||||||
assert(canUseScalarCheckedCastInstructions(B.getModule(),
|
assert(canUseScalarCheckedCastInstructions(B.getModule(),
|
||||||
sourceType, targetType));
|
sourceType, targetType));
|
||||||
|
|
||||||
// We only need a different failure block if the cast consumption
|
// Create our successor and fail blocks.
|
||||||
// requires us to destroy the source value.
|
SILBasicBlock *scalarFailBB = B.splitBlockForFallthrough();
|
||||||
SILBasicBlock *scalarFailBB;
|
|
||||||
if (!shouldDestroyOnFailure(consumption)) {
|
|
||||||
scalarFailBB = indirectFailBB;
|
|
||||||
} else {
|
|
||||||
scalarFailBB = B.splitBlockForFallthrough();
|
|
||||||
}
|
|
||||||
|
|
||||||
// We always need a different success block.
|
|
||||||
SILBasicBlock *scalarSuccBB = 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,
|
B.createCheckedCastBranch(loc, /*exact*/ false, srcValue, targetValueType,
|
||||||
scalarSuccBB, scalarFailBB, TrueCount, FalseCount);
|
scalarSuccBB, scalarFailBB, TrueCount, FalseCount);
|
||||||
|
|
||||||
// Emit the success block.
|
// Emit the success block.
|
||||||
B.setInsertionPoint(scalarSuccBB); {
|
B.setInsertionPoint(scalarSuccBB); {
|
||||||
auto &targetTL = B.getModule().Types.getTypeLowering(targetValueType);
|
|
||||||
SILValue succValue = scalarSuccBB->createPhiArgument(
|
SILValue succValue = scalarSuccBB->createPhiArgument(
|
||||||
targetValueType, ValueOwnershipKind::Owned);
|
targetValueType, srcValue.getOwnershipKind());
|
||||||
if (!shouldTakeOnSuccess(consumption))
|
|
||||||
targetTL.emitCopyValue(B, loc, succValue);
|
switch (consumption) {
|
||||||
targetTL.emitStoreOfCopy(B, loc, succValue, dest, IsInitialization);
|
// 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);
|
B.createBranch(loc, indirectSuccBB);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit the failure block.
|
// Emit the failure block.
|
||||||
if (shouldDestroyOnFailure(consumption)) {
|
|
||||||
B.setInsertionPoint(scalarFailBB);
|
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);
|
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 @fromLiteral : $@convention(thin) (Builtin.Int128, @thin Int64.Type) -> Int64
|
||||||
sil @use_nativeobject : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
sil @use_nativeobject : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
||||||
|
|
||||||
|
class Klass {}
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
// Multiple Inline in a Block Tests //
|
// Multiple Inline in a Block Tests //
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|||||||
@@ -293,3 +293,167 @@ bb0(%0 : $Builtin.NativeObject, %1 : $FakeOptional<Klass>):
|
|||||||
%9999 = tuple()
|
%9999 = tuple()
|
||||||
return %9999 : $()
|
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)
|
init(i: Builtin.Int64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Klass {}
|
||||||
|
|
||||||
sil [transparent] [ossa] @calleeWithGuaranteed : $@convention(thin) (@guaranteed C) -> Builtin.Int64 {
|
sil [transparent] [ossa] @calleeWithGuaranteed : $@convention(thin) (@guaranteed C) -> Builtin.Int64 {
|
||||||
bb(%0 : @guaranteed $C):
|
bb(%0 : @guaranteed $C):
|
||||||
%1 = ref_element_addr %0 : $C, #C.i
|
%1 = ref_element_addr %0 : $C, #C.i
|
||||||
@@ -142,3 +144,173 @@ bb3:
|
|||||||
destroy_value %0 : $Builtin.NativeObject
|
destroy_value %0 : $Builtin.NativeObject
|
||||||
return %13 : $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