1010//
1111// ===----------------------------------------------------------------------===//
1212// /
13- // / \file This is a pass that converts the borrow + gep pattern to destructures
14- // / or emits an error if it cannot be done. It is assumed that it runs
15- // / immediately before move checking of objects runs. This ensures that the move
16- // / checker does not need to worry about this problem and instead can just check
17- // / that the newly inserted destructures do not cause move only errors.
13+ // / \file This is a transform that converts the borrow + gep pattern to
14+ // / destructures or emits an error if it cannot be done. It is assumed that it
15+ // / runs immediately before move checking of objects runs. This ensures that the
16+ // / move checker does not need to worry about this problem and instead can just
17+ // / check that the newly inserted destructures do not cause move only errors.
18+ // /
19+ // / This is written as a utility so that we can have a utility pass that tests
20+ // / this directly but also invoke this via the move only object checker.
21+ // /
22+ // / TODO: Move this to SILOptimizer/Utils.
1823// /
1924// ===----------------------------------------------------------------------===//
2025
2833#include " swift/SIL/SILInstruction.h"
2934#include " swift/SILOptimizer/Analysis/Analysis.h"
3035#include " swift/SILOptimizer/Analysis/DeadEndBlocksAnalysis.h"
36+ #include " swift/Basic/BlotSetVector.h"
37+ #include " swift/Basic/FrozenMultiMap.h"
3138#include " swift/SILOptimizer/Analysis/PostOrderAnalysis.h"
3239#include " swift/SILOptimizer/PassManager/Passes.h"
3340#include " swift/SILOptimizer/PassManager/Transforms.h"
3744using namespace swift ;
3845using namespace swift ::siloptimizer;
3946
40- using namespace swift ;
41- using namespace swift ::siloptimizer;
42-
4347namespace {
4448using AvailableValues = BorrowToDestructureTransform::AvailableValues;
4549}
@@ -202,8 +206,8 @@ void BorrowToDestructureTransform::checkDestructureUsesOnBoundary() const {
202206 for (auto *use : destructureNeedingUses) {
203207 LLVM_DEBUG (llvm::dbgs ()
204208 << " DestructureNeedingUse: " << *use->getUser ());
205- auto destructureUse = *TypeTreeLeafTypeRange::get (use->get (), mmci);
206- if (liveness.isWithinBoundary (use->getUser (), destructureUse )) {
209+ auto destructureUseSpan = *TypeTreeLeafTypeRange::get (use->get (), mmci);
210+ if (liveness.isWithinBoundary (use->getUser (), destructureUseSpan )) {
207211 LLVM_DEBUG (llvm::dbgs () << " Within boundary! Emitting error!\n " );
208212 // Emit an error. We have a use after free.
209213 //
@@ -217,7 +221,7 @@ void BorrowToDestructureTransform::checkDestructureUsesOnBoundary() const {
217221 liveness.getNumSubElements ());
218222 liveness.computeBoundary (boundary);
219223 diagnosticEmitter.emitObjectDestructureNeededWithinBorrowBoundary (
220- mmci, use->getUser (), destructureUse , boundary);
224+ mmci, use->getUser (), destructureUseSpan , boundary);
221225 return ;
222226 } else {
223227 LLVM_DEBUG (llvm::dbgs () << " On boundary! No error!\n " );
@@ -1323,115 +1327,3 @@ void BorrowToDestructureTransform::cleanup(
13231327 // And finally do the same thing for our initial copy_value.
13241328 addCompensatingDestroys (liveness, boundary, initialValue);
13251329}
1326-
1327- // ===----------------------------------------------------------------------===//
1328- // Top Level Entrypoint
1329- // ===----------------------------------------------------------------------===//
1330-
1331- static bool runTransform (SILFunction *fn,
1332- ArrayRef<MarkMustCheckInst *> moveIntroducersToProcess,
1333- PostOrderAnalysis *poa,
1334- DiagnosticEmitter &diagnosticEmitter) {
1335- BorrowToDestructureTransform::IntervalMapAllocator allocator;
1336- bool madeChange = false ;
1337- while (!moveIntroducersToProcess.empty ()) {
1338- auto *mmci = moveIntroducersToProcess.back ();
1339- moveIntroducersToProcess = moveIntroducersToProcess.drop_back ();
1340-
1341- StackList<BeginBorrowInst *> borrowWorklist (mmci->getFunction ());
1342-
1343- // If we failed to gather borrows due to the transform not understanding
1344- // part of the SIL, fail and return false.
1345- if (!BorrowToDestructureTransform::gatherBorrows (mmci, borrowWorklist))
1346- return madeChange;
1347-
1348- // If we do not have any borrows to process, continue and process the next
1349- // instruction.
1350- if (borrowWorklist.empty ())
1351- continue ;
1352-
1353- SmallVector<SILBasicBlock *, 8 > discoveredBlocks;
1354-
1355- // Now that we have found all of our borrows, we want to find struct_extract
1356- // uses of our borrow as well as any operands that cannot use an owned
1357- // value.
1358- SWIFT_DEFER { discoveredBlocks.clear (); };
1359- BorrowToDestructureTransform transform (allocator, mmci, diagnosticEmitter,
1360- poa, discoveredBlocks);
1361-
1362- // Attempt to gather uses. Return if we saw something that we did not
1363- // understand. Return made change so we invalidate as appropriate.
1364- if (!transform.gatherUses (borrowWorklist))
1365- return madeChange;
1366-
1367- // Next make sure that any destructure needing instructions are on the
1368- // boundary in a per bit field sensitive manner.
1369- transform.checkDestructureUsesOnBoundary ();
1370-
1371- // If we emitted any diagnostic, break out. We return true since we actually
1372- // succeeded in our processing by finding the error. We only return false if
1373- // we want to tell the rest of the checker that there was an internal
1374- // compiler error that we need to emit a "compiler doesn't understand
1375- // error".
1376- if (diagnosticEmitter.emittedAnyDiagnostics ())
1377- return madeChange;
1378-
1379- // At this point, we know that all of our destructure requiring uses are on
1380- // the boundary of our live range. Now we need to do the rewriting.
1381- transform.blockToAvailableValues .emplace (transform.liveness );
1382- transform.rewriteUses ();
1383-
1384- // Now that we have done our rewritting, we need to do a few cleanups.
1385- transform.cleanup (borrowWorklist);
1386- }
1387-
1388- return madeChange;
1389- }
1390-
1391- namespace {
1392-
1393- class MoveOnlyBorrowToDestructureTransformPass : public SILFunctionTransform {
1394- void run () override {
1395- auto *fn = getFunction ();
1396-
1397- // Only run this pass if the move only language feature is enabled.
1398- if (!fn->getASTContext ().LangOpts .Features .contains (Feature::MoveOnly))
1399- return ;
1400-
1401- // Don't rerun diagnostics on deserialized functions.
1402- if (getFunction ()->wasDeserializedCanonical ())
1403- return ;
1404-
1405- assert (fn->getModule ().getStage () == SILStage::Raw &&
1406- " Should only run on Raw SIL" );
1407-
1408- LLVM_DEBUG (llvm::dbgs () << " ===> MoveOnly Object Checker. Visiting: "
1409- << fn->getName () << ' \n ' );
1410-
1411- auto *postOrderAnalysis = getAnalysis<PostOrderAnalysis>();
1412-
1413- SmallSetVector<MarkMustCheckInst *, 32 > moveIntroducersToProcess;
1414- DiagnosticEmitter emitter;
1415-
1416- bool madeChange = searchForCandidateObjectMarkMustChecks (
1417- getFunction (), moveIntroducersToProcess, emitter);
1418- if (madeChange) {
1419- invalidateAnalysis (SILAnalysis::InvalidationKind::Instructions);
1420- }
1421-
1422- if (emitter.emittedAnyDiagnostics ())
1423- return ;
1424-
1425- auto introducers = llvm::makeArrayRef (moveIntroducersToProcess.begin (),
1426- moveIntroducersToProcess.end ());
1427- if (runTransform (fn, introducers, postOrderAnalysis, emitter)) {
1428- invalidateAnalysis (SILAnalysis::InvalidationKind::Instructions);
1429- }
1430- }
1431- };
1432-
1433- } // namespace
1434-
1435- SILTransform *swift::createMoveOnlyBorrowToDestructureTransform () {
1436- return new MoveOnlyBorrowToDestructureTransformPass ();
1437- }
0 commit comments