Skip to content

Commit 62a03a4

Browse files
committed
[region-isolation] Fix handling of coroutine apply results.
In this part of the code, we are attempting to merge all of the operands into the same region and then assigning all non-Sendable results of the function to that same region. The problem that was occuring here was a thinko due to the control flow of the code here not separating nicely the case of whether or not we had operands or not. Previously this did not matter, since we just used the first result in such a case... but since we changed to assign to the first operand element in some cases, it matters now. To fix this, I split the confused logic into two different easy to follow control paths... one if we have operands and one where we do not have an operand. In the case where we have a first operand, we merge our elements into its region. If we do not have any operands, then we just perform one large region assign fresh. This was not exposed by code that used non-coroutines since in SIL only coroutines today have multiple results. rdar://132767643 (cherry picked from commit 541863d)
1 parent bd6ebcd commit 62a03a4

File tree

3 files changed

+63
-22
lines changed

3 files changed

+63
-22
lines changed

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,19 @@ class PartitionOp {
493493
"Transfer needs a sourceInst");
494494
}
495495

496+
template <typename T>
497+
PartitionOp(PartitionOpKind opKind, T collectionOfIndices,
498+
SILInstruction *sourceInst = nullptr)
499+
: opKind(opKind), opArgs(), source(sourceInst) {
500+
assert(((opKind != PartitionOpKind::Transfer &&
501+
opKind != PartitionOpKind::UndoTransfer) ||
502+
sourceInst) &&
503+
"Transfer needs a sourceInst");
504+
for (Element elt : collectionOfIndices) {
505+
opArgs.push_back(elt);
506+
}
507+
}
508+
496509
PartitionOp(PartitionOpKind opKind, Element arg1, Operand *sourceOperand)
497510
: opKind(opKind), opArgs({arg1}), source(sourceOperand) {
498511
assert(((opKind != PartitionOpKind::Transfer &&
@@ -529,9 +542,10 @@ class PartitionOp {
529542
return PartitionOp(PartitionOpKind::Assign, destElt, srcElt, srcOperand);
530543
}
531544

532-
static PartitionOp AssignFresh(Element tgt,
545+
template <typename T>
546+
static PartitionOp AssignFresh(T collection,
533547
SILInstruction *sourceInst = nullptr) {
534-
return PartitionOp(PartitionOpKind::AssignFresh, tgt, sourceInst);
548+
return PartitionOp(PartitionOpKind::AssignFresh, collection, sourceInst);
535549
}
536550

537551
static PartitionOp Transfer(Element tgt, Operand *transferringOp) {
@@ -1162,12 +1176,18 @@ struct PartitionOpEvaluator {
11621176
p.assignElement(op.getOpArgs()[0], op.getOpArgs()[1]);
11631177
return;
11641178
}
1165-
case PartitionOpKind::AssignFresh:
1166-
assert(op.getOpArgs().size() == 1 &&
1167-
"AssignFresh PartitionOp should be passed 1 argument");
1168-
1169-
p.trackNewElement(op.getOpArgs()[0]);
1179+
case PartitionOpKind::AssignFresh: {
1180+
auto arrayRef = op.getOpArgs();
1181+
1182+
Element front = arrayRef.front();
1183+
p.trackNewElement(front);
1184+
arrayRef = arrayRef.drop_front();
1185+
for (auto x : arrayRef) {
1186+
p.trackNewElement(x);
1187+
p.assignElement(x, front);
1188+
}
11701189
return;
1190+
}
11711191
case PartitionOpKind::Transfer: {
11721192
// NOTE: We purposely do not check here if a transferred value is already
11731193
// transferred. Callers are expected to put a require for that

lib/SILOptimizer/Analysis/RegionAnalysis.cpp

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,8 +1158,16 @@ struct PartitionOpBuilder {
11581158
Element getActorIntroducingRepresentative(SILIsolationInfo actorIsolation);
11591159

11601160
void addAssignFresh(SILValue value) {
1161+
std::array<Element, 1> values = {lookupValueID(value)};
11611162
currentInstPartitionOps.emplace_back(
1162-
PartitionOp::AssignFresh(lookupValueID(value), currentInst));
1163+
PartitionOp::AssignFresh(values, currentInst));
1164+
}
1165+
1166+
void addAssignFresh(ArrayRef<SILValue> values) {
1167+
auto transformedCollection = makeTransformRange(
1168+
values, [&](SILValue value) { return lookupValueID(value); });
1169+
currentInstPartitionOps.emplace_back(
1170+
PartitionOp::AssignFresh(transformedCollection, currentInst));
11631171
}
11641172

11651173
void addAssign(SILValue destValue, Operand *srcOperand) {
@@ -1732,23 +1740,18 @@ class PartitionOpTranslator {
17321740
return;
17331741
}
17341742

1735-
auto assignResultsRef = llvm::ArrayRef(assignResults);
1736-
SILValue front = assignResultsRef.front();
1737-
assignResultsRef = assignResultsRef.drop_front();
1738-
1743+
// If we do not have any non-Sendable srcs, then all of our results get one
1744+
// large fresh region.
17391745
if (assignOperands.empty()) {
1740-
// If no non-sendable srcs, non-sendable tgts get a fresh region.
1741-
builder.addAssignFresh(front);
1742-
} else {
1743-
builder.addAssign(front, assignOperands.front().first);
1746+
builder.addAssignFresh(assignResults);
1747+
return;
17441748
}
17451749

1746-
// Assign all targets to the target region.
1747-
while (assignResultsRef.size()) {
1748-
SILValue next = assignResultsRef.front();
1749-
assignResultsRef = assignResultsRef.drop_front();
1750-
1751-
builder.addAssign(next, assignOperands.front().first);
1750+
// Otherwise, we need to assign all of the results to be in the same region
1751+
// as the operands. Without losing generality, we just use the first
1752+
// non-Sendable one.
1753+
for (auto result : assignResults) {
1754+
builder.addAssign(result, assignOperands.front().first);
17521755
}
17531756
}
17541757

test/Concurrency/transfernonsendable.sil

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ actor MyActor {
9999
var klass: NonSendableKlass { get set }
100100
}
101101

102+
sil @beginApplyMultipleResultCallee : $@yield_once @convention(thin) () -> (@yields @guaranteed NonSendableKlass, @yields @guaranteed NonSendableKlass)
103+
102104
/////////////////
103105
// MARK: Tests //
104106
/////////////////
@@ -396,3 +398,19 @@ bb0:
396398
%9999 = tuple ()
397399
return %9999 : $()
398400
}
401+
402+
// Make sure that we do not crash on this.
403+
//
404+
// We used to crash on this since we would want to assign the region of an
405+
// operand to the results... but we do not have one and have multiple
406+
// results. This doesn't normally happen with most applies since applies do not
407+
// have multiple results, so in such a case, we would just assign fresh and not
408+
// try to do the assignment for the rest of the values.
409+
sil [ossa] @handleNoOperandToAssignToResults : $@convention(thin) () -> () {
410+
bb0:
411+
%0 = function_ref @beginApplyMultipleResultCallee : $@yield_once @convention(thin) () -> (@yields @guaranteed NonSendableKlass, @yields @guaranteed NonSendableKlass)
412+
(%1, %2, %3) = begin_apply %0() : $@yield_once @convention(thin) () -> (@yields @guaranteed NonSendableKlass, @yields @guaranteed NonSendableKlass)
413+
end_apply %3 as $()
414+
%9999 = tuple ()
415+
return %9999 : $()
416+
}

0 commit comments

Comments
 (0)