Skip to content

Commit 1710f6f

Browse files
committed
[move-only-addr] Refactor struct LivenessChecker into GlobalDataflow struct and clean it up a little bit to take summaries.
NFCI.
1 parent 7c2b72f commit 1710f6f

File tree

1 file changed

+171
-178
lines changed

1 file changed

+171
-178
lines changed

lib/SILOptimizer/Mandatory/MoveOnlyAddressChecker.cpp

Lines changed: 171 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ struct UseState {
491491
} // namespace
492492

493493
//===----------------------------------------------------------------------===//
494-
// MARK: Liveness Processor
494+
// MARK: Global Block State
495495
//===----------------------------------------------------------------------===//
496496

497497
namespace {
@@ -522,181 +522,8 @@ struct BlockState {
522522
: userUp(userUp), isInitDown(isInitDown) {}
523523
};
524524

525-
/// Post process the found liveness and emit errors if needed. TODO: Better
526-
/// name.
527-
struct LivenessChecker {
528-
MarkMustCheckInst *markedAddress;
529-
FieldSensitiveAddressPrunedLiveness &liveness;
530-
SmallBitVector livenessVector;
531-
bool hadAnyErrorUsers = false;
532-
SmallPtrSetImpl<SILInstruction *> &inoutTermUsers;
533-
BlockState::Map &blockToState;
534-
535-
DiagnosticEmitter &diagnosticEmitter;
536-
537-
LivenessChecker(MarkMustCheckInst *markedAddress,
538-
FieldSensitiveAddressPrunedLiveness &liveness,
539-
SmallPtrSetImpl<SILInstruction *> &inoutTermUsers,
540-
BlockState::Map &blockToState,
541-
DiagnosticEmitter &diagnosticEmitter)
542-
: markedAddress(markedAddress), liveness(liveness),
543-
inoutTermUsers(inoutTermUsers), blockToState(blockToState),
544-
diagnosticEmitter(diagnosticEmitter) {}
545-
546-
/// Returns true if we emitted any errors.
547-
bool
548-
compute(SmallVectorImpl<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>
549-
&takeUpInsts,
550-
SmallVectorImpl<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>
551-
&takeDownInsts);
552-
553-
void clear() {
554-
livenessVector.clear();
555-
hadAnyErrorUsers = false;
556-
}
557-
558-
std::pair<bool, bool> testInstVectorLiveness(
559-
SmallVectorImpl<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>
560-
&takeInsts);
561-
};
562-
563525
} // namespace
564526

565-
std::pair<bool, bool> LivenessChecker::testInstVectorLiveness(
566-
SmallVectorImpl<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>
567-
&takeInsts) {
568-
bool emittedDiagnostic = false;
569-
bool foundSingleBlockTakeDueToInitDown = false;
570-
571-
for (auto takeInstAndValue : takeInsts) {
572-
LLVM_DEBUG(llvm::dbgs() << " Checking: " << *takeInstAndValue.first);
573-
574-
// Check if we are in the boundary...
575-
liveness.isWithinBoundary(takeInstAndValue.first, livenessVector);
576-
577-
// If the bit vector does not contain any set bits, then we know that we did
578-
// not have any boundary violations for any leaf node of our root value.
579-
if (!livenessVector.any()) {
580-
// TODO: Today, we don't tell the user the actual field itself where the
581-
// violation occured and just instead just shows the two instructions. We
582-
// could be more specific though...
583-
LLVM_DEBUG(llvm::dbgs() << " Not within the boundary.\n");
584-
continue;
585-
}
586-
LLVM_DEBUG(llvm::dbgs()
587-
<< " Within the boundary! Emitting an error\n");
588-
589-
// Ok, we have an error and via the bit vector know which specific leaf
590-
// elements of our root type were within the per field boundary. We need to
591-
// go find the next reachable use that overlap with its sub-element. We only
592-
// emit a single error per use even if we get multiple sub elements that
593-
// match it. That helps reduce the amount of errors.
594-
//
595-
// DISCUSSION: It is important to note that this follows from the separation
596-
// of concerns behind this pass: we have simplified how we handle liveness
597-
// by losing this information. That being said, since we are erroring it is
598-
// ok that we are taking a little more time since we are not going to
599-
// codegen this code.
600-
//
601-
// That being said, set the flag that we saw at least one error, so we can
602-
// exit early after this loop.
603-
hadAnyErrorUsers = true;
604-
605-
// B/c of the separation of concerns with our liveness, we now need to walk
606-
// blocks to go find the specific later takes that are reachable from this
607-
// take. It is ok that we are doing a bit more work here since we are going
608-
// to exit and not codegen.
609-
auto *errorUser = takeInstAndValue.first;
610-
611-
// Before we do anything, grab the state for our errorUser's block from the
612-
// blockState and check if it is an init block. If so, we have no further
613-
// work to do since we already found correctness due to our single basic
614-
// block check. So, we have nothing further to do.
615-
if (blockToState.find(errorUser->getParent())->second.isInitDown) {
616-
// Set the flag that we saw an init down so that our assert later that we
617-
// actually emitted an error doesn't trigger.
618-
foundSingleBlockTakeDueToInitDown = true;
619-
continue;
620-
}
621-
622-
BasicBlockWorklist worklist(errorUser->getFunction());
623-
for (auto *succBlock : errorUser->getParent()->getSuccessorBlocks())
624-
worklist.pushIfNotVisited(succBlock);
625-
626-
LLVM_DEBUG(llvm::dbgs() << "Performing forward traversal from errorUse "
627-
"looking for the cause of liveness!\n");
628-
629-
while (auto *block = worklist.pop()) {
630-
LLVM_DEBUG(llvm::dbgs()
631-
<< "Visiting block: bb" << block->getDebugID() << "\n");
632-
auto iter = blockToState.find(block);
633-
if (iter == blockToState.end()) {
634-
LLVM_DEBUG(llvm::dbgs() << " No State! Skipping!\n");
635-
for (auto *succBlock : block->getSuccessorBlocks())
636-
worklist.pushIfNotVisited(succBlock);
637-
continue;
638-
}
639-
640-
auto *blockUser = iter->second.userUp;
641-
642-
if (blockUser) {
643-
LLVM_DEBUG(llvm::dbgs() << " Found userUp: " << *blockUser);
644-
auto info = liveness.isInterestingUser(blockUser);
645-
// Make sure that it overlaps with our range...
646-
if (info.second->contains(*info.second)) {
647-
LLVM_DEBUG(llvm::dbgs() << " Emitted diagnostic for it!\n");
648-
// and if it does... emit our diagnostic and continue to see if we
649-
// find errors along other paths.
650-
// if (invalidUsesWithDiagnostics.insert(errorUser
651-
bool isConsuming =
652-
info.first ==
653-
FieldSensitiveAddressPrunedLiveness::LifetimeEndingUse;
654-
diagnosticEmitter.emitAddressDiagnostic(
655-
markedAddress, blockUser, errorUser, isConsuming,
656-
inoutTermUsers.count(blockUser));
657-
emittedDiagnostic = true;
658-
continue;
659-
}
660-
}
661-
662-
// Otherwise, add successors and continue! We didn't overlap with this
663-
// use.
664-
LLVM_DEBUG(llvm::dbgs() << " Does not overlap at the type level, no "
665-
"diagnostic! Visiting successors!\n");
666-
for (auto *succBlock : block->getSuccessorBlocks())
667-
worklist.pushIfNotVisited(succBlock);
668-
}
669-
}
670-
671-
return {emittedDiagnostic, foundSingleBlockTakeDueToInitDown};
672-
}
673-
674-
bool LivenessChecker::compute(
675-
SmallVectorImpl<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>
676-
&takeUpInsts,
677-
SmallVectorImpl<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>
678-
&takeDownInsts) {
679-
// Then revisit our takes, this time checking if we are within the boundary
680-
// and if we are, emit an error.
681-
LLVM_DEBUG(llvm::dbgs() << "Checking takes for errors!\n");
682-
bool emittedDiagnostic = false;
683-
bool foundSingleBlockTakeDueToInitDown = false;
684-
685-
auto pair = testInstVectorLiveness(takeUpInsts);
686-
emittedDiagnostic |= pair.first;
687-
foundSingleBlockTakeDueToInitDown |= pair.second;
688-
689-
pair = testInstVectorLiveness(takeDownInsts);
690-
emittedDiagnostic |= pair.first;
691-
foundSingleBlockTakeDueToInitDown |= pair.second;
692-
693-
// If we emitted an error user, we should always emit at least one
694-
// diagnostic. If we didn't there is a bug in the implementation.
695-
assert(!hadAnyErrorUsers || emittedDiagnostic ||
696-
foundSingleBlockTakeDueToInitDown);
697-
return hadAnyErrorUsers;
698-
}
699-
700527
//===----------------------------------------------------------------------===//
701528
// MARK: Forward Declaration of Main Checker
702529
//===----------------------------------------------------------------------===//
@@ -1471,6 +1298,174 @@ void BlockSummaries::initializeLiveness(
14711298
}
14721299
}
14731300

1301+
//===----------------------------------------------------------------------===//
1302+
// MARK: Global Dataflow
1303+
//===----------------------------------------------------------------------===//
1304+
1305+
namespace {
1306+
1307+
/// Post process the found liveness and emit errors if needed. TODO: Better
1308+
/// name.
1309+
struct GlobalDataflow {
1310+
BlockSummaries &summaries;
1311+
FieldSensitiveAddressPrunedLiveness &liveness;
1312+
SmallPtrSetImpl<SILInstruction *> &inoutTermInstUsers;
1313+
SmallBitVector livenessVector;
1314+
bool hadAnyErrorUsers = false;
1315+
1316+
GlobalDataflow(BlockSummaries &summaries,
1317+
FieldSensitiveAddressPrunedLiveness &liveness,
1318+
SmallPtrSetImpl<SILInstruction *> &inoutTermInstUsers)
1319+
: summaries(summaries), liveness(liveness),
1320+
inoutTermInstUsers(inoutTermInstUsers) {}
1321+
1322+
/// Returns true if we emitted any errors.
1323+
bool compute();
1324+
1325+
void clear() {
1326+
livenessVector.clear();
1327+
hadAnyErrorUsers = false;
1328+
}
1329+
1330+
std::pair<bool, bool> testInstVectorLiveness(
1331+
SmallVectorImpl<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>
1332+
&instsToTest);
1333+
BlockState::Map &getBlockToState() const { return summaries.blockToState; }
1334+
};
1335+
1336+
} // namespace
1337+
1338+
std::pair<bool, bool> GlobalDataflow::testInstVectorLiveness(
1339+
SmallVectorImpl<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>
1340+
&instsToTest) {
1341+
bool emittedDiagnostic = false;
1342+
bool foundSingleBlockTakeDueToInitDown = false;
1343+
1344+
for (auto takeInstAndValue : instsToTest) {
1345+
LLVM_DEBUG(llvm::dbgs() << " Checking: " << *takeInstAndValue.first);
1346+
1347+
// Check if we are in the boundary...
1348+
liveness.isWithinBoundary(takeInstAndValue.first, livenessVector);
1349+
1350+
// If the bit vector does not contain any set bits, then we know that we did
1351+
// not have any boundary violations for any leaf node of our root value.
1352+
if (!livenessVector.any()) {
1353+
// TODO: Today, we don't tell the user the actual field itself where the
1354+
// violation occured and just instead just shows the two instructions. We
1355+
// could be more specific though...
1356+
LLVM_DEBUG(llvm::dbgs() << " Not within the boundary.\n");
1357+
continue;
1358+
}
1359+
LLVM_DEBUG(llvm::dbgs()
1360+
<< " Within the boundary! Emitting an error\n");
1361+
1362+
// Ok, we have an error and via the bit vector know which specific leaf
1363+
// elements of our root type were within the per field boundary. We need to
1364+
// go find the next reachable use that overlap with its sub-element. We only
1365+
// emit a single error per use even if we get multiple sub elements that
1366+
// match it. That helps reduce the amount of errors.
1367+
//
1368+
// DISCUSSION: It is important to note that this follows from the separation
1369+
// of concerns behind this pass: we have simplified how we handle liveness
1370+
// by losing this information. That being said, since we are erroring it is
1371+
// ok that we are taking a little more time since we are not going to
1372+
// codegen this code.
1373+
//
1374+
// That being said, set the flag that we saw at least one error, so we can
1375+
// exit early after this loop.
1376+
hadAnyErrorUsers = true;
1377+
1378+
// B/c of the separation of concerns with our liveness, we now need to walk
1379+
// blocks to go find the specific later takes that are reachable from this
1380+
// take. It is ok that we are doing a bit more work here since we are going
1381+
// to exit and not codegen.
1382+
auto *errorUser = takeInstAndValue.first;
1383+
1384+
// Before we do anything, grab the state for our errorUser's block from the
1385+
// blockState and check if it is an init block. If so, we have no further
1386+
// work to do since we already found correctness due to our single basic
1387+
// block check. So, we have nothing further to do.
1388+
if (getBlockToState().find(errorUser->getParent())->second.isInitDown) {
1389+
// Set the flag that we saw an init down so that our assert later that we
1390+
// actually emitted an error doesn't trigger.
1391+
foundSingleBlockTakeDueToInitDown = true;
1392+
continue;
1393+
}
1394+
1395+
BasicBlockWorklist worklist(errorUser->getFunction());
1396+
for (auto *succBlock : errorUser->getParent()->getSuccessorBlocks())
1397+
worklist.pushIfNotVisited(succBlock);
1398+
1399+
LLVM_DEBUG(llvm::dbgs() << "Performing forward traversal from errorUse "
1400+
"looking for the cause of liveness!\n");
1401+
1402+
while (auto *block = worklist.pop()) {
1403+
LLVM_DEBUG(llvm::dbgs()
1404+
<< "Visiting block: bb" << block->getDebugID() << "\n");
1405+
auto iter = getBlockToState().find(block);
1406+
if (iter == getBlockToState().end()) {
1407+
LLVM_DEBUG(llvm::dbgs() << " No State! Skipping!\n");
1408+
for (auto *succBlock : block->getSuccessorBlocks())
1409+
worklist.pushIfNotVisited(succBlock);
1410+
continue;
1411+
}
1412+
1413+
auto *blockUser = iter->second.userUp;
1414+
1415+
if (blockUser) {
1416+
LLVM_DEBUG(llvm::dbgs() << " Found userUp: " << *blockUser);
1417+
auto info = liveness.isInterestingUser(blockUser);
1418+
// Make sure that it overlaps with our range...
1419+
if (info.second->contains(*info.second)) {
1420+
LLVM_DEBUG(llvm::dbgs() << " Emitted diagnostic for it!\n");
1421+
// and if it does... emit our diagnostic and continue to see if we
1422+
// find errors along other paths.
1423+
// if (invalidUsesWithDiagnostics.insert(errorUser
1424+
bool isConsuming =
1425+
info.first ==
1426+
FieldSensitiveAddressPrunedLiveness::LifetimeEndingUse;
1427+
summaries.diagnosticEmitter.emitAddressDiagnostic(
1428+
summaries.markedAddress, blockUser, errorUser, isConsuming,
1429+
inoutTermInstUsers.count(blockUser));
1430+
emittedDiagnostic = true;
1431+
continue;
1432+
}
1433+
}
1434+
1435+
// Otherwise, add successors and continue! We didn't overlap with this
1436+
// use.
1437+
LLVM_DEBUG(llvm::dbgs() << " Does not overlap at the type level, no "
1438+
"diagnostic! Visiting successors!\n");
1439+
for (auto *succBlock : block->getSuccessorBlocks())
1440+
worklist.pushIfNotVisited(succBlock);
1441+
}
1442+
}
1443+
1444+
return {emittedDiagnostic, foundSingleBlockTakeDueToInitDown};
1445+
}
1446+
1447+
bool GlobalDataflow::compute() {
1448+
// Then revisit our takes, this time checking if we are within the boundary
1449+
// and if we are, emit an error.
1450+
LLVM_DEBUG(llvm::dbgs() << "Checking takes for errors!\n");
1451+
bool emittedDiagnostic = false;
1452+
bool foundSingleBlockTakeDueToInitDown = false;
1453+
1454+
auto pair = testInstVectorLiveness(summaries.takeUpInsts);
1455+
emittedDiagnostic |= pair.first;
1456+
foundSingleBlockTakeDueToInitDown |= pair.second;
1457+
1458+
pair = testInstVectorLiveness(summaries.takeDownInsts);
1459+
emittedDiagnostic |= pair.first;
1460+
foundSingleBlockTakeDueToInitDown |= pair.second;
1461+
1462+
// If we emitted an error user, we should always emit at least one
1463+
// diagnostic. If we didn't there is a bug in the implementation.
1464+
assert(!hadAnyErrorUsers || emittedDiagnostic ||
1465+
foundSingleBlockTakeDueToInitDown);
1466+
return hadAnyErrorUsers;
1467+
}
1468+
14741469
//===----------------------------------------------------------------------===//
14751470
// MARK: Main Pass Implementation
14761471
//===----------------------------------------------------------------------===//
@@ -1649,19 +1644,17 @@ bool MoveOnlyChecker::performSingleCheck(MarkMustCheckInst *markedAddress) {
16491644
FieldSensitiveAddressPrunedLiveness liveness(fn, markedAddress,
16501645
&discoveredBlocks);
16511646
SmallPtrSet<SILInstruction *, 8> inoutTermUsers;
1652-
16531647
summaries.initializeLiveness(liveness, inoutTermUsers);
16541648

16551649
// If we have multiple blocks in the function, now run the global pruned
16561650
// liveness dataflow.
16571651
if (std::next(fn->begin()) != fn->end()) {
16581652
// Then compute the takes that are within the cumulative boundary of
16591653
// liveness that we have computed. If we find any, they are the errors ones.
1660-
LivenessChecker emitter(markedAddress, liveness, inoutTermUsers,
1661-
summaries.blockToState, diagnosticEmitter);
1654+
GlobalDataflow emitter(summaries, liveness, inoutTermUsers);
16621655

16631656
// If we had any errors, we do not want to modify the SIL... just bail.
1664-
if (emitter.compute(summaries.takeUpInsts, summaries.takeDownInsts)) {
1657+
if (emitter.compute()) {
16651658
// TODO: Remove next line.
16661659
valuesWithDiagnostics.insert(markedAddress);
16671660
return true;

0 commit comments

Comments
 (0)