Skip to content

Commit 5d1fe77

Browse files
committed
[move-only] Move the rest of the actual computation from the borrowToDestructureTransform driver to the local Implementation.
1 parent c25d58d commit 5d1fe77

File tree

2 files changed

+89
-68
lines changed

2 files changed

+89
-68
lines changed

lib/SILOptimizer/Mandatory/MoveOnlyBorrowToDestructure.h

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -146,25 +146,9 @@ class BorrowToDestructureTransform {
146146
return pofi;
147147
}
148148

149-
/// Once we have gathered up all of our destructure uses and liveness
150-
/// requiring uses, validate that all of our destructure uses are on our
151-
/// boundary. Once we have done this, we know that it is safe to perform our
152-
/// transform.
153-
void checkDestructureUsesOnBoundary() const;
154-
155-
/// Check for cases where we have two consuming uses on the same instruction
156-
/// or a consuming/non-consuming use on the same instruction.
157-
void checkForErrorsOnSameInstruction();
158-
159-
/// Rewrite all of the uses of our borrow on our borrow operand, performing
160-
/// destructures as appropriate.
161-
void rewriteUses();
162-
163149
/// After we have rewritten uses, cleanup the IR by deleting the original
164150
/// borrow/struct_extract/copies and inserting compensating destroy_values.
165151
void cleanup(StackList<BeginBorrowInst *> &borrowWorklist);
166-
167-
AvailableValues &computeAvailableValues(SILBasicBlock *block);
168152
};
169153

170154
} // namespace siloptimizer

lib/SILOptimizer/Mandatory/MoveOnlyBorrowToDestructureTransform.cpp

Lines changed: 89 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,41 @@ struct borrowtodestructure::Implementation {
8787

8888
bool gatherUses(SILValue value);
8989

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+
90106
/// Returns mark_must_check if we are processing borrows or the enum argument
91107
/// if we are processing switch_enum.
92108
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+
}
93125
};
94126

95127
bool Implementation::gatherUses(SILValue value) {
@@ -212,18 +244,15 @@ bool Implementation::gatherUses(SILValue value) {
212244
return true;
213245
}
214246

215-
//===----------------------------------------------------------------------===//
216-
// MARK: Convert Borrow Extracts To Owned Destructures
217-
//===----------------------------------------------------------------------===//
218-
219-
void BorrowToDestructureTransform::checkForErrorsOnSameInstruction() {
247+
void Implementation::checkForErrorsOnSameInstruction() {
220248
// At this point, we have emitted all boundary checks. We also now need to
221249
// check if any of our consuming uses that are on the boundary are used by the
222250
// 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());
225253

226-
for (auto instRangePair : instToInterestingOperandIndexMap.getRange()) {
254+
for (auto instRangePair :
255+
interface.instToInterestingOperandIndexMap.getRange()) {
227256
SWIFT_DEFER { usedBits.reset(); };
228257

229258
// First loop through our uses and handle any consuming twice errors. We
@@ -234,7 +263,8 @@ void BorrowToDestructureTransform::checkForErrorsOnSameInstruction() {
234263
if (!use->isConsuming())
235264
continue;
236265

237-
auto destructureUseSpan = *TypeTreeLeafTypeRange::get(use->get(), mmci);
266+
auto destructureUseSpan =
267+
*TypeTreeLeafTypeRange::get(use->get(), getRootValue());
238268
for (unsigned index : destructureUseSpan.getRange()) {
239269
if (usedBits[index]) {
240270
// If we get that we used the same bit twice, we have an error. We set
@@ -261,7 +291,8 @@ void BorrowToDestructureTransform::checkForErrorsOnSameInstruction() {
261291
if (use->isConsuming())
262292
continue;
263293

264-
auto destructureUseSpan = *TypeTreeLeafTypeRange::get(use->get(), mmci);
294+
auto destructureUseSpan =
295+
*TypeTreeLeafTypeRange::get(use->get(), getRootValue());
265296
for (unsigned index : destructureUseSpan.getRange()) {
266297
if (!usedBits[index])
267298
continue;
@@ -301,18 +332,19 @@ void BorrowToDestructureTransform::checkForErrorsOnSameInstruction() {
301332
if (!use->isConsuming())
302333
continue;
303334

304-
auto destructureUseSpan = *TypeTreeLeafTypeRange::get(use->get(), mmci);
335+
auto destructureUseSpan =
336+
*TypeTreeLeafTypeRange::get(use->get(), getRootValue());
305337
bool emittedError = false;
306338
for (unsigned index : destructureUseSpan.getRange()) {
307339
if (!usedBits[index])
308340
continue;
309341

310342
if (badOperand->isConsuming())
311-
diagnosticEmitter.emitObjectInstConsumesValueTwice(mmci, use,
312-
badOperand);
343+
getDiagnostics().emitObjectInstConsumesValueTwice(getMarkedValue(),
344+
use, badOperand);
313345
else
314-
diagnosticEmitter.emitObjectInstConsumesAndUsesValue(mmci, use,
315-
badOperand);
346+
getDiagnostics().emitObjectInstConsumesAndUsesValue(getMarkedValue(),
347+
use, badOperand);
316348
emittedError = true;
317349
}
318350

@@ -323,19 +355,21 @@ void BorrowToDestructureTransform::checkForErrorsOnSameInstruction() {
323355
}
324356
}
325357

326-
void BorrowToDestructureTransform::checkDestructureUsesOnBoundary() const {
358+
void Implementation::checkDestructureUsesOnBoundary() const {
327359
LLVM_DEBUG(llvm::dbgs() << "Checking destructure uses on boundary!\n");
328360

329361
// Now that we have found all of our destructure needing uses and liveness
330362
// needing uses, make sure that none of our destructure needing uses are
331363
// within our boundary. If so, we have an automatic error since we have a
332364
// use-after-free.
333-
for (auto *use : destructureNeedingUses) {
365+
for (auto *use : interface.destructureNeedingUses) {
334366
LLVM_DEBUG(llvm::dbgs()
335367
<< " DestructureNeedingUse: " << *use->getUser());
336368

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)) {
339373
LLVM_DEBUG(llvm::dbgs()
340374
<< " On boundary or within boundary! No error!\n");
341375
continue;
@@ -351,10 +385,10 @@ void BorrowToDestructureTransform::checkDestructureUsesOnBoundary() const {
351385
// uses.
352386
LLVM_DEBUG(llvm::dbgs() << " Within boundary! Emitting error!\n");
353387
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);
358392
}
359393
}
360394

@@ -613,15 +647,14 @@ static void dumpSmallestTypeAvailable(
613647
/// ensures that we match at the source level the assumption by users that they
614648
/// can use entire valid parts as late as possible. If we were to do it earlier
615649
/// we would emit errors too early.
616-
AvailableValues &
617-
BorrowToDestructureTransform::computeAvailableValues(SILBasicBlock *block) {
650+
AvailableValues &Implementation::computeAvailableValues(SILBasicBlock *block) {
618651
LLVM_DEBUG(llvm::dbgs() << " Computing Available Values For bb"
619652
<< block->getDebugID() << '\n');
620653

621654
// First grab our block. If we already have state for the block, just return
622655
// its available values. We already computed the available values and
623656
// potentially updated it with new destructured values for our block.
624-
auto pair = blockToAvailableValues->get(block);
657+
auto pair = interface.blockToAvailableValues->get(block);
625658
if (!pair.second) {
626659
LLVM_DEBUG(llvm::dbgs()
627660
<< " Already have values! Returning them!\n");
@@ -641,11 +674,11 @@ BorrowToDestructureTransform::computeAvailableValues(SILBasicBlock *block) {
641674
// ensure that from an OSSA perspective any any destructures we insert are
642675
// independent of any other copies. We assume that OSSA canonicalization will
643676
// 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()) {
645678
LLVM_DEBUG(llvm::dbgs()
646679
<< " In initial block, setting to initial value!\n");
647680
for (unsigned i : indices(newValues))
648-
newValues[i] = initialValue;
681+
newValues[i] = interface.initialValue;
649682
LLVM_DEBUG(newValues.print(llvm::dbgs(), " "));
650683
return newValues;
651684
}
@@ -745,7 +778,7 @@ BorrowToDestructureTransform::computeAvailableValues(SILBasicBlock *block) {
745778
for (unsigned i : range(predAvailableValues.size())) {
746779
if (predAvailableValues[i])
747780
smallestTypeAvailable.push_back(
748-
{{TypeOffsetSizePair(predAvailableValues[i], mmci),
781+
{{TypeOffsetSizePair(predAvailableValues[i], getRootValue()),
749782
predAvailableValues[i]->getType()}});
750783
else
751784
smallestTypeAvailable.emplace_back(None);
@@ -779,7 +812,8 @@ BorrowToDestructureTransform::computeAvailableValues(SILBasicBlock *block) {
779812
// the NOTE above), we know that if subElt has a smaller size than our
780813
// accumulator, then it must be further down the type tree from our
781814
// accumulator.
782-
auto offsetSize = TypeOffsetSizePair(predAvailableValues[i], mmci);
815+
auto offsetSize =
816+
TypeOffsetSizePair(predAvailableValues[i], getRootValue());
783817
if (smallestTypeAvailable[i]->first.size > offsetSize.size)
784818
smallestTypeAvailable[i] = {offsetSize,
785819
predAvailableValues[i]->getType()};
@@ -800,7 +834,7 @@ BorrowToDestructureTransform::computeAvailableValues(SILBasicBlock *block) {
800834
<< " Destructuring available values in preds to smallest size for bb"
801835
<< block->getDebugID() << '\n');
802836
auto *fn = block->getFunction();
803-
IntervalMapAllocator::Map typeSpanToValue(allocator.get());
837+
IntervalMapAllocator::Map typeSpanToValue(getAllocator());
804838
for (auto *predBlock : predsSkippingBackEdges) {
805839
SWIFT_DEFER { typeSpanToValue.clear(); };
806840

@@ -843,7 +877,7 @@ BorrowToDestructureTransform::computeAvailableValues(SILBasicBlock *block) {
843877
auto iter = typeSpanToValue.find(i);
844878
assert(iter != typeSpanToValue.end());
845879
auto iterValue = iter.value();
846-
auto iterOffsetSize = TypeOffsetSizePair(iterValue, mmci);
880+
auto iterOffsetSize = TypeOffsetSizePair(iterValue, getRootValue());
847881
if (smallestOffsetSize->first.size == iterOffsetSize.size) {
848882
// Our value should already be in the interval map.
849883
assert(iter.start() == iterOffsetSize.startOffset &&
@@ -954,7 +988,7 @@ BorrowToDestructureTransform::computeAvailableValues(SILBasicBlock *block) {
954988
SILType offsetType = smallestTypeAvailable[i]->second;
955989
auto *phi = block->createPhiArgument(offsetType, OwnershipKind::Owned);
956990
newValues[i] = phi;
957-
createdPhiArguments.push_back(phi);
991+
interface.createdPhiArguments.push_back(phi);
958992
}
959993

960994
for (auto *predBlock : predsSkippingBackEdges) {
@@ -1000,28 +1034,30 @@ dumpIntervalMap(IntervalMapAllocator::Map &map) {
10001034
}
10011035
#endif
10021036

1003-
void BorrowToDestructureTransform::rewriteUses() {
1004-
blocksToUses.setFrozen();
1037+
void Implementation::rewriteUses() {
1038+
interface.blocksToUses.setFrozen();
10051039

10061040
LLVM_DEBUG(llvm::dbgs()
10071041
<< "Performing BorrowToDestructureTransform::rewriteUses()!\n");
10081042

10091043
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());
10121046

1013-
auto *fn = mmci->getFunction();
1014-
assert(!initialValue);
1047+
auto *fn = getMarkedValue()->getFunction();
1048+
assert(!interface.initialValue);
10151049
{
1016-
auto *next = mmci->getNextInstruction();
1050+
// We are always going to copy our root value.
1051+
auto *next = getRootValue()->getNextInstruction();
10171052
SILBuilderWithScope builder(next);
1018-
initialValue = builder.createCopyValue(getSafeLoc(next), mmci);
1053+
interface.initialValue =
1054+
builder.createCopyValue(getSafeLoc(next), getRootValue());
10191055
}
1020-
assert(initialValue);
1056+
assert(interface.initialValue);
10211057

10221058
// Walking each block in RPO order.
1023-
for (auto *block :
1024-
getPostOrderFunctionInfo()->getReversePostOrder(mmci->getParent())) {
1059+
for (auto *block : getPostOrderFunctionInfo()->getReversePostOrder(
1060+
getRootValue()->getParentBlock())) {
10251061
SWIFT_DEFER {
10261062
bitsNeededInBlock.reset();
10271063
seenOperands.clear();
@@ -1031,7 +1067,7 @@ void BorrowToDestructureTransform::rewriteUses() {
10311067
<< "Visiting block bb" << block->getDebugID() << '\n');
10321068

10331069
// 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)) {
10351071
// If we do, gather up the bits that we need.
10361072
for (auto operand : *operandList) {
10371073
auto &subEltSpan = operand.second.subEltSpan;
@@ -1068,7 +1104,7 @@ void BorrowToDestructureTransform::rewriteUses() {
10681104
if (!seenOperands.count(&operand))
10691105
continue;
10701106

1071-
auto span = *TypeTreeLeafTypeRange::get(operand.get(), mmci);
1107+
auto span = *TypeTreeLeafTypeRange::get(operand.get(), getRootValue());
10721108

10731109
// All available values in our span should have the same value
10741110
// associated with it.
@@ -1150,8 +1186,8 @@ void BorrowToDestructureTransform::rewriteUses() {
11501186

11511187
// Compute the location in the type of first's type and operand.get()'s
11521188
// type.
1153-
TypeOffsetSizePair firstValueOffsetSize(first, mmci);
1154-
TypeOffsetSizePair useOffsetSize(operand.get(), mmci);
1189+
TypeOffsetSizePair firstValueOffsetSize(first, getRootValue());
1190+
TypeOffsetSizePair useOffsetSize(operand.get(), getRootValue());
11551191

11561192
LLVM_DEBUG(llvm::dbgs() << " FirstValueTypeOffsetSize: "
11571193
<< firstValueOffsetSize << '\n');
@@ -1227,7 +1263,8 @@ void BorrowToDestructureTransform::rewriteUses() {
12271263
LLVM_DEBUG(
12281264
llvm::dbgs()
12291265
<< " Consuming Operand! Extracting using destructures!\n");
1230-
SILBuilderWithScope consumeBuilder(inst, &createdDestructures);
1266+
SILBuilderWithScope consumeBuilder(inst,
1267+
&interface.createdDestructures);
12311268
auto loc = getSafeLoc(inst);
12321269
auto iterOffsetSize = firstValueOffsetSize;
12331270
SILValue iterValue = first;
@@ -1507,7 +1544,7 @@ bool BorrowToDestructureTransform::transform() {
15071544
// Next make sure that any destructure needing instructions are on the
15081545
// boundary in a per bit field sensitive manner.
15091546
unsigned diagnosticCount = diagnosticEmitter.getDiagnosticCount();
1510-
checkDestructureUsesOnBoundary();
1547+
impl.checkDestructureUsesOnBoundary();
15111548

15121549
// If we emitted any diagnostic, break out. We return true since we actually
15131550
// succeeded in our processing by finding the error. We only return false if
@@ -1519,7 +1556,7 @@ bool BorrowToDestructureTransform::transform() {
15191556

15201557
// Then check if we had two consuming uses on the same instruction or a
15211558
// consuming/non-consuming use on the same isntruction.
1522-
checkForErrorsOnSameInstruction();
1559+
impl.checkForErrorsOnSameInstruction();
15231560

15241561
// If we emitted any diagnostic, break out. We return true since we actually
15251562
// succeeded in our processing by finding the error. We only return false if
@@ -1532,7 +1569,7 @@ bool BorrowToDestructureTransform::transform() {
15321569
// At this point, we know that all of our destructure requiring uses are on
15331570
// the boundary of our live range. Now we need to do the rewriting.
15341571
blockToAvailableValues.emplace(*liveness);
1535-
rewriteUses();
1572+
impl.rewriteUses();
15361573

15371574
// Now that we have done our rewritting, we need to do a few cleanups.
15381575
cleanup(borrowWorklist);

0 commit comments

Comments
 (0)