Skip to content

Commit 541863d

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
1 parent c1ddeb2 commit 541863d

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
@@ -1159,8 +1159,16 @@ struct PartitionOpBuilder {
11591159
Element getActorIntroducingRepresentative(SILIsolationInfo actorIsolation);
11601160

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

11661174
void addAssign(SILValue destValue, Operand *srcOperand) {
@@ -1733,23 +1741,18 @@ class PartitionOpTranslator {
17331741
return;
17341742
}
17351743

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

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

test/Concurrency/transfernonsendable.sil

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

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

0 commit comments

Comments
 (0)