Skip to content

Commit e70a722

Browse files
committed
[move-only] Integrate BorrowToDestructureTransform into the AddressChecker so we handle load [copy] switch_enum.
1 parent f487764 commit e70a722

7 files changed

+87
-20
lines changed

lib/SILOptimizer/Mandatory/MoveOnlyAddressChecker.cpp

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@
156156
#include "llvm/Support/Debug.h"
157157
#include "llvm/Support/ErrorHandling.h"
158158

159+
#include "MoveOnlyBorrowToDestructure.h"
159160
#include "MoveOnlyDiagnostics.h"
160161
#include "MoveOnlyObjectChecker.h"
161162

@@ -866,9 +867,15 @@ struct MoveOnlyChecker {
866867
/// Information about destroys that we use when inserting destroys.
867868
ConsumeInfo consumes;
868869

870+
/// Allocator used by the BorrowToDestructureTransform.
871+
borrowtodestructure::IntervalMapAllocator allocator;
872+
873+
/// PostOrderAnalysis used by the BorrowToDestructureTransform.
874+
PostOrderAnalysis *poa;
875+
869876
MoveOnlyChecker(SILFunction *fn, DeadEndBlocks *deBlocks,
870-
DominanceInfo *domTree)
871-
: fn(fn), deleter(), canonicalizer(), diagnosticEmitter() {
877+
DominanceInfo *domTree, PostOrderAnalysis *poa)
878+
: fn(fn), deleter(), canonicalizer(), diagnosticEmitter(), poa(poa) {
872879
deleter.setCallbacks(std::move(
873880
InstModCallbacks().onDelete([&](SILInstruction *instToDelete) {
874881
if (auto *mvi = dyn_cast<MarkMustCheckInst>(instToDelete))
@@ -1121,6 +1128,31 @@ bool GatherUsesVisitor::visitUse(Operand *op, AccessUseType useTy) {
11211128
li->getOwnershipQualifier() == LoadOwnershipQualifier::Take) {
11221129
SWIFT_DEFER { moveChecker.canonicalizer.clear(); };
11231130

1131+
// Before we do anything, run the borrow to destructure transform in case
1132+
// we have a switch_enum user.
1133+
unsigned numDiagnostics =
1134+
moveChecker.diagnosticEmitter.getDiagnosticCount();
1135+
BorrowToDestructureTransform borrowToDestructure(
1136+
moveChecker.allocator, markedValue, li, moveChecker.diagnosticEmitter,
1137+
moveChecker.poa);
1138+
if (!borrowToDestructure.transform()) {
1139+
assert(moveChecker.diagnosticEmitter
1140+
.didEmitCheckerDoesntUnderstandDiagnostic());
1141+
LLVM_DEBUG(llvm::dbgs()
1142+
<< "Failed to perform borrow to destructure transform!\n");
1143+
emittedEarlyDiagnostic = true;
1144+
return false;
1145+
}
1146+
1147+
// If we emitted an error diagnostic, do not transform further and instead
1148+
// mark that we emitted an early diagnostic and return true.
1149+
if (numDiagnostics !=
1150+
moveChecker.diagnosticEmitter.getDiagnosticCount()) {
1151+
LLVM_DEBUG(llvm::dbgs() << "Emitting borrow to destructure error!\n");
1152+
emittedEarlyDiagnostic = true;
1153+
return true;
1154+
}
1155+
11241156
// Canonicalize the lifetime of the load [take], load [copy].
11251157
moveChecker.changed |= moveChecker.canonicalizer.canonicalize(li);
11261158

@@ -1558,6 +1590,19 @@ void MoveOnlyChecker::cleanupAfterEmittingDiagnostic() {
15581590
changed = true;
15591591
}
15601592
}
1593+
1594+
// Convert any copy_value of move_only type to explicit copy value.
1595+
if (auto *cvi = dyn_cast<CopyValueInst>(inst)) {
1596+
if (!cvi->getOperand()->getType().isMoveOnly())
1597+
continue;
1598+
SILBuilderWithScope b(cvi);
1599+
auto *expCopy =
1600+
b.createExplicitCopyValue(cvi->getLoc(), cvi->getOperand());
1601+
cvi->replaceAllUsesWith(expCopy);
1602+
cvi->eraseFromParent();
1603+
changed = true;
1604+
continue;
1605+
}
15611606
}
15621607
}
15631608
}
@@ -1982,8 +2027,10 @@ class MoveOnlyCheckerPass : public SILFunctionTransform {
19822027
auto *dominanceAnalysis = getAnalysis<DominanceAnalysis>();
19832028
DominanceInfo *domTree = dominanceAnalysis->get(fn);
19842029
auto *deAnalysis = getAnalysis<DeadEndBlocksAnalysis>()->get(fn);
2030+
auto *poa = getAnalysis<PostOrderAnalysis>();
19852031

1986-
if (MoveOnlyChecker(getFunction(), deAnalysis, domTree).checkFunction()) {
2032+
if (MoveOnlyChecker(getFunction(), deAnalysis, domTree, poa)
2033+
.checkFunction()) {
19872034
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
19882035
}
19892036

lib/SILOptimizer/Mandatory/MoveOnlyBorrowToDestructure.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class BorrowToDestructureTransform {
5959

6060
IntervalMapAllocator &allocator;
6161
MarkMustCheckInst *mmci;
62+
SILValue rootValue;
6263
DiagnosticEmitter &diagnosticEmitter;
6364
PostOrderAnalysis *poa;
6465
PostOrderFunctionInfo *pofi = nullptr;
@@ -67,11 +68,11 @@ class BorrowToDestructureTransform {
6768

6869
public:
6970
BorrowToDestructureTransform(IntervalMapAllocator &allocator,
70-
MarkMustCheckInst *mmci,
71+
MarkMustCheckInst *mmci, SILValue rootValue,
7172
DiagnosticEmitter &diagnosticEmitter,
7273
PostOrderAnalysis *poa)
73-
: allocator(allocator), mmci(mmci), diagnosticEmitter(diagnosticEmitter),
74-
poa(poa) {}
74+
: allocator(allocator), mmci(mmci), rootValue(rootValue),
75+
diagnosticEmitter(diagnosticEmitter), poa(poa) {}
7576

7677
bool transform();
7778

lib/SILOptimizer/Mandatory/MoveOnlyBorrowToDestructureTransform.cpp

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,7 +1523,7 @@ void Implementation::cleanup() {
15231523
///
15241524
/// Returns false if we found an escape and thus cannot process. It is assumed
15251525
/// that the caller will fail in such a case.
1526-
static bool gatherBorrows(MarkMustCheckInst *mmci,
1526+
static bool gatherBorrows(SILValue rootValue,
15271527
StackList<BeginBorrowInst *> &borrowWorklist) {
15281528
// If we have a no implicit copy mark_must_check, we do not run the borrow to
15291529
// destructure transform since:
@@ -1534,15 +1534,16 @@ static bool gatherBorrows(MarkMustCheckInst *mmci,
15341534
// 2. If we do not have a move only type, then we know that all fields that we
15351535
// access directly and would cause a need to destructure must be copyable,
15361536
// so no transformation/error is needed.
1537-
if (mmci->getType().isMoveOnlyWrapped()) {
1538-
LLVM_DEBUG(llvm::dbgs() << "Skipping move only wrapped inst: " << *mmci);
1537+
if (rootValue->getType().isMoveOnlyWrapped()) {
1538+
LLVM_DEBUG(llvm::dbgs()
1539+
<< "Skipping move only wrapped inst: " << *rootValue);
15391540
return true;
15401541
}
15411542

1542-
LLVM_DEBUG(llvm::dbgs() << "Searching for borrows for inst: " << *mmci);
1543+
LLVM_DEBUG(llvm::dbgs() << "Searching for borrows for inst: " << *rootValue);
15431544

1544-
StackList<Operand *> worklist(mmci->getFunction());
1545-
for (auto *op : mmci->getUses())
1545+
StackList<Operand *> worklist(rootValue->getFunction());
1546+
for (auto *op : rootValue->getUses())
15461547
worklist.push_back(op);
15471548

15481549
while (!worklist.empty()) {
@@ -1728,8 +1729,10 @@ bool BorrowToDestructureTransform::transform() {
17281729

17291730
// If we failed to gather borrows due to the transform not understanding part
17301731
// of the SIL, fail and return false.
1731-
if (!gatherBorrows(mmci, borrowWorklist))
1732+
if (!gatherBorrows(rootValue, borrowWorklist)) {
1733+
diagnosticEmitter.emitCheckerDoesntUnderstandDiagnostic(mmci);
17321734
return false;
1735+
}
17331736

17341737
// If we do not have any borrows to process, return true early to show we
17351738
// succeeded in processing.
@@ -1742,8 +1745,10 @@ bool BorrowToDestructureTransform::transform() {
17421745
SmallVector<SwitchEnumInst *, 8> switchEnumWorklist;
17431746
for (auto *borrow : borrowWorklist) {
17441747
// Attempt to gather the switch enums and if we fail, return false.
1745-
if (!gatherSwitchEnum(borrow, switchEnumWorklist))
1748+
if (!gatherSwitchEnum(borrow, switchEnumWorklist)) {
1749+
diagnosticEmitter.emitCheckerDoesntUnderstandDiagnostic(mmci);
17461750
return false;
1751+
}
17471752
}
17481753

17491754
// Now perform the checking of our switch_enum, working in stack order.
@@ -1863,15 +1868,23 @@ bool BorrowToDestructureTransform::transform() {
18631868
}
18641869
}
18651870

1871+
// At this point, we have correct OSSA SIL for our switch_enums. Check if for
1872+
// any of our switch_enum we emitted a we don't understand diagnostic... in
1873+
// such a case, exit before we do further work.
1874+
if (diagnosticEmitter.didEmitCheckerDoesntUnderstandDiagnostic())
1875+
return false;
1876+
18661877
// Now that we have handled our switch_enum we need to handle our
18671878
// borrows... begin by gathering uses. Return false if we saw something that
18681879
// we did not understand.
18691880
SmallVector<SILBasicBlock *, 8> discoveredBlocks;
18701881
Implementation impl(*this, discoveredBlocks);
1871-
impl.init(mmci);
1882+
impl.init(rootValue);
18721883
for (auto *bbi : borrowWorklist) {
1873-
if (!impl.gatherUses(bbi))
1884+
if (!impl.gatherUses(bbi)) {
1885+
diagnosticEmitter.emitCheckerDoesntUnderstandDiagnostic(mmci);
18741886
return false;
1887+
}
18751888
}
18761889

18771890
// Next make sure that any destructure needing instructions are on the

lib/SILOptimizer/Mandatory/MoveOnlyBorrowToDestructureTransformTester.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ static bool runTransform(SILFunction *fn,
5555
auto *mmci = moveIntroducersToProcess.back();
5656
moveIntroducersToProcess = moveIntroducersToProcess.drop_back();
5757

58-
BorrowToDestructureTransform transform(allocator, mmci, diagnosticEmitter,
59-
poa);
58+
BorrowToDestructureTransform transform(allocator, mmci, mmci,
59+
diagnosticEmitter, poa);
6060
transform.transform();
6161
madeChange = true;
6262
}

lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ void DiagnosticEmitter::emitCheckerDoesntUnderstandDiagnostic(
102102
diag::sil_moveonlychecker_not_understand_moveonly);
103103
}
104104
registerDiagnosticEmitted(markedValue);
105+
emittedCheckerDoesntUnderstandDiagnostic = true;
105106
}
106107

107108
//===----------------------------------------------------------------------===//

lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ class DiagnosticEmitter {
5050
/// diagnosics while running a callee.
5151
unsigned diagnosticCount = 0;
5252

53+
bool emittedCheckerDoesntUnderstandDiagnostic = false;
54+
5355
public:
5456
void init(SILFunction *inputFn, OSSACanonicalizer *inputCanonicalizer) {
5557
fn = inputFn;
@@ -65,6 +67,9 @@ class DiagnosticEmitter {
6567
}
6668

6769
unsigned getDiagnosticCount() const { return diagnosticCount; }
70+
bool didEmitCheckerDoesntUnderstandDiagnostic() const {
71+
return emittedCheckerDoesntUnderstandDiagnostic;
72+
}
6873

6974
void emitCheckerDoesntUnderstandDiagnostic(MarkMustCheckInst *markedValue);
7075
void emitObjectGuaranteedDiagnostic(MarkMustCheckInst *markedValue);

lib/SILOptimizer/Mandatory/MoveOnlyObjectChecker.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,8 +423,8 @@ struct MoveOnlyChecker {
423423
bool MoveOnlyChecker::convertBorrowExtractsToOwnedDestructures(
424424
MarkMustCheckInst *mmci, DiagnosticEmitter &diagnosticEmitter,
425425
DominanceInfo *domTree, PostOrderAnalysis *poa) {
426-
BorrowToDestructureTransform transform(allocator, mmci, diagnosticEmitter,
427-
poa);
426+
BorrowToDestructureTransform transform(allocator, mmci, mmci,
427+
diagnosticEmitter, poa);
428428
if (!transform.transform()) {
429429
LLVM_DEBUG(llvm::dbgs()
430430
<< "Failed to perform borrow to destructure transform!\n");

0 commit comments

Comments
 (0)