@@ -87,9 +87,41 @@ struct borrowtodestructure::Implementation {
87
87
88
88
bool gatherUses (SILValue value);
89
89
90
+ // / Once we have gathered up all of our destructure uses and liveness
91
+ // / requiring uses, validate that all of our destructure uses are on our
92
+ // / boundary. Once we have done this, we know that it is safe to perform our
93
+ // / transform.
94
+ void checkDestructureUsesOnBoundary () const ;
95
+
96
+ // / Check for cases where we have two consuming uses on the same instruction
97
+ // / or a consuming/non-consuming use on the same instruction.
98
+ void checkForErrorsOnSameInstruction ();
99
+
100
+ // / Rewrite all of the uses of our borrow on our borrow operand, performing
101
+ // / destructures as appropriate.
102
+ void rewriteUses ();
103
+
104
+ AvailableValues &computeAvailableValues (SILBasicBlock *block);
105
+
90
106
// / Returns mark_must_check if we are processing borrows or the enum argument
91
107
// / if we are processing switch_enum.
92
108
SILValue getRootValue () const { return interface.mmci ; }
109
+
110
+ DiagnosticEmitter &getDiagnostics () const {
111
+ return interface.diagnosticEmitter ;
112
+ }
113
+
114
+ // / Always returns the actual root mark_must_check for both switch_enum args
115
+ // / and normal borrow user checks.
116
+ MarkMustCheckInst *getMarkedValue () const { return interface.mmci ; }
117
+
118
+ PostOrderFunctionInfo *getPostOrderFunctionInfo () {
119
+ return interface.getPostOrderFunctionInfo ();
120
+ }
121
+
122
+ IntervalMapAllocator::Allocator &getAllocator () {
123
+ return interface.allocator .get ();
124
+ }
93
125
};
94
126
95
127
bool Implementation::gatherUses (SILValue value) {
@@ -212,18 +244,15 @@ bool Implementation::gatherUses(SILValue value) {
212
244
return true ;
213
245
}
214
246
215
- // ===----------------------------------------------------------------------===//
216
- // MARK: Convert Borrow Extracts To Owned Destructures
217
- // ===----------------------------------------------------------------------===//
218
-
219
- void BorrowToDestructureTransform::checkForErrorsOnSameInstruction () {
247
+ void Implementation::checkForErrorsOnSameInstruction () {
220
248
// At this point, we have emitted all boundary checks. We also now need to
221
249
// check if any of our consuming uses that are on the boundary are used by the
222
250
// same instruction as a different consuming or non-consuming use.
223
- instToInterestingOperandIndexMap.setFrozen ();
224
- SmallBitVector usedBits (liveness->getNumSubElements ());
251
+ interface. instToInterestingOperandIndexMap .setFrozen ();
252
+ SmallBitVector usedBits (interface. liveness ->getNumSubElements ());
225
253
226
- for (auto instRangePair : instToInterestingOperandIndexMap.getRange ()) {
254
+ for (auto instRangePair :
255
+ interface.instToInterestingOperandIndexMap .getRange ()) {
227
256
SWIFT_DEFER { usedBits.reset (); };
228
257
229
258
// First loop through our uses and handle any consuming twice errors. We
@@ -234,7 +263,8 @@ void BorrowToDestructureTransform::checkForErrorsOnSameInstruction() {
234
263
if (!use->isConsuming ())
235
264
continue ;
236
265
237
- auto destructureUseSpan = *TypeTreeLeafTypeRange::get (use->get (), mmci);
266
+ auto destructureUseSpan =
267
+ *TypeTreeLeafTypeRange::get (use->get (), getRootValue ());
238
268
for (unsigned index : destructureUseSpan.getRange ()) {
239
269
if (usedBits[index]) {
240
270
// If we get that we used the same bit twice, we have an error. We set
@@ -261,7 +291,8 @@ void BorrowToDestructureTransform::checkForErrorsOnSameInstruction() {
261
291
if (use->isConsuming ())
262
292
continue ;
263
293
264
- auto destructureUseSpan = *TypeTreeLeafTypeRange::get (use->get (), mmci);
294
+ auto destructureUseSpan =
295
+ *TypeTreeLeafTypeRange::get (use->get (), getRootValue ());
265
296
for (unsigned index : destructureUseSpan.getRange ()) {
266
297
if (!usedBits[index])
267
298
continue ;
@@ -301,18 +332,19 @@ void BorrowToDestructureTransform::checkForErrorsOnSameInstruction() {
301
332
if (!use->isConsuming ())
302
333
continue ;
303
334
304
- auto destructureUseSpan = *TypeTreeLeafTypeRange::get (use->get (), mmci);
335
+ auto destructureUseSpan =
336
+ *TypeTreeLeafTypeRange::get (use->get (), getRootValue ());
305
337
bool emittedError = false ;
306
338
for (unsigned index : destructureUseSpan.getRange ()) {
307
339
if (!usedBits[index])
308
340
continue ;
309
341
310
342
if (badOperand->isConsuming ())
311
- diagnosticEmitter .emitObjectInstConsumesValueTwice (mmci, use ,
312
- badOperand);
343
+ getDiagnostics () .emitObjectInstConsumesValueTwice (getMarkedValue () ,
344
+ use, badOperand);
313
345
else
314
- diagnosticEmitter .emitObjectInstConsumesAndUsesValue (mmci, use ,
315
- badOperand);
346
+ getDiagnostics () .emitObjectInstConsumesAndUsesValue (getMarkedValue () ,
347
+ use, badOperand);
316
348
emittedError = true ;
317
349
}
318
350
@@ -323,19 +355,21 @@ void BorrowToDestructureTransform::checkForErrorsOnSameInstruction() {
323
355
}
324
356
}
325
357
326
- void BorrowToDestructureTransform ::checkDestructureUsesOnBoundary () const {
358
+ void Implementation ::checkDestructureUsesOnBoundary () const {
327
359
LLVM_DEBUG (llvm::dbgs () << " Checking destructure uses on boundary!\n " );
328
360
329
361
// Now that we have found all of our destructure needing uses and liveness
330
362
// needing uses, make sure that none of our destructure needing uses are
331
363
// within our boundary. If so, we have an automatic error since we have a
332
364
// use-after-free.
333
- for (auto *use : destructureNeedingUses) {
365
+ for (auto *use : interface. destructureNeedingUses ) {
334
366
LLVM_DEBUG (llvm::dbgs ()
335
367
<< " DestructureNeedingUse: " << *use->getUser ());
336
368
337
- auto destructureUseSpan = *TypeTreeLeafTypeRange::get (use->get (), mmci);
338
- if (!liveness->isWithinBoundary (use->getUser (), destructureUseSpan)) {
369
+ auto destructureUseSpan =
370
+ *TypeTreeLeafTypeRange::get (use->get (), getRootValue ());
371
+ if (!interface.liveness ->isWithinBoundary (use->getUser (),
372
+ destructureUseSpan)) {
339
373
LLVM_DEBUG (llvm::dbgs ()
340
374
<< " On boundary or within boundary! No error!\n " );
341
375
continue ;
@@ -351,10 +385,10 @@ void BorrowToDestructureTransform::checkDestructureUsesOnBoundary() const {
351
385
// uses.
352
386
LLVM_DEBUG (llvm::dbgs () << " Within boundary! Emitting error!\n " );
353
387
FieldSensitivePrunedLivenessBoundary boundary (
354
- liveness->getNumSubElements ());
355
- liveness->computeBoundary (boundary);
356
- diagnosticEmitter .emitObjectDestructureNeededWithinBorrowBoundary (
357
- mmci , use->getUser (), destructureUseSpan, boundary);
388
+ interface. liveness ->getNumSubElements ());
389
+ interface. liveness ->computeBoundary (boundary);
390
+ getDiagnostics () .emitObjectDestructureNeededWithinBorrowBoundary (
391
+ getMarkedValue () , use->getUser (), destructureUseSpan, boundary);
358
392
}
359
393
}
360
394
@@ -613,15 +647,14 @@ static void dumpSmallestTypeAvailable(
613
647
// / ensures that we match at the source level the assumption by users that they
614
648
// / can use entire valid parts as late as possible. If we were to do it earlier
615
649
// / we would emit errors too early.
616
- AvailableValues &
617
- BorrowToDestructureTransform::computeAvailableValues (SILBasicBlock *block) {
650
+ AvailableValues &Implementation::computeAvailableValues (SILBasicBlock *block) {
618
651
LLVM_DEBUG (llvm::dbgs () << " Computing Available Values For bb"
619
652
<< block->getDebugID () << ' \n ' );
620
653
621
654
// First grab our block. If we already have state for the block, just return
622
655
// its available values. We already computed the available values and
623
656
// potentially updated it with new destructured values for our block.
624
- auto pair = blockToAvailableValues->get (block);
657
+ auto pair = interface. blockToAvailableValues ->get (block);
625
658
if (!pair.second ) {
626
659
LLVM_DEBUG (llvm::dbgs ()
627
660
<< " Already have values! Returning them!\n " );
@@ -641,11 +674,11 @@ BorrowToDestructureTransform::computeAvailableValues(SILBasicBlock *block) {
641
674
// ensure that from an OSSA perspective any any destructures we insert are
642
675
// independent of any other copies. We assume that OSSA canonicalization will
643
676
// remove the extra copy later after we run or emit an error if it can't.
644
- if (block == mmci-> getParent ()) {
677
+ if (block == getRootValue ()-> getParentBlock ()) {
645
678
LLVM_DEBUG (llvm::dbgs ()
646
679
<< " In initial block, setting to initial value!\n " );
647
680
for (unsigned i : indices (newValues))
648
- newValues[i] = initialValue;
681
+ newValues[i] = interface. initialValue ;
649
682
LLVM_DEBUG (newValues.print (llvm::dbgs (), " " ));
650
683
return newValues;
651
684
}
@@ -745,7 +778,7 @@ BorrowToDestructureTransform::computeAvailableValues(SILBasicBlock *block) {
745
778
for (unsigned i : range (predAvailableValues.size ())) {
746
779
if (predAvailableValues[i])
747
780
smallestTypeAvailable.push_back (
748
- {{TypeOffsetSizePair (predAvailableValues[i], mmci ),
781
+ {{TypeOffsetSizePair (predAvailableValues[i], getRootValue () ),
749
782
predAvailableValues[i]->getType ()}});
750
783
else
751
784
smallestTypeAvailable.emplace_back (None);
@@ -779,7 +812,8 @@ BorrowToDestructureTransform::computeAvailableValues(SILBasicBlock *block) {
779
812
// the NOTE above), we know that if subElt has a smaller size than our
780
813
// accumulator, then it must be further down the type tree from our
781
814
// accumulator.
782
- auto offsetSize = TypeOffsetSizePair (predAvailableValues[i], mmci);
815
+ auto offsetSize =
816
+ TypeOffsetSizePair (predAvailableValues[i], getRootValue ());
783
817
if (smallestTypeAvailable[i]->first .size > offsetSize.size )
784
818
smallestTypeAvailable[i] = {offsetSize,
785
819
predAvailableValues[i]->getType ()};
@@ -800,7 +834,7 @@ BorrowToDestructureTransform::computeAvailableValues(SILBasicBlock *block) {
800
834
<< " Destructuring available values in preds to smallest size for bb"
801
835
<< block->getDebugID() << '\n');
802
836
auto *fn = block->getFunction ();
803
- IntervalMapAllocator::Map typeSpanToValue (allocator.get ());
837
+ IntervalMapAllocator::Map typeSpanToValue (getAllocator ());
804
838
for (auto *predBlock : predsSkippingBackEdges) {
805
839
SWIFT_DEFER { typeSpanToValue.clear (); };
806
840
@@ -843,7 +877,7 @@ BorrowToDestructureTransform::computeAvailableValues(SILBasicBlock *block) {
843
877
auto iter = typeSpanToValue.find (i);
844
878
assert (iter != typeSpanToValue.end ());
845
879
auto iterValue = iter.value ();
846
- auto iterOffsetSize = TypeOffsetSizePair (iterValue, mmci );
880
+ auto iterOffsetSize = TypeOffsetSizePair (iterValue, getRootValue () );
847
881
if (smallestOffsetSize->first .size == iterOffsetSize.size ) {
848
882
// Our value should already be in the interval map.
849
883
assert (iter.start () == iterOffsetSize.startOffset &&
@@ -954,7 +988,7 @@ BorrowToDestructureTransform::computeAvailableValues(SILBasicBlock *block) {
954
988
SILType offsetType = smallestTypeAvailable[i]->second ;
955
989
auto *phi = block->createPhiArgument (offsetType, OwnershipKind::Owned);
956
990
newValues[i] = phi;
957
- createdPhiArguments.push_back (phi);
991
+ interface. createdPhiArguments .push_back (phi);
958
992
}
959
993
960
994
for (auto *predBlock : predsSkippingBackEdges) {
@@ -1000,28 +1034,30 @@ dumpIntervalMap(IntervalMapAllocator::Map &map) {
1000
1034
}
1001
1035
#endif
1002
1036
1003
- void BorrowToDestructureTransform ::rewriteUses () {
1004
- blocksToUses.setFrozen ();
1037
+ void Implementation ::rewriteUses () {
1038
+ interface. blocksToUses .setFrozen ();
1005
1039
1006
1040
LLVM_DEBUG (llvm::dbgs ()
1007
1041
<< " Performing BorrowToDestructureTransform::rewriteUses()!\n " );
1008
1042
1009
1043
llvm::SmallPtrSet<Operand *, 8 > seenOperands;
1010
- SmallBitVector bitsNeededInBlock (liveness->getNumSubElements ());
1011
- IntervalMapAllocator::Map typeSpanToValue (allocator. get ());
1044
+ SmallBitVector bitsNeededInBlock (interface. liveness ->getNumSubElements ());
1045
+ IntervalMapAllocator::Map typeSpanToValue (getAllocator ());
1012
1046
1013
- auto *fn = mmci ->getFunction ();
1014
- assert (!initialValue);
1047
+ auto *fn = getMarkedValue () ->getFunction ();
1048
+ assert (!interface. initialValue );
1015
1049
{
1016
- auto *next = mmci->getNextInstruction ();
1050
+ // We are always going to copy our root value.
1051
+ auto *next = getRootValue ()->getNextInstruction ();
1017
1052
SILBuilderWithScope builder (next);
1018
- initialValue = builder.createCopyValue (getSafeLoc (next), mmci);
1053
+ interface.initialValue =
1054
+ builder.createCopyValue (getSafeLoc (next), getRootValue ());
1019
1055
}
1020
- assert (initialValue);
1056
+ assert (interface. initialValue );
1021
1057
1022
1058
// Walking each block in RPO order.
1023
- for (auto *block :
1024
- getPostOrderFunctionInfo ()->getReversePostOrder (mmci-> getParent ())) {
1059
+ for (auto *block : getPostOrderFunctionInfo ()-> getReversePostOrder (
1060
+ getRootValue ()->getParentBlock ())) {
1025
1061
SWIFT_DEFER {
1026
1062
bitsNeededInBlock.reset ();
1027
1063
seenOperands.clear ();
@@ -1031,7 +1067,7 @@ void BorrowToDestructureTransform::rewriteUses() {
1031
1067
<< " Visiting block bb" << block->getDebugID () << ' \n ' );
1032
1068
1033
1069
// See if we have any operands that we need to process...
1034
- if (auto operandList = blocksToUses.find (block)) {
1070
+ if (auto operandList = interface. blocksToUses .find (block)) {
1035
1071
// If we do, gather up the bits that we need.
1036
1072
for (auto operand : *operandList) {
1037
1073
auto &subEltSpan = operand.second .subEltSpan ;
@@ -1068,7 +1104,7 @@ void BorrowToDestructureTransform::rewriteUses() {
1068
1104
if (!seenOperands.count (&operand))
1069
1105
continue ;
1070
1106
1071
- auto span = *TypeTreeLeafTypeRange::get (operand.get (), mmci );
1107
+ auto span = *TypeTreeLeafTypeRange::get (operand.get (), getRootValue () );
1072
1108
1073
1109
// All available values in our span should have the same value
1074
1110
// associated with it.
@@ -1150,8 +1186,8 @@ void BorrowToDestructureTransform::rewriteUses() {
1150
1186
1151
1187
// Compute the location in the type of first's type and operand.get()'s
1152
1188
// type.
1153
- TypeOffsetSizePair firstValueOffsetSize (first, mmci );
1154
- TypeOffsetSizePair useOffsetSize (operand.get (), mmci );
1189
+ TypeOffsetSizePair firstValueOffsetSize (first, getRootValue () );
1190
+ TypeOffsetSizePair useOffsetSize (operand.get (), getRootValue () );
1155
1191
1156
1192
LLVM_DEBUG (llvm::dbgs () << " FirstValueTypeOffsetSize: "
1157
1193
<< firstValueOffsetSize << ' \n ' );
@@ -1227,7 +1263,8 @@ void BorrowToDestructureTransform::rewriteUses() {
1227
1263
LLVM_DEBUG (
1228
1264
llvm::dbgs ()
1229
1265
<< " Consuming Operand! Extracting using destructures!\n " );
1230
- SILBuilderWithScope consumeBuilder (inst, &createdDestructures);
1266
+ SILBuilderWithScope consumeBuilder (inst,
1267
+ &interface.createdDestructures );
1231
1268
auto loc = getSafeLoc (inst);
1232
1269
auto iterOffsetSize = firstValueOffsetSize;
1233
1270
SILValue iterValue = first;
@@ -1507,7 +1544,7 @@ bool BorrowToDestructureTransform::transform() {
1507
1544
// Next make sure that any destructure needing instructions are on the
1508
1545
// boundary in a per bit field sensitive manner.
1509
1546
unsigned diagnosticCount = diagnosticEmitter.getDiagnosticCount ();
1510
- checkDestructureUsesOnBoundary ();
1547
+ impl. checkDestructureUsesOnBoundary ();
1511
1548
1512
1549
// If we emitted any diagnostic, break out. We return true since we actually
1513
1550
// succeeded in our processing by finding the error. We only return false if
@@ -1519,7 +1556,7 @@ bool BorrowToDestructureTransform::transform() {
1519
1556
1520
1557
// Then check if we had two consuming uses on the same instruction or a
1521
1558
// consuming/non-consuming use on the same isntruction.
1522
- checkForErrorsOnSameInstruction ();
1559
+ impl. checkForErrorsOnSameInstruction ();
1523
1560
1524
1561
// If we emitted any diagnostic, break out. We return true since we actually
1525
1562
// succeeded in our processing by finding the error. We only return false if
@@ -1532,7 +1569,7 @@ bool BorrowToDestructureTransform::transform() {
1532
1569
// At this point, we know that all of our destructure requiring uses are on
1533
1570
// the boundary of our live range. Now we need to do the rewriting.
1534
1571
blockToAvailableValues.emplace (*liveness);
1535
- rewriteUses ();
1572
+ impl. rewriteUses ();
1536
1573
1537
1574
// Now that we have done our rewritting, we need to do a few cleanups.
1538
1575
cleanup (borrowWorklist);
0 commit comments