66#include " swift/SIL/BasicBlockData.h"
77#include " swift/SIL/BasicBlockDatastructures.h"
88#include " swift/SIL/MemAccessUtils.h"
9+ #include " swift/SIL/OwnershipUtils.h"
910#include " swift/SIL/SILBasicBlock.h"
1011#include " swift/SIL/SILFunction.h"
1112#include " swift/SIL/SILInstruction.h"
@@ -58,33 +59,96 @@ class PartitionOpTranslator {
5859 ProtocolDecl *sendableProtocol;
5960
6061 // nodeIDMap stores unique IDs for all SILNodes corresponding to
61- // non-Sendable values. Implicit conversion from SILValue used pervasively
62+ // non-Sendable values. Implicit conversion from SILValue used pervasively.
63+ // ensure simplifyVal is called on SILValues before entering into this map
6264 llvm::DenseMap<const SILNode *, unsigned > nodeIDMap;
6365 unsigned nextNodeID = 0 ;
6466
67+ // some values that AccessStorage claims are uniquely identified are still
68+ // captured (e.g. in a closure). This set is initialized upon
69+ // PartitionOpTranslator construction to store those values.
70+ // ensure simplifyVal is called on SILValues before entering into this map
71+ //
72+ // TODO: we could remember not just which values fit this description,
73+ // but at what points in function flow they do, this would be more
74+ // permissive, but I'm avoiding implementing it in case existing
75+ // utilities would make it easier than handrolling
76+ std::set<SILValue> capturedUIValues;
77+
78+ void initCapturedUIValues () {
79+ for (const SILBasicBlock &block: *function) {
80+ for (const SILInstruction &inst: block) {
81+ if (isApplyInst (inst)) {
82+ // add all nonsendable, uniquely identified arguments to applications
83+ // to capturedUIValues, because applications capture them
84+ for (SILValue val : inst.getOperandValues ()) {
85+ if (isNonSendable (val) && isUniquelyIdentified (val))
86+ capturedUIValues.insert (simplifyVal (val));
87+ }
88+ }
89+ }
90+ }
91+ }
92+
93+ public:
94+ // create a new PartitionOpTranslator, all that's needed is the underlying
95+ // SIL function
96+ PartitionOpTranslator (SILFunction *function) :
97+ function (function),
98+ sendableProtocol (function->getASTContext ()
99+ .getProtocol(KnownProtocolKind::Sendable)) {
100+ assert (sendableProtocol && " PartitionOpTranslators should only be created "
101+ " in contexts in which the availability of the "
102+ " Sendable protocol has already been checked." );
103+ initCapturedUIValues ();
104+ LLVM_DEBUG (
105+ llvm::dbgs () << " Captured Uniquely Identified addresses for "
106+ << function->getName () << " :\n " ;
107+ for (SILValue val : capturedUIValues)
108+ val->dump ();
109+
110+ );
111+ }
112+
113+ private:
114+ static inline bool isAddress (SILValue val) {
115+ return val->getType ().isAddress ();
116+ }
117+
118+ static bool isApplyInst (const SILInstruction &inst) {
119+ return isa<ApplyInst, TryApplyInst, PartialApplyInst, BuiltinInst>(inst);
120+ }
121+
65122 AccessStorage getAccessStorageFromAddr (SILValue val) {
66- assert (val-> getType (). isAddress ());
123+ assert (isAddress (val ));
67124 auto accessStorage = AccessStorage::compute (val);
68125 if (accessStorage) {
69- if (auto initExistential = dyn_cast_or_null<InitExistentialAddrInst>(
70- accessStorage.getRoot ().getDefiningInstruction ()))
126+ auto definingInst = accessStorage.getRoot ().getDefiningInstruction ();
127+ if (definingInst &&
128+ isa<InitExistentialAddrInst, CopyValueInst>(definingInst))
71129 // look through these because AccessStorage does not
72- return getAccessStorageFromAddr (initExistential ->getOperand ());
130+ return getAccessStorageFromAddr (definingInst ->getOperand (0 ));
73131 }
74132 return accessStorage;
75133 }
76134
77135 bool isUniquelyIdentified (SILValue val) {
78- if (!val->getType ().isAddress ())
136+ val = simplifyVal (val);
137+ if (!isAddress (val))
79138 return false ;
80- if (auto accessStorage = getAccessStorageFromAddr (val)) {
81- return accessStorage.isUniquelyIdentified ();
82- }
139+ if (auto accessStorage = getAccessStorageFromAddr (val))
140+ return accessStorage.isUniquelyIdentified () &&
141+ !capturedUIValues. count ( simplifyVal (val));
83142 return false ;
84143 }
85144
145+ // simplifyVal reduces an address-typed SILValue to the root SILValue
146+ // that it was derived from, reducing the set of values that must be
147+ // reasoned about by rendering two values that are projections/aliases the
148+ // same.
149+ // TODO: make usage of this more principled with a wrapper type SimplSILValue
86150 SILValue simplifyVal (SILValue val) {
87- if (!val-> getType (). isAddress ())
151+ if (!isAddress (val ))
88152 return getUnderlyingObject (val);
89153 if (auto accessStorage = getAccessStorageFromAddr (val)) {
90154 return accessStorage.getRoot ();
@@ -209,17 +273,6 @@ class PartitionOpTranslator {
209273 }
210274
211275public:
212- // create a new PartitionOpTranslator, all that's needed is the underlying
213- // SIL function
214- PartitionOpTranslator (SILFunction *function) :
215- function (function),
216- sendableProtocol (function->getASTContext ()
217- .getProtocol(KnownProtocolKind::Sendable)) {
218- assert (sendableProtocol && " PartitionOpTranslators should only be created "
219- " in contexts in which the availability of the "
220- " Sendable protocol has already been checked." );
221- }
222-
223276 // Create a partition that places all arguments from this function,
224277 // including self if available, into the same region, ensuring those
225278 // arguments get IDs in doing so. This Partition will be used as the
@@ -352,17 +405,22 @@ class PartitionOpTranslator {
352405 }
353406 // ===========================================================================
354407
408+ // used to index the translations of SILInstructions performed
409+ int translationIndex = 0 ;
410+
355411 // Some SILInstructions contribute to the partition of non-Sendable values
356412 // being analyzed. translateSILInstruction translate a SILInstruction
357413 // to its effect on the non-Sendable partition, if it has one.
358414 //
359415 // The current pattern of
360416 std::vector<PartitionOp> translateSILInstruction (SILInstruction *instruction) {
417+ translationIndex++;
361418 currentInstruction = instruction;
362419
363420 // The following instructions are treated as assigning their result to a
364421 // fresh region.
365- if (isa<AllocRefInst,
422+ if (isa<AllocBoxInst,
423+ AllocRefInst,
366424 AllocStackInst,
367425 LiteralInst>(instruction)) {
368426 return translateSILAssignFresh (instruction->getResult (0 ));
@@ -410,7 +468,7 @@ class PartitionOpTranslator {
410468 }
411469
412470 // Handle applications
413- if (isa<ApplyInst, PartialApplyInst>( instruction)) {
471+ if (isApplyInst (* instruction)) {
414472 return translateSILApply (instruction);
415473 }
416474
@@ -428,6 +486,11 @@ class PartitionOpTranslator {
428486 return translateSILRequire (returnInst->getOperand ());
429487 }
430488
489+ LLVM_DEBUG (
490+ llvm::dbgs () << " WARN: unhandled instruction kind "
491+ << getSILInstructionName (instruction->getKind ());
492+ );
493+
431494 return {};
432495 }
433496
@@ -454,8 +517,12 @@ class PartitionOpTranslator {
454517 partitionOps.push_back (op);
455518
456519 LLVM_DEBUG (
520+ llvm::dbgs () << " ┌─┬─╼" ;
457521 instruction.dump ();
458- llvm::dbgs () << " └───╼ " ;
522+ llvm::dbgs () << " │ └─╼ " ;
523+ instruction.getLoc ().getSourceLoc ().printLineAndColumn (llvm::dbgs (), function->getASTContext ().SourceMgr );
524+ llvm::dbgs () << " │ translation #" << translationIndex;
525+ llvm::dbgs () << " \n └─────╼ " ;
459526 op.dump ();
460527 );
461528 }
@@ -527,7 +594,8 @@ class BlockPartitionState {
527594 for (auto &partitionOp : blockPartitionOps) {
528595 workingPartition.apply (partitionOp, handleFailure,
529596 translator.getNonConsumables (),
530- handleConsumeNonConsumable);
597+ handleConsumeNonConsumable,
598+ /* reviveAfterFailure=*/ false );
531599 }
532600 }
533601
0 commit comments