19
19
#include " swift/Basic/LLVM.h"
20
20
#include " swift/SIL/SILFunction.h"
21
21
#include " swift/SIL/SILInstruction.h"
22
+
23
+ #include " llvm/ADT/MapVector.h"
24
+ #include " llvm/ADT/STLExtras.h"
22
25
#include " llvm/ADT/SmallVector.h"
23
26
#include " llvm/Support/Debug.h"
27
+
24
28
#include < algorithm>
25
29
#include < variant>
26
30
@@ -223,6 +227,7 @@ class SILIsolationInfo {
223
227
};
224
228
225
229
class Partition ;
230
+ class TransferringOperandToStateMap ;
226
231
227
232
// / A persistent data structure that is used to "rewind" partition history so
228
233
// / that we can discover when values become part of the same region.
@@ -244,6 +249,7 @@ class IsolationHistory {
244
249
245
250
// TODO: This shouldn't need to be a friend.
246
251
friend class Partition ;
252
+ friend TransferringOperandToStateMap;
247
253
248
254
// / First node in the immutable linked list.
249
255
Node *head = nullptr ;
@@ -297,6 +303,11 @@ class IsolationHistory {
297
303
// / Push that \p other should be merged into this region.
298
304
void pushCFGHistoryJoin (Node *otherNode);
299
305
306
+ // / Push the top node of \p history as a CFG history join.
307
+ void pushCFGHistoryJoin (IsolationHistory history) {
308
+ return pushCFGHistoryJoin (history.getHead ());
309
+ }
310
+
300
311
Node *pop ();
301
312
};
302
313
@@ -456,10 +467,7 @@ class IsolationHistory::Factory {
456
467
IsolationHistory get () { return IsolationHistory (this ); }
457
468
};
458
469
459
- class TransferringOperand {
460
- using ValueType = llvm::PointerIntPair<Operand *, 1 >;
461
- ValueType value;
462
-
470
+ struct TransferringOperandState {
463
471
// / The dynamic isolation info of the region of value when we transferred.
464
472
// /
465
473
// / This will contain the isolated value if we found one.
@@ -468,65 +476,30 @@ class TransferringOperand {
468
476
// / The dynamic isolation history at this point.
469
477
IsolationHistory isolationHistory;
470
478
471
- TransferringOperand (ValueType newValue, SILIsolationInfo isolationRegionInfo,
472
- IsolationHistory isolationHistory)
473
- : value(newValue), isolationInfo(isolationRegionInfo),
474
- isolationHistory (isolationHistory) {
475
- assert (isolationInfo && " Should never see unknown isolation info" );
476
- }
477
-
478
- public:
479
- TransferringOperand (Operand *op, bool isClosureCaptured,
480
- SILIsolationInfo isolationRegionInfo,
481
- IsolationHistory isolationHistory)
482
- : TransferringOperand({op, isClosureCaptured}, isolationRegionInfo,
483
- isolationHistory) {}
484
- explicit TransferringOperand (Operand *op,
485
- SILIsolationInfo isolationRegionInfo,
486
- IsolationHistory isolationHistory)
487
- : TransferringOperand({op, false }, isolationRegionInfo,
488
- isolationHistory) {}
489
-
490
- operator bool () const { return bool (value.getPointer ()); }
491
-
492
- Operand *getOperand () const { return value.getPointer (); }
493
-
494
- SILValue get () const { return getOperand ()->get (); }
495
-
496
- bool isClosureCaptured () const { return value.getInt (); }
479
+ // / Set to true if the element associated with the operand's vlaue is closure
480
+ // / captured by the user. In such a case, if our element is a sendable var of
481
+ // / a non-Sendable type, we cannot access it since we could race against an
482
+ // / assignment to the var in a closure.
483
+ bool isClosureCaptured;
497
484
498
- SILInstruction *getUser () const { return getOperand ()->getUser (); }
499
-
500
- SILIsolationInfo getIsolationInfo () const { return isolationInfo; }
501
-
502
- IsolationHistory getIsolationHistory () const { return isolationHistory; }
503
-
504
- unsigned getOperandNumber () const { return getOperand ()->getOperandNumber (); }
505
-
506
- void print (llvm::raw_ostream &os) const {
507
- os << " Op Num: " << getOperand ()->getOperandNumber () << " . "
508
- << " Capture: " << (isClosureCaptured () ? " yes. " : " no. " )
509
- << " IsolationInfo: " ;
510
- isolationInfo.print (os);
511
- os << " \n User: " << *getUser ();
512
- }
485
+ TransferringOperandState (IsolationHistory history)
486
+ : isolationInfo(), isolationHistory(history), isClosureCaptured(false ) {}
487
+ };
513
488
514
- static void Profile (llvm::FoldingSetNodeID &id, Operand *op,
515
- bool isClosureCaptured,
516
- SILIsolationInfo isolationRegionInfo,
517
- IsolationHistory isolationHistory) {
518
- id.AddPointer (op);
519
- id.AddBoolean (isClosureCaptured);
520
- isolationRegionInfo.Profile (id);
521
- id.AddPointer (isolationHistory.getHead ());
522
- }
489
+ class TransferringOperandToStateMap {
490
+ llvm::SmallDenseMap<Operand *, TransferringOperandState> internalMap;
491
+ IsolationHistory::Factory &isolationHistoryFactory;
523
492
524
- void Profile (llvm::FoldingSetNodeID &id) const {
525
- Profile (id, getOperand (), isClosureCaptured (), isolationInfo,
526
- isolationHistory);
493
+ public:
494
+ TransferringOperandToStateMap (
495
+ IsolationHistory::Factory &isolationHistoryFactory)
496
+ : isolationHistoryFactory(isolationHistoryFactory) {}
497
+ TransferringOperandState &get (Operand *op) const {
498
+ auto *self = const_cast <TransferringOperandToStateMap *>(this );
499
+ auto history = IsolationHistory (&isolationHistoryFactory);
500
+ return self->internalMap .try_emplace (op, TransferringOperandState (history))
501
+ .first ->getSecond ();
527
502
}
528
-
529
- SWIFT_DEBUG_DUMP { print (llvm::dbgs ()); }
530
503
};
531
504
532
505
} // namespace swift
@@ -675,9 +648,8 @@ class Partition {
675
648
676
649
using Element = PartitionPrimitives::Element;
677
650
using Region = PartitionPrimitives::Region;
678
- using TransferringOperandSet = ImmutablePointerSet<TransferringOperand *>;
679
- using TransferringOperandSetFactory =
680
- ImmutablePointerSetFactory<TransferringOperand *>;
651
+ using TransferringOperandSet = ImmutablePointerSet<Operand *>;
652
+ using TransferringOperandSetFactory = ImmutablePointerSetFactory<Operand *>;
681
653
using IsolationHistoryNode = IsolationHistory::Node;
682
654
683
655
private:
@@ -689,7 +661,7 @@ class Partition {
689
661
// / multi map here. The implication of this is that when we are performing
690
662
// / dataflow we use a union operation to combine CFG elements and just take
691
663
// / the first instruction that we see.
692
- llvm::SmallDenseMap <Region, TransferringOperandSet *, 2 >
664
+ llvm::SmallMapVector <Region, TransferringOperandSet *, 2 >
693
665
regionToTransferredOpMap;
694
666
695
667
// / Label each index with a non-negative (unsigned) label if it is associated
@@ -736,7 +708,16 @@ class Partition {
736
708
fst.canonicalize ();
737
709
snd.canonicalize ();
738
710
739
- return fst.elementToRegionMap == snd.elementToRegionMap ;
711
+ return fst.elementToRegionMap == snd.elementToRegionMap &&
712
+ fst.regionToTransferredOpMap .size () ==
713
+ snd.regionToTransferredOpMap .size () &&
714
+ llvm::all_of (
715
+ fst.regionToTransferredOpMap ,
716
+ [&snd](const std::pair<Region, TransferringOperandSet *> &p) {
717
+ auto sndIter = snd.regionToTransferredOpMap .find (p.first );
718
+ return sndIter != snd.regionToTransferredOpMap .end () &&
719
+ sndIter->second == p.second ;
720
+ });
740
721
}
741
722
742
723
bool isTrackingElement (Element val) const {
@@ -1013,13 +994,16 @@ struct PartitionOpEvaluator {
1013
994
1014
995
protected:
1015
996
TransferringOperandSetFactory &ptrSetFactory;
997
+ TransferringOperandToStateMap &operandToStateMap;
1016
998
1017
999
Partition &p;
1018
1000
1019
1001
public:
1020
1002
PartitionOpEvaluator (Partition &p,
1021
- TransferringOperandSetFactory &ptrSetFactory)
1022
- : ptrSetFactory(ptrSetFactory), p(p) {}
1003
+ TransferringOperandSetFactory &ptrSetFactory,
1004
+ TransferringOperandToStateMap &operandToStateMap)
1005
+ : ptrSetFactory(ptrSetFactory), operandToStateMap(operandToStateMap),
1006
+ p (p) {}
1023
1007
1024
1008
// / Call shouldEmitVerboseLogging on our CRTP subclass.
1025
1009
bool shouldEmitVerboseLogging () const {
@@ -1028,7 +1012,7 @@ struct PartitionOpEvaluator {
1028
1012
1029
1013
// / Call handleLocalUseAfterTransfer on our CRTP subclass.
1030
1014
void handleLocalUseAfterTransfer (const PartitionOp &op, Element elt,
1031
- TransferringOperand *transferringOp) const {
1015
+ Operand *transferringOp) const {
1032
1016
return asImpl ().handleLocalUseAfterTransfer (op, elt, transferringOp);
1033
1017
}
1034
1018
@@ -1193,9 +1177,13 @@ struct PartitionOpEvaluator {
1193
1177
}
1194
1178
1195
1179
// Mark op.getOpArgs()[0] as transferred.
1196
- auto *ptrSet = ptrSetFactory.emplace (
1197
- op.getSourceOp (), isClosureCapturedElt, transferredRegionIsolation,
1198
- p.getIsolationHistory ());
1180
+ TransferringOperandState &state = operandToStateMap.get (op.getSourceOp ());
1181
+ state.isClosureCaptured |= isClosureCapturedElt;
1182
+ state.isolationInfo =
1183
+ state.isolationInfo .merge (transferredRegionIsolation);
1184
+ assert (state.isolationInfo && " Cannot have unknown" );
1185
+ state.isolationHistory .pushCFGHistoryJoin (p.getIsolationHistory ());
1186
+ auto *ptrSet = ptrSetFactory.get (op.getSourceOp ());
1199
1187
p.markTransferred (op.getOpArgs ()[0 ], ptrSet);
1200
1188
return ;
1201
1189
}
@@ -1265,9 +1253,8 @@ struct PartitionOpEvaluator {
1265
1253
private:
1266
1254
// Private helper that squelches the error if our transfer instruction and our
1267
1255
// use have the same isolation.
1268
- void
1269
- handleLocalUseAfterTransferHelper (const PartitionOp &op, Element elt,
1270
- TransferringOperand *transferringOp) const {
1256
+ void handleLocalUseAfterTransferHelper (const PartitionOp &op, Element elt,
1257
+ Operand *transferringOp) const {
1271
1258
if (shouldTryToSquelchErrors ()) {
1272
1259
if (auto isolationInfo = SILIsolationInfo::get (op.getSourceInst ())) {
1273
1260
if (isolationInfo.isActorIsolated () &&
@@ -1305,8 +1292,9 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
1305
1292
using Super = PartitionOpEvaluator<Subclass>;
1306
1293
1307
1294
PartitionOpEvaluatorBaseImpl (Partition &workingPartition,
1308
- TransferringOperandSetFactory &ptrSetFactory)
1309
- : Super(workingPartition, ptrSetFactory) {}
1295
+ TransferringOperandSetFactory &ptrSetFactory,
1296
+ TransferringOperandToStateMap &operandToStateMap)
1297
+ : Super(workingPartition, ptrSetFactory, operandToStateMap) {}
1310
1298
1311
1299
// / Should we emit extra verbose logging statements when evaluating
1312
1300
// / PartitionOps.
@@ -1325,7 +1313,7 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
1325
1313
// / region. Can be used to get the immediate value transferred or the
1326
1314
// / transferring instruction.
1327
1315
void handleLocalUseAfterTransfer (const PartitionOp &op, Element elt,
1328
- TransferringOperand *transferringOp) const {}
1316
+ Operand *transferringOp) const {}
1329
1317
1330
1318
// / This is called if we detect a never transferred element that was passed to
1331
1319
// / a transfer instruction.
@@ -1373,8 +1361,10 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
1373
1361
struct PartitionOpEvaluatorBasic final
1374
1362
: PartitionOpEvaluatorBaseImpl<PartitionOpEvaluatorBasic> {
1375
1363
PartitionOpEvaluatorBasic (Partition &workingPartition,
1376
- TransferringOperandSetFactory &ptrSetFactory)
1377
- : PartitionOpEvaluatorBaseImpl(workingPartition, ptrSetFactory) {}
1364
+ TransferringOperandSetFactory &ptrSetFactory,
1365
+ TransferringOperandToStateMap &operandToStateMap)
1366
+ : PartitionOpEvaluatorBaseImpl(workingPartition, ptrSetFactory,
1367
+ operandToStateMap) {}
1378
1368
};
1379
1369
1380
1370
} // namespace swift
0 commit comments