Skip to content

Commit 8679b62

Browse files
authored
Merge pull request #72583 from gottesmm/more-fixes
[region-isolation] A few improvements + If a value is dynamically actor isolated, do not consider it transferred if the transfer statically was to that same actor isolation.
2 parents 60a62db + 6f66849 commit 8679b62

15 files changed

+322
-88
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,7 @@ NOTE(regionbasedisolation_named_stronglytransferred_binding, none,
987987
"%0 used after being passed as a transferring parameter; Later uses could race",
988988
(Identifier))
989989
NOTE(regionbasedisolation_named_isolated_closure_yields_race, none,
990-
"%0 %1 is captured by %2 closure. %2 uses in closure may race against later %3 uses",
990+
"%0 %1 is captured by a %2 closure. %2 uses in closure may race against later %3 uses",
991991
(StringRef, Identifier, ActorIsolation, ActorIsolation))
992992

993993
// Misc Error.

include/swift/SIL/SILFunction.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,9 @@ class SILFunction
347347
/// block indices.
348348
unsigned BlockListChangeIdx = 0;
349349

350+
/// The isolation of this function.
351+
std::optional<ActorIsolation> actorIsolation;
352+
350353
/// The function's bare attribute. Bare means that the function is SIL-only
351354
/// and does not require debug info.
352355
unsigned Bare : 1;
@@ -1367,6 +1370,14 @@ class SILFunction
13671370
return false;
13681371
}
13691372

1373+
void setActorIsolation(ActorIsolation newActorIsolation) {
1374+
actorIsolation = newActorIsolation;
1375+
}
1376+
1377+
std::optional<ActorIsolation> getActorIsolation() const {
1378+
return actorIsolation;
1379+
}
1380+
13701381
//===--------------------------------------------------------------------===//
13711382
// Block List Access
13721383
//===--------------------------------------------------------------------===//

include/swift/SILOptimizer/Analysis/RegionAnalysis.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,13 @@ class regionanalysisimpl::TrackableValue {
286286
bool isTransferringParameter() const;
287287

288288
void print(llvm::raw_ostream &os) const {
289+
os << "TrackableValue. State: ";
290+
valueState.print(os);
291+
os << "\n Rep Value: ";
292+
getRepresentative().print(os);
293+
}
294+
295+
void printVerbose(llvm::raw_ostream &os) const {
289296
os << "TrackableValue. State: ";
290297
valueState.print(os);
291298
os << "\n Rep Value: " << getRepresentative();

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/Basic/FrozenMultiMap.h"
1818
#include "swift/Basic/ImmutablePointerSet.h"
1919
#include "swift/Basic/LLVM.h"
20+
#include "swift/SIL/SILFunction.h"
2021
#include "swift/SIL/SILInstruction.h"
2122
#include "llvm/ADT/SmallVector.h"
2223
#include "llvm/Support/Debug.h"
@@ -204,7 +205,7 @@ class SILIsolationInfo {
204205
return getActorIsolated(actorIsolation);
205206
if (nomDecl->isActor())
206207
return {Kind::Actor, nomDecl};
207-
return {};
208+
return SILIsolationInfo();
208209
}
209210

210211
static SILIsolationInfo getTaskIsolated(SILValue value) {
@@ -756,8 +757,8 @@ struct PartitionOpEvaluator {
756757
// value... emit an error.
757758
if (auto *transferredOperandSet = p.getTransferred(op.getOpArgs()[1])) {
758759
for (auto transferredOperand : transferredOperandSet->data()) {
759-
handleLocalUseAfterTransfer(op, op.getOpArgs()[1],
760-
transferredOperand);
760+
handleLocalUseAfterTransferHelper(op, op.getOpArgs()[1],
761+
transferredOperand);
761762
}
762763
}
763764
p.assignElement(op.getOpArgs()[0], op.getOpArgs()[1]);
@@ -789,6 +790,21 @@ struct PartitionOpEvaluator {
789790
std::tie(transferredRegionIsolation, isClosureCapturedElt) =
790791
getIsolationRegionInfo(transferredRegion, op.getSourceOp());
791792

793+
// Before we do anything, see if our dynamic isolation kind is the same as
794+
// the isolation info for our partition op. If they match, this is not a
795+
// real transfer operation.
796+
//
797+
// DISCUSSION: We couldn't not emit this earlier since we needed the
798+
// dynamic isolation info of our value.
799+
if (transferredRegionIsolation.isActorIsolated()) {
800+
if (auto calleeIsolationInfo =
801+
SILIsolationInfo::get(op.getSourceInst())) {
802+
if (transferredRegionIsolation == calleeIsolationInfo) {
803+
return;
804+
}
805+
}
806+
}
807+
792808
// If we merged anything, we need to handle a transfer
793809
// non-transferrable. We pass in the dynamic isolation region info of our
794810
// region.
@@ -824,14 +840,14 @@ struct PartitionOpEvaluator {
824840
// if attempting to merge a transferred region, handle the failure
825841
if (auto *transferredOperandSet = p.getTransferred(op.getOpArgs()[0])) {
826842
for (auto transferredOperand : transferredOperandSet->data()) {
827-
handleLocalUseAfterTransfer(op, op.getOpArgs()[0],
828-
transferredOperand);
843+
handleLocalUseAfterTransferHelper(op, op.getOpArgs()[0],
844+
transferredOperand);
829845
}
830846
}
831847
if (auto *transferredOperandSet = p.getTransferred(op.getOpArgs()[1])) {
832848
for (auto transferredOperand : transferredOperandSet->data()) {
833-
handleLocalUseAfterTransfer(op, op.getOpArgs()[1],
834-
transferredOperand);
849+
handleLocalUseAfterTransferHelper(op, op.getOpArgs()[1],
850+
transferredOperand);
835851
}
836852
}
837853

@@ -844,8 +860,8 @@ struct PartitionOpEvaluator {
844860
"Require PartitionOp's argument should already be tracked");
845861
if (auto *transferredOperandSet = p.getTransferred(op.getOpArgs()[0])) {
846862
for (auto transferredOperand : transferredOperandSet->data()) {
847-
handleLocalUseAfterTransfer(op, op.getOpArgs()[0],
848-
transferredOperand);
863+
handleLocalUseAfterTransferHelper(op, op.getOpArgs()[0],
864+
transferredOperand);
849865
}
850866
}
851867
return;
@@ -858,6 +874,43 @@ struct PartitionOpEvaluator {
858874
for (auto &o : ops)
859875
apply(o);
860876
}
877+
878+
/// Provides a way for subclasses to disable the error squelching
879+
/// functionality.
880+
///
881+
/// Used by the unittests.
882+
bool shouldTryToSquelchErrors() const {
883+
return asImpl().shouldTryToSquelchErrors();
884+
}
885+
886+
private:
887+
// Private helper that squelches the error if our transfer instruction and our
888+
// use have the same isolation.
889+
void
890+
handleLocalUseAfterTransferHelper(const PartitionOp &op, Element elt,
891+
TransferringOperand *transferringOp) const {
892+
if (shouldTryToSquelchErrors()) {
893+
if (auto isolationInfo = SILIsolationInfo::get(op.getSourceInst())) {
894+
if (isolationInfo.isActorIsolated() &&
895+
isolationInfo == SILIsolationInfo::get(transferringOp->getUser()))
896+
return;
897+
}
898+
899+
// If our instruction does not have any isolation info associated with it,
900+
// it must be nonisolated. See if our function has a matching isolation to
901+
// our transferring operand. If so, we can squelch this.
902+
if (auto functionIsolation =
903+
transferringOp->getUser()->getFunction()->getActorIsolation()) {
904+
if (functionIsolation->isActorIsolated() &&
905+
SILIsolationInfo::getActorIsolated(*functionIsolation) ==
906+
SILIsolationInfo::get(transferringOp->getUser()))
907+
return;
908+
}
909+
}
910+
911+
// Ok, we actually need to emit a call to the callback.
912+
return handleLocalUseAfterTransfer(op, elt, transferringOp);
913+
}
861914
};
862915

863916
/// A base implementation that can be used to default initialize CRTP
@@ -927,6 +980,9 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
927980
/// to access the instruction in the evaluator which creates a problem when
928981
/// since the operand we pass in is a dummy operand.
929982
bool isClosureCaptured(Element elt, Operand *op) const { return false; }
983+
984+
/// By default squelch errors.
985+
bool shouldTryToSquelchErrors() const { return true; }
930986
};
931987

932988
/// A subclass of PartitionOpEvaluatorBaseImpl that doesn't have any special

lib/SILGen/SILGen.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,6 +1217,10 @@ void SILGenModule::preEmitFunction(SILDeclRef constant, SILFunction *F,
12171217
if (F->getLoweredFunctionType()->isPolymorphic())
12181218
F->setGenericEnvironment(Types.getConstantGenericEnvironment(constant));
12191219

1220+
// Set the actor isolation of the function to its innermost decl context.
1221+
F->setActorIsolation(
1222+
getActorIsolationOfContext(constant.getInnermostDeclContext()));
1223+
12201224
// Create a debug scope for the function using astNode as source location.
12211225
F->setDebugScope(new (M) SILDebugScope(Loc, F));
12221226

lib/SILOptimizer/Analysis/RegionAnalysis.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1470,6 +1470,7 @@ class PartitionOpTranslator {
14701470
llvm::SmallVector<Element, 8> nonSendableJoinedIndices;
14711471
llvm::SmallVector<Element, 8> nonSendableSeparateIndices;
14721472
for (SILArgument *arg : functionArguments) {
1473+
// This will decide what the isolation region is.
14731474
if (auto state = tryToTrackValue(arg)) {
14741475
// If we can transfer our parameter, just add it to
14751476
// nonSendableSeparateIndices.
@@ -1485,9 +1486,8 @@ class PartitionOpTranslator {
14851486

14861487
// Otherwise, it is one of our merged parameters. Add it to the never
14871488
// transfer list and to the region join list.
1488-
LLVM_DEBUG(llvm::dbgs() << " %%" << state->getID() << ": " << *arg);
1489-
valueMap.mergeIsolationRegionInfo(
1490-
arg, SILIsolationInfo::getTaskIsolated(arg));
1489+
LLVM_DEBUG(llvm::dbgs() << " %%" << state->getID() << ": ";
1490+
state->print(llvm::dbgs()); llvm::dbgs() << *arg);
14911491
nonSendableJoinedIndices.push_back(state->getID());
14921492
}
14931493
}
@@ -3460,7 +3460,9 @@ void RegionAnalysisValueMap::print(llvm::raw_ostream &os) const {
34603460
}
34613461
std::sort(temp.begin(), temp.end());
34623462
for (auto p : temp) {
3463-
os << "%%" << p.first << ": " << p.second;
3463+
os << "%%" << p.first << ": ";
3464+
auto value = getValueForId(Element(p.first));
3465+
value->print(os);
34643466
}
34653467
#endif
34663468
}

lib/SILOptimizer/Mandatory/TransferNonSendable.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,11 +1021,19 @@ class TransferNonTransferrableDiagnosticEmitter {
10211021
.highlight(getOperand()->getUser()->getLoc().getSourceRange());
10221022
}
10231023

1024-
void emitFunctionArgumentClosure(SourceLoc loc, Type type,
1025-
ApplyIsolationCrossing crossing) {
1026-
diagnoseError(loc, diag::regionbasedisolation_arg_transferred,
1027-
"task-isolated", type, crossing.getCalleeIsolation())
1028-
.highlight(getOperand()->getUser()->getLoc().getSourceRange());
1024+
void emitNamedFunctionArgumentClosure(SILLocation loc, Identifier name,
1025+
ApplyIsolationCrossing crossing) {
1026+
emitNamedOnlyError(loc, name);
1027+
SmallString<64> descriptiveKindStr;
1028+
{
1029+
llvm::raw_svector_ostream os(descriptiveKindStr);
1030+
getIsolationRegionInfo().printForDiagnostics(os);
1031+
}
1032+
diagnoseNote(loc,
1033+
diag::regionbasedisolation_named_isolated_closure_yields_race,
1034+
descriptiveKindStr, name, crossing.getCalleeIsolation(),
1035+
crossing.getCallerIsolation())
1036+
.highlight(loc.getSourceRange());
10291037
}
10301038

10311039
void emitFunctionArgumentApplyStronglyTransferred(SILLocation loc,
@@ -1160,9 +1168,9 @@ bool TransferNonTransferrableDiagnosticInferrer::initForIsolatedPartialApply(
11601168
unsigned opIndex = ApplySite(op->getUser()).getAppliedArgIndex(*op);
11611169
for (auto &p : foundCapturedIsolationCrossing) {
11621170
if (std::get<1>(p) == opIndex) {
1163-
Type type = std::get<0>(p).getDecl()->getInterfaceType();
1164-
diagnosticEmitter.emitFunctionArgumentClosure(std::get<0>(p).getLoc(),
1165-
type, std::get<2>(p));
1171+
auto loc = RegularLocation(std::get<0>(p).getLoc());
1172+
diagnosticEmitter.emitNamedFunctionArgumentClosure(
1173+
loc, std::get<0>(p).getDecl()->getBaseIdentifier(), std::get<2>(p));
11661174
return true;
11671175
}
11681176
}

lib/SILOptimizer/Utils/PartitionUtils.cpp

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,21 @@ static llvm::cl::opt<bool, true> // The parser
4242
//===----------------------------------------------------------------------===//
4343

4444
SILIsolationInfo SILIsolationInfo::get(SILInstruction *inst) {
45-
if (ApplyExpr *apply = inst->getLoc().getAsASTNode<ApplyExpr>())
46-
if (auto crossing = apply->getIsolationCrossing())
47-
return SILIsolationInfo::getActorIsolated(crossing->getCalleeIsolation());
45+
if (ApplyExpr *apply = inst->getLoc().getAsASTNode<ApplyExpr>()) {
46+
if (auto crossing = apply->getIsolationCrossing()) {
47+
if (crossing->getCalleeIsolation().isActorIsolated())
48+
return SILIsolationInfo::getActorIsolated(
49+
crossing->getCalleeIsolation());
50+
}
51+
}
4852

4953
if (auto fas = FullApplySite::isa(inst)) {
50-
if (auto crossing = fas.getIsolationCrossing())
51-
return SILIsolationInfo::getActorIsolated(crossing->getCalleeIsolation());
54+
if (auto crossing = fas.getIsolationCrossing()) {
55+
if (crossing->getCalleeIsolation().isActorIsolated()) {
56+
return SILIsolationInfo::getActorIsolated(
57+
crossing->getCalleeIsolation());
58+
}
59+
}
5260

5361
if (fas.hasSelfArgument()) {
5462
auto &self = fas.getSelfArgumentOperand();
@@ -79,9 +87,18 @@ SILIsolationInfo SILIsolationInfo::get(SILInstruction *inst) {
7987
}
8088

8189
SILIsolationInfo SILIsolationInfo::get(SILFunctionArgument *arg) {
90+
// If we have self and our function is actor isolated, all of our arguments
91+
// should be marked as actor isolated.
8292
if (auto *self = arg->getFunction()->maybeGetSelfArgument()) {
83-
if (auto *nomDecl = self->getType().getNominalOrBoundGenericNominal()) {
84-
return SILIsolationInfo::getActorIsolated(nomDecl);
93+
if (auto functionIsolation = arg->getFunction()->getActorIsolation()) {
94+
if (functionIsolation->isActorIsolated()) {
95+
if (auto *nomDecl = self->getType().getNominalOrBoundGenericNominal()) {
96+
if (auto isolationInfo =
97+
SILIsolationInfo::getActorIsolated(nomDecl)) {
98+
return isolationInfo;
99+
}
100+
}
101+
}
85102
}
86103
}
87104

@@ -171,7 +188,7 @@ bool SILIsolationInfo::operator==(const SILIsolationInfo &other) const {
171188

172189
// Otherwise, try to use the inferred actor decl.
173190
auto *lhsDecl = tryInferActorDecl();
174-
auto *rhsDecl = tryInferActorDecl();
191+
auto *rhsDecl = other.tryInferActorDecl();
175192
if (lhsDecl && rhsDecl)
176193
return lhsDecl == rhsDecl;
177194

0 commit comments

Comments
 (0)