6
6
#include " swift/SIL/BasicBlockData.h"
7
7
#include " swift/SIL/BasicBlockDatastructures.h"
8
8
#include " swift/SIL/MemAccessUtils.h"
9
+ #include " swift/SIL/OwnershipUtils.h"
9
10
#include " swift/SIL/SILBasicBlock.h"
10
11
#include " swift/SIL/SILFunction.h"
11
12
#include " swift/SIL/SILInstruction.h"
@@ -58,33 +59,96 @@ class PartitionOpTranslator {
58
59
ProtocolDecl *sendableProtocol;
59
60
60
61
// 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
62
64
llvm::DenseMap<const SILNode *, unsigned > nodeIDMap;
63
65
unsigned nextNodeID = 0 ;
64
66
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
+
65
122
AccessStorage getAccessStorageFromAddr (SILValue val) {
66
- assert (val-> getType (). isAddress ());
123
+ assert (isAddress (val ));
67
124
auto accessStorage = AccessStorage::compute (val);
68
125
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))
71
129
// look through these because AccessStorage does not
72
- return getAccessStorageFromAddr (initExistential ->getOperand ());
130
+ return getAccessStorageFromAddr (definingInst ->getOperand (0 ));
73
131
}
74
132
return accessStorage;
75
133
}
76
134
77
135
bool isUniquelyIdentified (SILValue val) {
78
- if (!val->getType ().isAddress ())
136
+ val = simplifyVal (val);
137
+ if (!isAddress (val))
79
138
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));
83
142
return false ;
84
143
}
85
144
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
86
150
SILValue simplifyVal (SILValue val) {
87
- if (!val-> getType (). isAddress ())
151
+ if (!isAddress (val ))
88
152
return getUnderlyingObject (val);
89
153
if (auto accessStorage = getAccessStorageFromAddr (val)) {
90
154
return accessStorage.getRoot ();
@@ -209,17 +273,6 @@ class PartitionOpTranslator {
209
273
}
210
274
211
275
public:
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
-
223
276
// Create a partition that places all arguments from this function,
224
277
// including self if available, into the same region, ensuring those
225
278
// arguments get IDs in doing so. This Partition will be used as the
@@ -352,17 +405,22 @@ class PartitionOpTranslator {
352
405
}
353
406
// ===========================================================================
354
407
408
+ // used to index the translations of SILInstructions performed
409
+ int translationIndex = 0 ;
410
+
355
411
// Some SILInstructions contribute to the partition of non-Sendable values
356
412
// being analyzed. translateSILInstruction translate a SILInstruction
357
413
// to its effect on the non-Sendable partition, if it has one.
358
414
//
359
415
// The current pattern of
360
416
std::vector<PartitionOp> translateSILInstruction (SILInstruction *instruction) {
417
+ translationIndex++;
361
418
currentInstruction = instruction;
362
419
363
420
// The following instructions are treated as assigning their result to a
364
421
// fresh region.
365
- if (isa<AllocRefInst,
422
+ if (isa<AllocBoxInst,
423
+ AllocRefInst,
366
424
AllocStackInst,
367
425
LiteralInst>(instruction)) {
368
426
return translateSILAssignFresh (instruction->getResult (0 ));
@@ -410,7 +468,7 @@ class PartitionOpTranslator {
410
468
}
411
469
412
470
// Handle applications
413
- if (isa<ApplyInst, PartialApplyInst>( instruction)) {
471
+ if (isApplyInst (* instruction)) {
414
472
return translateSILApply (instruction);
415
473
}
416
474
@@ -428,6 +486,11 @@ class PartitionOpTranslator {
428
486
return translateSILRequire (returnInst->getOperand ());
429
487
}
430
488
489
+ LLVM_DEBUG (
490
+ llvm::dbgs () << " WARN: unhandled instruction kind "
491
+ << getSILInstructionName (instruction->getKind ());
492
+ );
493
+
431
494
return {};
432
495
}
433
496
@@ -454,8 +517,12 @@ class PartitionOpTranslator {
454
517
partitionOps.push_back (op);
455
518
456
519
LLVM_DEBUG (
520
+ llvm::dbgs () << " ┌─┬─╼" ;
457
521
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 └─────╼ " ;
459
526
op.dump ();
460
527
);
461
528
}
@@ -527,7 +594,8 @@ class BlockPartitionState {
527
594
for (auto &partitionOp : blockPartitionOps) {
528
595
workingPartition.apply (partitionOp, handleFailure,
529
596
translator.getNonConsumables (),
530
- handleConsumeNonConsumable);
597
+ handleConsumeNonConsumable,
598
+ /* reviveAfterFailure=*/ false );
531
599
}
532
600
}
533
601
0 commit comments