Skip to content

Commit 1e4fe6c

Browse files
committed
[region-isolation] Do not transfer @out parameters!
Instead treat them as actual results.
1 parent 5011584 commit 1e4fe6c

File tree

3 files changed

+71
-8
lines changed

3 files changed

+71
-8
lines changed

lib/SILOptimizer/Analysis/RegionAnalysis.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,8 +1434,12 @@ class PartitionOpTranslator {
14341434

14351435
if (auto tryApplyInst = dyn_cast<TryApplyInst>(inst)) {
14361436
foundResults.emplace_back(tryApplyInst->getNormalBB()->getArgument(0));
1437-
if (tryApplyInst->getErrorBB()->getNumArguments() > 0)
1437+
if (tryApplyInst->getErrorBB()->getNumArguments() > 0) {
14381438
foundResults.emplace_back(tryApplyInst->getErrorBB()->getArgument(0));
1439+
}
1440+
for (auto indirectResults : tryApplyInst->getIndirectSILResults()) {
1441+
foundResults.emplace_back(indirectResults);
1442+
}
14391443
return;
14401444
}
14411445

@@ -1800,10 +1804,10 @@ class PartitionOpTranslator {
18001804
};
18011805

18021806
if (applySite.hasSelfArgument()) {
1803-
handleSILOperands(applySite.getOperandsWithoutSelf());
1807+
handleSILOperands(applySite.getOperandsWithoutIndirectResultsOrSelf());
18041808
handleSILSelf(&applySite.getSelfArgumentOperand());
18051809
} else {
1806-
handleSILOperands(applySite->getAllOperands());
1810+
handleSILOperands(applySite.getOperandsWithoutIndirectResults());
18071811
}
18081812

18091813
// non-sendable results can't be returned from cross-isolation calls without

lib/SILOptimizer/Mandatory/TransferNonSendable.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,9 @@ void UseAfterTransferDiagnosticInferrer::initForApply(const Operand *op,
553553
SILInstruction *i = const_cast<SILInstruction *>(op->getUser());
554554
auto fai = FullApplySite::isa(i);
555555

556+
assert(!fai.getArgumentConvention(*op).isIndirectOutParameter() &&
557+
"An indirect out parameter is never transferred");
558+
556559
Expr *foundExpr = nullptr;
557560

558561
// If we have self, then infer it.
@@ -677,6 +680,8 @@ void UseAfterTransferDiagnosticInferrer::init(const Operand *op) {
677680

678681
// Otherwise, see if our operand's instruction is a transferring parameter.
679682
if (auto fas = FullApplySite::isa(nonConstOp->getUser())) {
683+
assert(!fas.getArgumentConvention(*nonConstOp).isIndirectOutParameter() &&
684+
"We should never transfer an indirect out parameter");
680685
if (fas.getArgumentParameterInfo(*nonConstOp)
681686
.hasOption(SILParameterInfo::Transferring)) {
682687
return initForUseOfStronglyTransferredValue(op);
@@ -962,12 +967,13 @@ struct DiagnosticEvaluator final
962967
auto rep = info->getValueMap().getRepresentative(transferredVal);
963968
LLVM_DEBUG(llvm::dbgs()
964969
<< " Emitting Use After Transfer Error!\n"
965-
<< " ID: %%" << transferredVal << "\n"
966-
<< " Rep: " << *rep
970+
<< " Transferring Inst: " << *transferringOp.getUser()
971+
<< " Transferring Op Value: "
972+
<< transferringOp.getOperand()->get()
967973
<< " Require Inst: " << *partitionOp.getSourceInst()
968-
<< " Transferring Op Num: "
969-
<< transferringOp.getOperand()->getOperandNumber() << '\n'
970-
<< " Transferring Inst: " << *transferringOp.getUser());
974+
<< " ID: %%" << transferredVal << "\n"
975+
<< " Rep: " << *rep << " Transferring Op Num: "
976+
<< transferringOp.getOperand()->getOperandNumber() << '\n');
971977
transferOpToRequireInstMultiMap.insert(transferringOp.getOperand(),
972978
partitionOp.getSourceInst());
973979
}

test/Concurrency/transfernonsendable.sil

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ sil @useRawPointer : $@convention(thin) (Builtin.RawPointer) -> ()
6363
sil @initRawPointer : $@convention(thin) () -> Builtin.RawPointer
6464

6565
sil @transferIndirect : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> ()
66+
sil @transferIndirectWithOutResult : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
6667
sil @useIndirect : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
6768
sil @initIndirect : $@convention(thin) <T> () -> @out T
6869
sil @initIndirectTransferring : $@convention(thin) @async <T> () -> @out T
@@ -92,3 +93,55 @@ bb0(%0 : $*{ var NonSendableKlass }):
9293
%9999 = tuple ()
9394
return %9999 : $()
9495
}
96+
97+
// This doesn't error since the @out parameter is not transferred when it is initialized.
98+
//
99+
// DISCUSSION: The frontend prevents us from using such a value. But we
100+
// shouldn't crash on such values.
101+
sil [ossa] @transfer_does_not_transfer_out_parameters_1 : $@convention(thin) @async () -> () {
102+
bb0:
103+
%0 = alloc_stack $NonSendableKlass
104+
%init = function_ref @initIndirect : $@convention(thin) <T> () -> @out T
105+
apply %init<NonSendableKlass>(%0) : $@convention(thin) <T> () -> @out T
106+
107+
%1 = alloc_stack $NonSendableKlass
108+
%f = function_ref @transferIndirectWithOutResult : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
109+
apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %f<NonSendableKlass>(%1, %0) : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
110+
111+
%useIndirect = function_ref @useIndirect : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
112+
apply %useIndirect<NonSendableKlass>(%1) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
113+
114+
destroy_addr %1 : $*NonSendableKlass
115+
dealloc_stack %1 : $*NonSendableKlass
116+
destroy_addr %0 : $*NonSendableKlass
117+
dealloc_stack %0 : $*NonSendableKlass
118+
119+
%9999 = tuple ()
120+
return %9999 : $()
121+
}
122+
123+
sil [ossa] @transfer_does_not_transfer_out_parameters_2 : $@convention(thin) @async () -> () {
124+
bb0:
125+
%0 = alloc_stack $NonSendableKlass
126+
%init = function_ref @initIndirect : $@convention(thin) <T> () -> @out T
127+
apply %init<NonSendableKlass>(%0) : $@convention(thin) <T> () -> @out T
128+
129+
%1 = alloc_stack $NonSendableKlass
130+
%f = function_ref @transferIndirectWithOutResult : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
131+
apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %f<NonSendableKlass>(%1, %0) : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
132+
133+
%f2 = function_ref @transferIndirect : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> ()
134+
apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %f2<NonSendableKlass>(%1) : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> ()
135+
// expected-warning @-1 {{transferring value of non-Sendable type 'NonSendableKlass' from nonisolated context to global actor '<null>'-isolated context}}
136+
%useIndirect = function_ref @useIndirect : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
137+
apply %useIndirect<NonSendableKlass>(%1) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
138+
// expected-note @-1 {{access here could race}}
139+
140+
destroy_addr %1 : $*NonSendableKlass
141+
dealloc_stack %1 : $*NonSendableKlass
142+
destroy_addr %0 : $*NonSendableKlass
143+
dealloc_stack %0 : $*NonSendableKlass
144+
145+
%9999 = tuple ()
146+
return %9999 : $()
147+
}

0 commit comments

Comments
 (0)