Skip to content

Commit 0b74399

Browse files
committed
[region-isolation] Add support for unchecked_trivial_bit_cast
NOTE: This required me to stop using swift::getUnderlyingObject from getUnderlyingTrackedObject since when it stripsCasts it looks through unchecked_trivial_bit_cast... but we only want to do that if both the operand and result of the instruction are non-Sendable. To fix this I inlined getUnderlyingObject's impl and removed that part of stripCasts.
1 parent d08359e commit 0b74399

File tree

2 files changed

+120
-3
lines changed

2 files changed

+120
-3
lines changed

lib/SILOptimizer/Mandatory/TransferNonSendable.cpp

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,14 +199,28 @@ static SILValue getUnderlyingTrackedObjectValue(SILValue value) {
199199
while (true) {
200200
SILValue temp = result;
201201

202-
temp = getUnderlyingObject(temp);
202+
temp = stripSinglePredecessorArgs(temp);
203+
temp = stripAddressProjections(temp);
204+
temp = stripIndexingInsts(temp);
205+
temp = lookThroughOwnershipInsts(temp);
203206

204207
if (auto *svi = dyn_cast<SingleValueInstruction>(temp)) {
205208
if (isa<ExplicitCopyValueInst, CopyableToMoveOnlyWrapperValueInst,
206209
MoveOnlyWrapperToCopyableValueInst,
207-
MoveOnlyWrapperToCopyableBoxInst>(svi)) {
210+
MoveOnlyWrapperToCopyableBoxInst, BeginAccessInst,
211+
MarkDependenceInst>(svi) ||
212+
isIdentityPreservingRefCast(svi)) {
208213
temp = svi->getOperand(0);
209214
}
215+
216+
// If we have a cast and our operand and result are non-Sendable, treat it
217+
// as a look through.
218+
if (isa<UncheckedTrivialBitCastInst>(svi)) {
219+
if (isNonSendableType(svi->getType(), fn) &&
220+
isNonSendableType(svi->getOperand(0)->getType(), fn)) {
221+
temp = svi->getOperand(0);
222+
}
223+
}
210224
}
211225

212226
if (auto *r = dyn_cast<RefToRawPointerInst>(temp)) {
@@ -2467,7 +2481,6 @@ CONSTANT_TRANSLATION(DeallocExistentialBoxInst, Ignored)
24672481
// Unhandled Instructions
24682482
//
24692483

2470-
CONSTANT_TRANSLATION(UncheckedTrivialBitCastInst, Unhandled)
24712484
CONSTANT_TRANSLATION(UncheckedBitwiseCastInst, Unhandled)
24722485
CONSTANT_TRANSLATION(UncheckedValueCastInst, Unhandled)
24732486
CONSTANT_TRANSLATION(RefToUnownedInst, Unhandled)
@@ -2640,6 +2653,34 @@ PartitionOpTranslator::visitRefToRawPointerInst(RefToRawPointerInst *r) {
26402653
return TranslationSemantics::AssignFresh;
26412654
}
26422655

2656+
TranslationSemantics PartitionOpTranslator::visitUncheckedTrivialBitCastInst(
2657+
UncheckedTrivialBitCastInst *cast) {
2658+
bool isOperandNonSendable = isNonSendableType(cast->getOperand()->getType());
2659+
bool isResultNonSendable = isNonSendableType(cast->getType());
2660+
2661+
// If our operand is non sendable...
2662+
if (isOperandNonSendable) {
2663+
// ... and our result is non-Sendable, look through.
2664+
if (isResultNonSendable) {
2665+
return TranslationSemantics::LookThrough;
2666+
}
2667+
2668+
// Otherwise, if our result is Sendable, just treat this instruction as a
2669+
// require of the operand. It would be undefined behavior for the user to
2670+
// convert something from non-Sendable to Sendable if it was not actually
2671+
// Sendable behind the scenes.
2672+
return TranslationSemantics::Require;
2673+
}
2674+
2675+
// If our operand is sendable and our result is non-Sendable, treat this as
2676+
// assign fresh.
2677+
if (isResultNonSendable)
2678+
return TranslationSemantics::AssignFresh;
2679+
2680+
// Otherwise, both our operand and result are sendable, so just return ignore.
2681+
return TranslationSemantics::Ignored;
2682+
}
2683+
26432684
TranslationSemantics
26442685
PartitionOpTranslator::visitMarkDependenceInst(MarkDependenceInst *mdi) {
26452686
translateSILAssign(mdi, mdi->getValue());

test/Concurrency/transfernonsendable_instruction_matching.sil

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,3 +580,79 @@ bb0:
580580
%9999 = tuple ()
581581
return %9999 : $()
582582
}
583+
584+
sil [ossa] @unchecked_trivial_bitcast_test_nonsendable_to_nonsendable : $@convention(thin) @async () -> () {
585+
bb0:
586+
%constructFn = function_ref @constructNonSendableKlass : $@convention(thin) () -> @owned NonSendableKlass
587+
%value = apply %constructFn() : $@convention(thin) () -> @owned NonSendableKlass
588+
589+
%rawPointer = unchecked_trivial_bit_cast %value : $NonSendableKlass to $Builtin.RawPointer
590+
591+
%transferRawPointer = function_ref @transferRawPointer : $@convention(thin) @async (Builtin.RawPointer) -> ()
592+
apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %transferRawPointer(%rawPointer) : $@convention(thin) @async (Builtin.RawPointer) -> ()
593+
// expected-warning @-1 {{passing argument of non-sendable type 'Builtin.RawPointer' from nonisolated context to global actor '<null>'-isolated context at this call site could yield a race with accesses later in this function}}
594+
595+
fix_lifetime %value : $NonSendableKlass
596+
// expected-note @-1 {{access here could race}}
597+
598+
destroy_value %value : $NonSendableKlass
599+
%9999 = tuple ()
600+
return %9999 : $()
601+
}
602+
603+
sil [ossa] @unchecked_trivial_bitcast_test_sendable_to_nonsendable : $@convention(thin) @async () -> () {
604+
bb0:
605+
%constructFn = function_ref @constructSendableKlass : $@convention(thin) () -> @owned SendableKlass
606+
%value = apply %constructFn() : $@convention(thin) () -> @owned SendableKlass
607+
608+
%rawPointer = unchecked_trivial_bit_cast %value : $SendableKlass to $Builtin.RawPointer
609+
610+
%transferRawPointer = function_ref @transferRawPointer : $@convention(thin) @async (Builtin.RawPointer) -> ()
611+
apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %transferRawPointer(%rawPointer) : $@convention(thin) @async (Builtin.RawPointer) -> ()
612+
// expected-warning @-1 {{passing argument of non-sendable type 'Builtin.RawPointer' from nonisolated context to global actor '<null>'-isolated context at this call site could yield a race with accesses later in this function}}
613+
614+
fix_lifetime %value : $SendableKlass
615+
616+
apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %transferRawPointer(%rawPointer) : $@convention(thin) @async (Builtin.RawPointer) -> ()
617+
// expected-warning @-1 {{passing argument of non-sendable type 'Builtin.RawPointer' from nonisolated context to global actor '<null>'-isolated context at this call site could yield a race with accesses later in this function}}
618+
// expected-note @-2 {{access here could race}}
619+
620+
fix_lifetime %rawPointer : $Builtin.RawPointer
621+
// expected-note @-1 {{access here could race}}
622+
623+
destroy_value %value : $SendableKlass
624+
%9999 = tuple ()
625+
return %9999 : $()
626+
}
627+
628+
sil [ossa] @unchecked_trivial_bitcast_test_nonsendable_to_sendable : $@convention(thin) @async () -> () {
629+
bb0:
630+
%constructFn = function_ref @constructNonSendableKlass : $@convention(thin) () -> @owned NonSendableKlass
631+
%value = apply %constructFn() : $@convention(thin) () -> @owned NonSendableKlass
632+
633+
%transferNonSendableKlass = function_ref @transferNonSendableKlass : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
634+
apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %transferNonSendableKlass(%value) : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
635+
// expected-warning @-1 {{passing argument of non-sendable type 'NonSendableKlass' from nonisolated context to global actor '<null>'-isolated context at this call site could yield a race with accesses later in this function}}
636+
637+
%word = unchecked_trivial_bit_cast %value : $NonSendableKlass to $Builtin.Word
638+
// expected-note @-1 {{access here could race}}
639+
640+
destroy_value %value : $NonSendableKlass
641+
%9999 = tuple ()
642+
return %9999 : $()
643+
}
644+
645+
sil [ossa] @unchecked_trivial_bitcast_test_sendable_to_sendable : $@convention(thin) @async () -> () {
646+
bb0:
647+
%constructFn = function_ref @constructSendableKlass : $@convention(thin) () -> @owned SendableKlass
648+
%value = apply %constructFn() : $@convention(thin) () -> @owned SendableKlass
649+
650+
%transferSendableKlass = function_ref @transferSendableKlass : $@convention(thin) @async (@guaranteed SendableKlass) -> ()
651+
apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %transferSendableKlass(%value) : $@convention(thin) @async (@guaranteed SendableKlass) -> ()
652+
653+
%word = unchecked_trivial_bit_cast %value : $SendableKlass to $Builtin.Word
654+
655+
destroy_value %value : $SendableKlass
656+
%9999 = tuple ()
657+
return %9999 : $()
658+
}

0 commit comments

Comments
 (0)