@@ -224,6 +224,7 @@ class SILIsolationInfo {
224224};
225225
226226class Partition ;
227+ class TransferringOperandToStateMap ;
227228
228229// / A persistent data structure that is used to "rewind" partition history so
229230// / that we can discover when values become part of the same region.
@@ -245,6 +246,7 @@ class IsolationHistory {
245246
246247 // TODO: This shouldn't need to be a friend.
247248 friend class Partition ;
249+ friend TransferringOperandToStateMap;
248250
249251 // / First node in the immutable linked list.
250252 Node *head = nullptr ;
@@ -298,6 +300,11 @@ class IsolationHistory {
298300 // / Push that \p other should be merged into this region.
299301 void pushCFGHistoryJoin (Node *otherNode);
300302
303+ // / Push the top node of \p history as a CFG history join.
304+ void pushCFGHistoryJoin (IsolationHistory history) {
305+ return pushCFGHistoryJoin (history.getHead ());
306+ }
307+
301308 Node *pop ();
302309};
303310
@@ -457,10 +464,7 @@ class IsolationHistory::Factory {
457464 IsolationHistory get () { return IsolationHistory (this ); }
458465};
459466
460- class TransferringOperand {
461- using ValueType = llvm::PointerIntPair<Operand *, 1 >;
462- ValueType value;
463-
467+ struct TransferringOperandState {
464468 // / The dynamic isolation info of the region of value when we transferred.
465469 // /
466470 // / This will contain the isolated value if we found one.
@@ -469,65 +473,30 @@ class TransferringOperand {
469473 // / The dynamic isolation history at this point.
470474 IsolationHistory isolationHistory;
471475
472- TransferringOperand (ValueType newValue, SILIsolationInfo isolationRegionInfo,
473- IsolationHistory isolationHistory)
474- : value(newValue), isolationInfo(isolationRegionInfo),
475- isolationHistory (isolationHistory) {
476- assert (isolationInfo && " Should never see unknown isolation info" );
477- }
478-
479- public:
480- TransferringOperand (Operand *op, bool isClosureCaptured,
481- SILIsolationInfo isolationRegionInfo,
482- IsolationHistory isolationHistory)
483- : TransferringOperand({op, isClosureCaptured}, isolationRegionInfo,
484- isolationHistory) {}
485- explicit TransferringOperand (Operand *op,
486- SILIsolationInfo isolationRegionInfo,
487- IsolationHistory isolationHistory)
488- : TransferringOperand({op, false }, isolationRegionInfo,
489- isolationHistory) {}
490-
491- operator bool () const { return bool (value.getPointer ()); }
492-
493- Operand *getOperand () const { return value.getPointer (); }
494-
495- SILValue get () const { return getOperand ()->get (); }
496-
497- bool isClosureCaptured () const { return value.getInt (); }
498-
499- SILInstruction *getUser () const { return getOperand ()->getUser (); }
476+ // / Set to true if the element associated with the operand's vlaue is closure
477+ // / captured by the user. In such a case, if our element is a sendable var of
478+ // / a non-Sendable type, we cannot access it since we could race against an
479+ // / assignment to the var in a closure.
480+ bool isClosureCaptured;
500481
501- SILIsolationInfo getIsolationInfo () const { return isolationInfo; }
502-
503- IsolationHistory getIsolationHistory () const { return isolationHistory; }
504-
505- unsigned getOperandNumber () const { return getOperand ()->getOperandNumber (); }
506-
507- void print (llvm::raw_ostream &os) const {
508- os << " Op Num: " << getOperand ()->getOperandNumber () << " . "
509- << " Capture: " << (isClosureCaptured () ? " yes. " : " no. " )
510- << " IsolationInfo: " ;
511- isolationInfo.print (os);
512- os << " \n User: " << *getUser ();
513- }
482+ TransferringOperandState (IsolationHistory history)
483+ : isolationInfo(), isolationHistory(history), isClosureCaptured(false ) {}
484+ };
514485
515- static void Profile (llvm::FoldingSetNodeID &id, Operand *op,
516- bool isClosureCaptured,
517- SILIsolationInfo isolationRegionInfo,
518- IsolationHistory isolationHistory) {
519- id.AddPointer (op);
520- id.AddBoolean (isClosureCaptured);
521- isolationRegionInfo.Profile (id);
522- id.AddPointer (isolationHistory.getHead ());
523- }
486+ class TransferringOperandToStateMap {
487+ llvm::SmallDenseMap<Operand *, TransferringOperandState> internalMap;
488+ IsolationHistory::Factory &isolationHistoryFactory;
524489
525- void Profile (llvm::FoldingSetNodeID &id) const {
526- Profile (id, getOperand (), isClosureCaptured (), isolationInfo,
527- isolationHistory);
490+ public:
491+ TransferringOperandToStateMap (
492+ IsolationHistory::Factory &isolationHistoryFactory)
493+ : isolationHistoryFactory(isolationHistoryFactory) {}
494+ TransferringOperandState &get (Operand *op) const {
495+ auto *self = const_cast <TransferringOperandToStateMap *>(this );
496+ auto history = IsolationHistory (&isolationHistoryFactory);
497+ return self->internalMap .try_emplace (op, TransferringOperandState (history))
498+ .first ->getSecond ();
528499 }
529-
530- SWIFT_DEBUG_DUMP { print (llvm::dbgs ()); }
531500};
532501
533502} // namespace swift
@@ -676,9 +645,8 @@ class Partition {
676645
677646 using Element = PartitionPrimitives::Element;
678647 using Region = PartitionPrimitives::Region;
679- using TransferringOperandSet = ImmutablePointerSet<TransferringOperand *>;
680- using TransferringOperandSetFactory =
681- ImmutablePointerSetFactory<TransferringOperand *>;
648+ using TransferringOperandSet = ImmutablePointerSet<Operand *>;
649+ using TransferringOperandSetFactory = ImmutablePointerSetFactory<Operand *>;
682650 using IsolationHistoryNode = IsolationHistory::Node;
683651
684652private:
@@ -1014,13 +982,16 @@ struct PartitionOpEvaluator {
1014982
1015983protected:
1016984 TransferringOperandSetFactory &ptrSetFactory;
985+ TransferringOperandToStateMap &operandToStateMap;
1017986
1018987 Partition &p;
1019988
1020989public:
1021990 PartitionOpEvaluator (Partition &p,
1022- TransferringOperandSetFactory &ptrSetFactory)
1023- : ptrSetFactory(ptrSetFactory), p(p) {}
991+ TransferringOperandSetFactory &ptrSetFactory,
992+ TransferringOperandToStateMap &operandToStateMap)
993+ : ptrSetFactory(ptrSetFactory), operandToStateMap(operandToStateMap),
994+ p (p) {}
1024995
1025996 // / Call shouldEmitVerboseLogging on our CRTP subclass.
1026997 bool shouldEmitVerboseLogging () const {
@@ -1029,7 +1000,7 @@ struct PartitionOpEvaluator {
10291000
10301001 // / Call handleLocalUseAfterTransfer on our CRTP subclass.
10311002 void handleLocalUseAfterTransfer (const PartitionOp &op, Element elt,
1032- TransferringOperand *transferringOp) const {
1003+ Operand *transferringOp) const {
10331004 return asImpl ().handleLocalUseAfterTransfer (op, elt, transferringOp);
10341005 }
10351006
@@ -1194,9 +1165,13 @@ struct PartitionOpEvaluator {
11941165 }
11951166
11961167 // Mark op.getOpArgs()[0] as transferred.
1197- auto *ptrSet = ptrSetFactory.emplace (
1198- op.getSourceOp (), isClosureCapturedElt, transferredRegionIsolation,
1199- p.getIsolationHistory ());
1168+ TransferringOperandState &state = operandToStateMap.get (op.getSourceOp ());
1169+ state.isClosureCaptured |= isClosureCapturedElt;
1170+ state.isolationInfo =
1171+ state.isolationInfo .merge (transferredRegionIsolation);
1172+ assert (state.isolationInfo && " Cannot have unknown" );
1173+ state.isolationHistory .pushCFGHistoryJoin (p.getIsolationHistory ());
1174+ auto *ptrSet = ptrSetFactory.get (op.getSourceOp ());
12001175 p.markTransferred (op.getOpArgs ()[0 ], ptrSet);
12011176 return ;
12021177 }
@@ -1266,9 +1241,8 @@ struct PartitionOpEvaluator {
12661241private:
12671242 // Private helper that squelches the error if our transfer instruction and our
12681243 // use have the same isolation.
1269- void
1270- handleLocalUseAfterTransferHelper (const PartitionOp &op, Element elt,
1271- TransferringOperand *transferringOp) const {
1244+ void handleLocalUseAfterTransferHelper (const PartitionOp &op, Element elt,
1245+ Operand *transferringOp) const {
12721246 if (shouldTryToSquelchErrors ()) {
12731247 if (auto isolationInfo = SILIsolationInfo::get (op.getSourceInst ())) {
12741248 if (isolationInfo.isActorIsolated () &&
@@ -1306,8 +1280,9 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
13061280 using Super = PartitionOpEvaluator<Subclass>;
13071281
13081282 PartitionOpEvaluatorBaseImpl (Partition &workingPartition,
1309- TransferringOperandSetFactory &ptrSetFactory)
1310- : Super(workingPartition, ptrSetFactory) {}
1283+ TransferringOperandSetFactory &ptrSetFactory,
1284+ TransferringOperandToStateMap &operandToStateMap)
1285+ : Super(workingPartition, ptrSetFactory, operandToStateMap) {}
13111286
13121287 // / Should we emit extra verbose logging statements when evaluating
13131288 // / PartitionOps.
@@ -1326,7 +1301,7 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
13261301 // / region. Can be used to get the immediate value transferred or the
13271302 // / transferring instruction.
13281303 void handleLocalUseAfterTransfer (const PartitionOp &op, Element elt,
1329- TransferringOperand *transferringOp) const {}
1304+ Operand *transferringOp) const {}
13301305
13311306 // / This is called if we detect a never transferred element that was passed to
13321307 // / a transfer instruction.
@@ -1374,8 +1349,10 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
13741349struct PartitionOpEvaluatorBasic final
13751350 : PartitionOpEvaluatorBaseImpl<PartitionOpEvaluatorBasic> {
13761351 PartitionOpEvaluatorBasic (Partition &workingPartition,
1377- TransferringOperandSetFactory &ptrSetFactory)
1378- : PartitionOpEvaluatorBaseImpl(workingPartition, ptrSetFactory) {}
1352+ TransferringOperandSetFactory &ptrSetFactory,
1353+ TransferringOperandToStateMap &operandToStateMap)
1354+ : PartitionOpEvaluatorBaseImpl(workingPartition, ptrSetFactory,
1355+ operandToStateMap) {}
13791356};
13801357
13811358} // namespace swift
0 commit comments