|
150 | 150 | #include "swift/SIL/SILInstruction.h"
|
151 | 151 | #include "swift/SIL/SILValue.h"
|
152 | 152 | #include "swift/SIL/SILVisitor.h"
|
| 153 | +#include "swift/SIL/StackList.h" |
153 | 154 | #include "swift/SILOptimizer/Analysis/DeadEndBlocksAnalysis.h"
|
154 | 155 | #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h"
|
155 | 156 | #include "swift/SILOptimizer/PassManager/Transforms.h"
|
@@ -2259,6 +2260,13 @@ void ApplyRewriter::rewriteApply(ArrayRef<SILValue> newCallArgs) {
|
2259 | 2260 | /// ending uses.
|
2260 | 2261 | static void emitEndBorrows(SILValue value, AddressLoweringState &pass);
|
2261 | 2262 |
|
| 2263 | +/// Emit end_borrows at the lifetime ends of the guaranteed value which |
| 2264 | +/// encloses \p enclosingValue. |
| 2265 | +static void |
| 2266 | +emitEndBorrowsAtEnclosingGuaranteedBoundary(SILValue lifetimeToEnd, |
| 2267 | + SILValue enclosingValue, |
| 2268 | + AddressLoweringState &pass); |
| 2269 | + |
2262 | 2270 | void ApplyRewriter::convertBeginApplyWithOpaqueYield() {
|
2263 | 2271 | // Avoid revisiting this apply.
|
2264 | 2272 | bool erased = pass.indirectApplies.erase(apply);
|
@@ -3265,7 +3273,8 @@ void UseRewriter::rewriteDestructure(SILInstruction *destructure) {
|
3265 | 3273 | }
|
3266 | 3274 | result->replaceAllUsesWith(loadElement);
|
3267 | 3275 | if (guaranteed) {
|
3268 |
| - emitEndBorrows(loadElement, pass); |
| 3276 | + emitEndBorrowsAtEnclosingGuaranteedBoundary( |
| 3277 | + loadElement, destructure->getOperand(0), pass); |
3269 | 3278 | }
|
3270 | 3279 | }
|
3271 | 3280 | }
|
@@ -3392,6 +3401,53 @@ static void emitEndBorrows(SILValue value, AddressLoweringState &pass) {
|
3392 | 3401 | });
|
3393 | 3402 | }
|
3394 | 3403 |
|
| 3404 | +/// Emit end_borrows at the lifetime ends of the guaranteed value which |
| 3405 | +/// encloses \p enclosingValue. |
| 3406 | +/// |
| 3407 | +/// precondition: \p enclosingValue must be of opaque type |
| 3408 | +static void |
| 3409 | +emitEndBorrowsAtEnclosingGuaranteedBoundary(SILValue lifetimeToEnd, |
| 3410 | + SILValue enclosingValue, |
| 3411 | + AddressLoweringState &pass) { |
| 3412 | + /// It's necessary that enclosingValue be of opaque type. In practice, this |
| 3413 | + /// is the only situation in which AddressLowering needs to create a borrow |
| 3414 | + /// scope corresponding to some guaranteed value: the enclosingValue is the |
| 3415 | + /// opaque value that AddressLowering is rewriting. |
| 3416 | + /// |
| 3417 | + /// It's required in order to ensure that no introducer of enclosingValue has |
| 3418 | + /// a phi scope-ending use. That enables just visiting the local scope ending |
| 3419 | + /// uses. |
| 3420 | + /// |
| 3421 | + /// Given: enclosingValue is opaque. |
| 3422 | + /// |
| 3423 | + /// Then every introducer is opaque. In fact every introducer's type is some |
| 3424 | + /// aggregate in which enclosingValue's type appears. The reason is that |
| 3425 | + /// representation-changing forwarding guaranteed operations are not allowed |
| 3426 | + /// on opaque values. (See SIL.rst, Forwarding Address-Only Values). |
| 3427 | + /// |
| 3428 | + /// Thus no introducer is reborrowed. For suppose that some introducer were |
| 3429 | + /// reborrowed. Then it would appear as an operand of some phi with |
| 3430 | + /// guaranteed ownership. And that phi would be of opaque type. But that's |
| 3431 | + /// invalid! (See SILVerifier::visitSILPhiArgument.) |
| 3432 | + assert(enclosingValue->getType().isAddressOnly(*pass.function)); |
| 3433 | + TinyPtrVector<SILValue> introducers; |
| 3434 | + visitBorrowIntroducers(enclosingValue, [&](SILValue introducer) { |
| 3435 | + introducers.push_back(introducer); |
| 3436 | + return true; |
| 3437 | + }); |
| 3438 | + assert(introducers.size() == 1); |
| 3439 | + for (auto introducer : introducers) { |
| 3440 | + assert(introducer->getType().isAddressOnly(*pass.function)); |
| 3441 | + auto borrow = BorrowedValue(introducer); |
| 3442 | + borrow.visitLocalScopeEndingUses([&](Operand *use) { |
| 3443 | + assert(!PhiOperand(use)); |
| 3444 | + pass.getBuilder(use->getUser()->getIterator()) |
| 3445 | + .createEndBorrow(pass.genLoc(), lifetimeToEnd); |
| 3446 | + return true; |
| 3447 | + }); |
| 3448 | + } |
| 3449 | +} |
| 3450 | + |
3395 | 3451 | // Extract from an opaque struct or tuple.
|
3396 | 3452 | void UseRewriter::emitExtract(SingleValueInstruction *extractInst) {
|
3397 | 3453 | SILValue extractAddr = addrMat.materializeDefProjection(extractInst);
|
@@ -3805,12 +3861,22 @@ static void rewriteFunction(AddressLoweringState &pass) {
|
3805 | 3861 | if (valueDef->getType().isAddress())
|
3806 | 3862 | continue;
|
3807 | 3863 |
|
| 3864 | + // Collect end_borrows and rewrite them last so that when rewriting other |
| 3865 | + // users the lifetime ends of a borrow introducer can be used. |
| 3866 | + StackList<EndBorrowInst *> endBorrows(pass.function); |
3808 | 3867 | SmallPtrSet<Operand *, 8> originalUses;
|
3809 | 3868 | SmallVector<Operand *, 8> uses(valueDef->getUses());
|
3810 | 3869 | for (auto *oper : uses) {
|
3811 | 3870 | originalUses.insert(oper);
|
| 3871 | + if (auto *ebi = dyn_cast<EndBorrowInst>(oper->getUser())) { |
| 3872 | + endBorrows.push_back(ebi); |
| 3873 | + continue; |
| 3874 | + } |
3812 | 3875 | UseRewriter::rewriteUse(oper, pass);
|
3813 | 3876 | }
|
| 3877 | + for (auto *ebi : endBorrows) { |
| 3878 | + UseRewriter::rewriteUse(&ebi->getOperandRef(), pass); |
| 3879 | + } |
3814 | 3880 | // Rewrite every new use that was added.
|
3815 | 3881 | uses.clear();
|
3816 | 3882 | for (auto *use : valueDef->getUses()) {
|
|
0 commit comments