10
10
//
11
11
// ===----------------------------------------------------------------------===//
12
12
// /
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.
18
23
// /
19
24
// ===----------------------------------------------------------------------===//
20
25
28
33
#include " swift/SIL/SILInstruction.h"
29
34
#include " swift/SILOptimizer/Analysis/Analysis.h"
30
35
#include " swift/SILOptimizer/Analysis/DeadEndBlocksAnalysis.h"
36
+ #include " swift/Basic/BlotSetVector.h"
37
+ #include " swift/Basic/FrozenMultiMap.h"
31
38
#include " swift/SILOptimizer/Analysis/PostOrderAnalysis.h"
32
39
#include " swift/SILOptimizer/PassManager/Passes.h"
33
40
#include " swift/SILOptimizer/PassManager/Transforms.h"
37
44
using namespace swift ;
38
45
using namespace swift ::siloptimizer;
39
46
40
- using namespace swift ;
41
- using namespace swift ::siloptimizer;
42
-
43
47
namespace {
44
48
using AvailableValues = BorrowToDestructureTransform::AvailableValues;
45
49
}
@@ -202,8 +206,8 @@ void BorrowToDestructureTransform::checkDestructureUsesOnBoundary() const {
202
206
for (auto *use : destructureNeedingUses) {
203
207
LLVM_DEBUG (llvm::dbgs ()
204
208
<< " 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 )) {
207
211
LLVM_DEBUG (llvm::dbgs () << " Within boundary! Emitting error!\n " );
208
212
// Emit an error. We have a use after free.
209
213
//
@@ -217,7 +221,7 @@ void BorrowToDestructureTransform::checkDestructureUsesOnBoundary() const {
217
221
liveness.getNumSubElements ());
218
222
liveness.computeBoundary (boundary);
219
223
diagnosticEmitter.emitObjectDestructureNeededWithinBorrowBoundary (
220
- mmci, use->getUser (), destructureUse , boundary);
224
+ mmci, use->getUser (), destructureUseSpan , boundary);
221
225
return ;
222
226
} else {
223
227
LLVM_DEBUG (llvm::dbgs () << " On boundary! No error!\n " );
@@ -1323,115 +1327,3 @@ void BorrowToDestructureTransform::cleanup(
1323
1327
// And finally do the same thing for our initial copy_value.
1324
1328
addCompensatingDestroys (liveness, boundary, initialValue);
1325
1329
}
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