Skip to content

Commit e709d94

Browse files
authored
Merge pull request #62631 from gottesmm/pr-d0e166cdd030c3826f8abfc0081e61545623320f
[move-only] Make sure that we convert copy_value/load [copy] move only to their after error variant if we error early.
2 parents 758d98a + b80984c commit e709d94

File tree

2 files changed

+105
-64
lines changed

2 files changed

+105
-64
lines changed

lib/SILOptimizer/Mandatory/MoveOnlyAddressChecker.cpp

Lines changed: 59 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,17 @@ struct MoveOnlyChecker {
391391
/// [noimplicitcopy]. If we find one that does not fit a pattern that we
392392
/// understand, emit an error diagnostic telling the programmer that the move
393393
/// checker did not know how to recognize this code pattern.
394-
void searchForCandidateMarkMustChecks();
394+
///
395+
/// Returns true if we emitted a diagnostic. Returns false otherwise.
396+
bool searchForCandidateMarkMustChecks();
397+
398+
/// After we have emitted a diagnostic, we need to clean up the instruction
399+
/// stream by converting /all/ copies of move only typed things to use
400+
/// explicit_copy_value so that we maintain the SIL invariant that in
401+
/// canonical SIL move only types are not copied by normal copies.
402+
///
403+
/// Returns true if we actually changed any instructions.
404+
void cleanupAfterEmittingDiagnostic();
395405

396406
/// Emits an error diagnostic for \p markedValue.
397407
void performObjectCheck(MarkMustCheckInst *markedValue);
@@ -1334,7 +1344,44 @@ bool GlobalDataflow::compute() {
13341344
// MARK: Main Pass Implementation
13351345
//===----------------------------------------------------------------------===//
13361346

1337-
void MoveOnlyChecker::searchForCandidateMarkMustChecks() {
1347+
void MoveOnlyChecker::cleanupAfterEmittingDiagnostic() {
1348+
for (auto &block : *fn) {
1349+
for (auto ii = block.begin(), ie = block.end(); ii != ie;) {
1350+
auto *inst = &*ii;
1351+
++ii;
1352+
1353+
// Convert load [copy] -> load_borrow + explicit_copy_value.
1354+
if (auto *li = dyn_cast<LoadInst>(inst)) {
1355+
if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Copy) {
1356+
SILBuilderWithScope builder(li);
1357+
auto *lbi = builder.createLoadBorrow(li->getLoc(), li->getOperand());
1358+
auto *cvi = builder.createExplicitCopyValue(li->getLoc(), lbi);
1359+
builder.createEndBorrow(li->getLoc(), lbi);
1360+
li->replaceAllUsesWith(cvi);
1361+
li->eraseFromParent();
1362+
changed = true;
1363+
}
1364+
}
1365+
1366+
// Convert copy_addr !take of src to its explicit value form so we don't
1367+
// error.
1368+
if (auto *copyAddr = dyn_cast<CopyAddrInst>(inst)) {
1369+
if (!copyAddr->isTakeOfSrc()) {
1370+
SILBuilderWithScope builder(copyAddr);
1371+
builder.createExplicitCopyAddr(
1372+
copyAddr->getLoc(), copyAddr->getSrc(), copyAddr->getDest(),
1373+
IsTake_t(copyAddr->isTakeOfSrc()),
1374+
IsInitialization_t(copyAddr->isInitializationOfDest()));
1375+
copyAddr->eraseFromParent();
1376+
changed = true;
1377+
}
1378+
}
1379+
}
1380+
}
1381+
}
1382+
1383+
bool MoveOnlyChecker::searchForCandidateMarkMustChecks() {
1384+
bool emittedDiagnostic = false;
13381385
for (auto &block : *fn) {
13391386
for (auto ii = block.begin(), ie = block.end(); ii != ie;) {
13401387
auto *mmci = dyn_cast<MarkMustCheckInst>(&*ii);
@@ -1351,6 +1398,7 @@ void MoveOnlyChecker::searchForCandidateMarkMustChecks() {
13511398
llvm::dbgs()
13521399
<< "Early emitting diagnostic for unsupported alloc box!\n");
13531400
diagnosticEmitter.emitCheckerDoesntUnderstandDiagnostic(mmci);
1401+
emittedDiagnostic = true;
13541402
continue;
13551403
}
13561404

@@ -1360,6 +1408,7 @@ void MoveOnlyChecker::searchForCandidateMarkMustChecks() {
13601408
llvm::dbgs()
13611409
<< "Early emitting diagnostic for unsupported alloc box!\n");
13621410
diagnosticEmitter.emitCheckerDoesntUnderstandDiagnostic(mmci);
1411+
emittedDiagnostic = true;
13631412
continue;
13641413
}
13651414
}
@@ -1368,6 +1417,7 @@ void MoveOnlyChecker::searchForCandidateMarkMustChecks() {
13681417
moveIntroducersToProcess.insert(mmci);
13691418
}
13701419
}
1420+
return emittedDiagnostic;
13711421
}
13721422

13731423
bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
@@ -1566,15 +1616,18 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
15661616
bool MoveOnlyChecker::check() {
15671617
// First search for candidates to process and emit diagnostics on any
15681618
// mark_must_check [noimplicitcopy] we didn't recognize.
1569-
searchForCandidateMarkMustChecks();
1619+
bool emittedDiagnostic = searchForCandidateMarkMustChecks();
15701620

15711621
// If we didn't find any introducers to check, just return changed.
15721622
//
15731623
// NOTE: changed /can/ be true here if we had any mark_must_check
15741624
// [noimplicitcopy] that we didn't understand and emitting a diagnostic upon
15751625
// and then deleting.
1576-
if (moveIntroducersToProcess.empty())
1626+
if (moveIntroducersToProcess.empty()) {
1627+
if (emittedDiagnostic)
1628+
cleanupAfterEmittingDiagnostic();
15771629
return changed;
1630+
}
15781631

15791632
for (auto *markedValue : moveIntroducersToProcess) {
15801633
LLVM_DEBUG(llvm::dbgs() << "Visiting: " << *markedValue);
@@ -1587,7 +1640,7 @@ bool MoveOnlyChecker::check() {
15871640
diagnosticEmitter.emitCheckerDoesntUnderstandDiagnostic(markedValue);
15881641
}
15891642
}
1590-
bool emittedDiagnostic = diagnosticEmitter.emittedAnyDiagnostics();
1643+
emittedDiagnostic = diagnosticEmitter.emittedAnyDiagnostics();
15911644

15921645
// Ok, now that we have performed our checks, we need to eliminate all mark
15931646
// must check inst since it is invalid for these to be in canonical SIL and
@@ -1608,40 +1661,7 @@ bool MoveOnlyChecker::check() {
16081661
// It is also ok that we use a little more compile time and go over the
16091662
// function again, since we are going to fail the compilation and not codegen.
16101663
if (emittedDiagnostic) {
1611-
for (auto &block : *fn) {
1612-
for (auto ii = block.begin(), ie = block.end(); ii != ie;) {
1613-
auto *inst = &*ii;
1614-
++ii;
1615-
1616-
// Convert load [copy] -> load_borrow + explicit_copy_value.
1617-
if (auto *li = dyn_cast<LoadInst>(inst)) {
1618-
if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Copy) {
1619-
SILBuilderWithScope builder(li);
1620-
auto *lbi =
1621-
builder.createLoadBorrow(li->getLoc(), li->getOperand());
1622-
auto *cvi = builder.createExplicitCopyValue(li->getLoc(), lbi);
1623-
builder.createEndBorrow(li->getLoc(), lbi);
1624-
li->replaceAllUsesWith(cvi);
1625-
li->eraseFromParent();
1626-
changed = true;
1627-
}
1628-
}
1629-
1630-
// Convert copy_addr !take of src to its explicit value form so we don't
1631-
// error.
1632-
if (auto *copyAddr = dyn_cast<CopyAddrInst>(inst)) {
1633-
if (!copyAddr->isTakeOfSrc()) {
1634-
SILBuilderWithScope builder(copyAddr);
1635-
builder.createExplicitCopyAddr(
1636-
copyAddr->getLoc(), copyAddr->getSrc(), copyAddr->getDest(),
1637-
IsTake_t(copyAddr->isTakeOfSrc()),
1638-
IsInitialization_t(copyAddr->isInitializationOfDest()));
1639-
copyAddr->eraseFromParent();
1640-
changed = true;
1641-
}
1642-
}
1643-
}
1644-
}
1664+
cleanupAfterEmittingDiagnostic();
16451665
}
16461666

16471667
return changed;

lib/SILOptimizer/Mandatory/MoveOnlyObjectChecker.cpp

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,39 @@ struct MoveOnlyChecker {
7373

7474
bool check(NonLocalAccessBlockAnalysis *accessBlockAnalysis,
7575
DominanceInfo *domTree);
76+
77+
/// After we have emitted a diagnostic, we need to clean up the instruction
78+
/// stream by converting /all/ copies of move only typed things to use
79+
/// explicit_copy_value so that we maintain the SIL invariant that in
80+
/// canonical SIL move only types are not copied by normal copies.
81+
///
82+
/// Returns true if we actually changed any instructions.
83+
bool cleanupAfterEmittingDiagnostic();
7684
};
7785

7886
} // namespace
7987

88+
bool MoveOnlyChecker::cleanupAfterEmittingDiagnostic() {
89+
bool changed = false;
90+
for (auto &block : *fn) {
91+
for (auto ii = block.begin(), ie = block.end(); ii != ie;) {
92+
auto *cvi = dyn_cast<CopyValueInst>(&*ii);
93+
++ii;
94+
95+
if (!cvi || !cvi->getOperand()->getType().isMoveOnlyWrapped())
96+
continue;
97+
98+
SILBuilderWithScope b(cvi);
99+
auto *expCopy =
100+
b.createExplicitCopyValue(cvi->getLoc(), cvi->getOperand());
101+
cvi->replaceAllUsesWith(expCopy);
102+
cvi->eraseFromParent();
103+
changed = true;
104+
}
105+
}
106+
return changed;
107+
}
108+
80109
bool MoveOnlyChecker::searchForCandidateMarkMustChecks(
81110
DiagnosticEmitter &emitter) {
82111
bool changed = false;
@@ -296,15 +325,22 @@ bool MoveOnlyChecker::check(NonLocalAccessBlockAnalysis *accessBlockAnalysis,
296325

297326
// First search for candidates to process and emit diagnostics on any
298327
// mark_must_check [noimplicitcopy] we didn't recognize.
299-
changed |= searchForCandidateMarkMustChecks(diagnosticEmitter);
328+
bool emittedDiagnostic = searchForCandidateMarkMustChecks(diagnosticEmitter);
300329

301-
// If we didn't find any introducers to check, just return changed.
330+
// If we didn't find any introducers to check, just return if we emitted an
331+
// error (which is the only way we emitted a change to the instruction
332+
// stream).
302333
//
303334
// NOTE: changed /can/ be true here if we had any mark_must_check
304335
// [noimplicitcopy] that we didn't understand and emitting a diagnostic upon
305336
// and then deleting.
306-
if (moveIntroducersToProcess.empty())
307-
return changed;
337+
if (moveIntroducersToProcess.empty()) {
338+
if (emittedDiagnostic) {
339+
cleanupAfterEmittingDiagnostic();
340+
return true;
341+
}
342+
return false;
343+
}
308344

309345
auto moveIntroducers = llvm::makeArrayRef(moveIntroducersToProcess.begin(),
310346
moveIntroducersToProcess.end());
@@ -345,7 +381,7 @@ bool MoveOnlyChecker::check(NonLocalAccessBlockAnalysis *accessBlockAnalysis,
345381
diagnosticEmitter.emitObjectOwnedDiagnostic(markedValue);
346382
}
347383

348-
bool emittedDiagnostic = diagnosticEmitter.emittedAnyDiagnostics();
384+
emittedDiagnostic = diagnosticEmitter.emittedAnyDiagnostics();
349385

350386
// Ok, we have success. All of our marker instructions were proven as safe or
351387
// we emitted a diagnostic. Now we need to clean up the IR by eliminating our
@@ -390,30 +426,15 @@ bool MoveOnlyChecker::check(NonLocalAccessBlockAnalysis *accessBlockAnalysis,
390426
}
391427

392428
// Once we have finished processing, if we emitted any diagnostics, then we
393-
// may have copy_value of @moveOnly typed values. This is not valid in
394-
// Canonical SIL, so we need to ensure that those copy_value become
395-
// explicit_copy_value. This is ok to do since we are already going to fail
396-
// the compilation and just are trying to maintain SIL invariants.
429+
// may have copy_value of move only and @moveOnly wrapped type values. This is
430+
// not valid in Canonical SIL, so we need to ensure that those copy_value
431+
// become explicit_copy_value. This is ok to do since we are already going to
432+
// fail the compilation and just are trying to maintain SIL invariants.
397433
//
398434
// It is also ok that we use a little more compile time and go over the
399435
// function again, since we are going to fail the compilation and not codegen.
400436
if (emittedDiagnostic) {
401-
for (auto &block : *fn) {
402-
for (auto ii = block.begin(), ie = block.end(); ii != ie;) {
403-
auto *cvi = dyn_cast<CopyValueInst>(&*ii);
404-
++ii;
405-
406-
if (!cvi || !cvi->getOperand()->getType().isMoveOnlyWrapped())
407-
continue;
408-
409-
SILBuilderWithScope b(cvi);
410-
auto *expCopy =
411-
b.createExplicitCopyValue(cvi->getLoc(), cvi->getOperand());
412-
cvi->replaceAllUsesWith(expCopy);
413-
cvi->eraseFromParent();
414-
changed = true;
415-
}
416-
}
437+
changed |= cleanupAfterEmittingDiagnostic();
417438
}
418439

419440
return changed;

0 commit comments

Comments
 (0)