@@ -472,7 +472,7 @@ class DestroyLocalVariable : public Cleanup {
472
472
Var->print(llvm::errs());
473
473
llvm::errs() << "\n";
474
474
if (isActive()) {
475
- auto loc = SGF.VarLocs[Var];
475
+ auto & loc = SGF.VarLocs[Var];
476
476
assert((loc.box || loc.value) && "One of box or value should be set");
477
477
if (loc.box) {
478
478
llvm::errs() << "Box: " << loc.box << "\n";
@@ -664,7 +664,8 @@ class LocalVariableInitialization : public SingleBufferInitialization {
664
664
/// decl to.
665
665
assert(SGF.VarLocs.count(decl) == 0 && "Already emitted the local?");
666
666
667
- SGF.VarLocs[decl] = SILGenFunction::VarLoc::get(Addr, Box);
667
+ SGF.VarLocs[decl] = SILGenFunction::VarLoc(Addr,
668
+ SILAccessEnforcement::Dynamic, Box);
668
669
669
670
SingleBufferInitialization::finishInitialization(SGF);
670
671
assert(!DidFinish &&
@@ -677,6 +678,54 @@ class LocalVariableInitialization : public SingleBufferInitialization {
677
678
} // end anonymous namespace
678
679
679
680
namespace {
681
+
682
+ static void deallocateAddressable(SILGenFunction &SGF,
683
+ SILLocation l,
684
+ const SILGenFunction::VarLoc::AddressableBuffer::State &state) {
685
+ SGF.B.createEndBorrow(l, state.storeBorrow);
686
+ SGF.B.createDeallocStack(l, state.allocStack);
687
+ if (state.reabstraction) {
688
+ SGF.B.createDestroyValue(l, state.reabstraction);
689
+ }
690
+ }
691
+
692
+ /// Cleanup to deallocate the addressable buffer for a parameter or let
693
+ /// binding.
694
+ class DeallocateLocalVariableAddressableBuffer : public Cleanup {
695
+ ValueDecl *vd;
696
+ public:
697
+ DeallocateLocalVariableAddressableBuffer(ValueDecl *vd) : vd(vd) {}
698
+
699
+ void emit(SILGenFunction &SGF, CleanupLocation l,
700
+ ForUnwind_t forUnwind) override {
701
+ auto found = SGF.VarLocs.find(vd);
702
+ if (found == SGF.VarLocs.end()) {
703
+ return;
704
+ }
705
+ auto &loc = found->second;
706
+
707
+ if (auto &state = loc.addressableBuffer.state) {
708
+ // The addressable buffer was forced, so clean it up now.
709
+ deallocateAddressable(SGF, l, *state);
710
+ } else {
711
+ // Remember this insert location in case we need to force the addressable
712
+ // buffer later.
713
+ SILInstruction *marker = SGF.B.createTuple(l, {});
714
+ loc.addressableBuffer.cleanupPoints.emplace_back(marker);
715
+ }
716
+ }
717
+
718
+ void dump(SILGenFunction &SGF) const override {
719
+ #ifndef NDEBUG
720
+ llvm::errs() << "DeallocateLocalVariableAddressableBuffer\n"
721
+ << "State:" << getState() << "\n"
722
+ << "Decl: ";
723
+ vd->print(llvm::errs());
724
+ llvm::errs() << "\n";
725
+ #endif
726
+ }
727
+ };
728
+
680
729
/// Initialize a writeback buffer that receives the value of a 'let'
681
730
/// declaration.
682
731
class LetValueInitialization : public Initialization {
@@ -755,7 +804,8 @@ class LetValueInitialization : public Initialization {
755
804
if (isUninitialized)
756
805
address = SGF.B.createMarkUninitializedVar(vd, address);
757
806
DestroyCleanup = SGF.enterDormantTemporaryCleanup(address, *lowering);
758
- SGF.VarLocs[vd] = SILGenFunction::VarLoc::get(address);
807
+ SGF.VarLocs[vd] = SILGenFunction::VarLoc(address,
808
+ SILAccessEnforcement::Unknown);
759
809
}
760
810
// Push a cleanup to destroy the let declaration. This has to be
761
811
// inactive until the variable is initialized: if control flow exits the
@@ -766,6 +816,10 @@ class LetValueInitialization : public Initialization {
766
816
SGF.Cleanups.pushCleanupInState<DestroyLocalVariable>(
767
817
CleanupState::Dormant, vd);
768
818
DestroyCleanup = SGF.Cleanups.getTopCleanup();
819
+
820
+ // If the binding has an addressable buffer forced, it should be cleaned
821
+ // up here.
822
+ SGF.enterLocalVariableAddressableBufferScope(vd);
769
823
}
770
824
771
825
~LetValueInitialization() override {
@@ -883,7 +937,8 @@ class LetValueInitialization : public Initialization {
883
937
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule()))
884
938
value = getValueForLexicalLifetimeBinding(SGF, loc, value, wasPlusOne);
885
939
886
- SGF.VarLocs[vd] = SILGenFunction::VarLoc::get(value);
940
+ SGF.VarLocs[vd] = SILGenFunction::VarLoc(value,
941
+ SILAccessEnforcement::Unknown);
887
942
888
943
// Emit a debug_value[_addr] instruction to record the start of this value's
889
944
// lifetime, if permitted to do so.
@@ -1463,7 +1518,7 @@ SILGenFunction::emitInitializationForVarDecl(VarDecl *vd, bool forceImmutable,
1463
1518
assert(SILDebugClient && "Debugger client doesn't support SIL");
1464
1519
SILValue SV = SILDebugClient->emitLValueForVariable(vd, B);
1465
1520
1466
- VarLocs[vd] = SILGenFunction:: VarLoc::get (SV);
1521
+ VarLocs[vd] = VarLoc(SV, SILAccessEnforcement::Dynamic );
1467
1522
return InitializationPtr(new KnownAddressInitialization(SV));
1468
1523
}
1469
1524
@@ -1494,7 +1549,7 @@ SILGenFunction::emitInitializationForVarDecl(VarDecl *vd, bool forceImmutable,
1494
1549
if (isUninitialized)
1495
1550
addr = B.createMarkUninitializedVar(loc, addr);
1496
1551
1497
- VarLocs[vd] = SILGenFunction:: VarLoc::get (addr);
1552
+ VarLocs[vd] = VarLoc(addr, SILAccessEnforcement::Dynamic );
1498
1553
Result = InitializationPtr(new KnownAddressInitialization(addr));
1499
1554
} else {
1500
1555
std::optional<MarkUninitializedInst::Kind> uninitKind;
@@ -2309,11 +2364,9 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
2309
2364
}
2310
2365
};
2311
2366
2312
- auto loc = VarLocs[vd];
2313
-
2314
2367
// For a heap variable, the box is responsible for the value. We just need
2315
2368
// to give up our retain count on it.
2316
- if (auto boxValue = loc .box) {
2369
+ if (auto boxValue = VarLocs[vd] .box) {
2317
2370
if (!getASTContext().SILOpts.supportsLexicalLifetimes(getModule())) {
2318
2371
emitDestroy(boxValue);
2319
2372
return;
@@ -2329,7 +2382,7 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
2329
2382
2330
2383
// For 'let' bindings, we emit a release_value or destroy_addr, depending on
2331
2384
// whether we have an address or not.
2332
- SILValue Val = loc .value;
2385
+ SILValue Val = VarLocs[vd] .value;
2333
2386
2334
2387
if (Val->getType().isAddress()) {
2335
2388
B.createDestroyAddr(silLoc, Val);
@@ -2406,6 +2459,108 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
2406
2459
llvm_unreachable("unhandled case");
2407
2460
}
2408
2461
2462
+ void
2463
+ SILGenFunction::enterLocalVariableAddressableBufferScope(VarDecl *decl) {
2464
+ Cleanups.pushCleanup<DeallocateLocalVariableAddressableBuffer>(decl);
2465
+ }
2466
+
2467
+ SILValue
2468
+ SILGenFunction::getLocalVariableAddressableBuffer(VarDecl *decl,
2469
+ SILLocation curLoc,
2470
+ ValueOwnership ownership) {
2471
+ auto foundVarLoc = VarLocs.find(decl);
2472
+ if (foundVarLoc == VarLocs.end()) {
2473
+ return SILValue();
2474
+ }
2475
+
2476
+ auto value = foundVarLoc->second.value;
2477
+ auto access = foundVarLoc->second.access;
2478
+ auto *state = foundVarLoc->second.addressableBuffer.state.get();
2479
+
2480
+ SILType fullyAbstractedTy = getLoweredType(AbstractionPattern::getOpaque(),
2481
+ decl->getTypeInContext()->getRValueType());
2482
+
2483
+ // Check whether the bound value is inherently suitable for addressability.
2484
+ // It must already be in memory and fully abstracted.
2485
+ if (value->getType().isAddress()
2486
+ && fullyAbstractedTy.getASTType() == value->getType().getASTType()) {
2487
+ SILValue address = value;
2488
+ // Begin an access if the address is mutable.
2489
+ if (access != SILAccessEnforcement::Unknown) {
2490
+ address = B.emitBeginAccess(curLoc, address,
2491
+ ownership == ValueOwnership::InOut ? SILAccessKind::Modify
2492
+ : SILAccessKind::Read,
2493
+ access);
2494
+ }
2495
+ return address;
2496
+ }
2497
+
2498
+ // We can't retroactively introduce a reabstracted representation for a
2499
+ // mutable binding (since we would now have two mutable memory locations
2500
+ // representing the same value).
2501
+ if (access != SILAccessEnforcement::Unknown) {
2502
+ return SILValue();
2503
+ }
2504
+
2505
+ assert(ownership == ValueOwnership::Shared);
2506
+
2507
+ // Check whether the in-memory representation has already been forced.
2508
+ if (state) {
2509
+ return state->storeBorrow;
2510
+ }
2511
+
2512
+ // Otherwise, force the addressable representation.
2513
+ SILValue reabstraction, allocStack, storeBorrow;
2514
+ {
2515
+ SavedInsertionPointRAII save(B);
2516
+ B.setInsertionPoint(value->getNextInstruction());
2517
+ auto declarationLoc = value->getDefiningInsertionPoint()->getLoc();
2518
+
2519
+ // Reabstract if necessary.
2520
+ auto newValue = value;
2521
+ reabstraction = SILValue();
2522
+ if (newValue->getType().getASTType() != fullyAbstractedTy.getASTType()){
2523
+ auto reabstracted = emitSubstToOrigValue(curLoc,
2524
+ ManagedValue::forBorrowedRValue(value),
2525
+ AbstractionPattern::getOpaque(),
2526
+ decl->getTypeInContext()->getCanonicalType(),
2527
+ SGFContext());
2528
+ reabstraction = reabstracted.forward(*this);
2529
+ newValue = reabstraction;
2530
+ }
2531
+ // TODO: reabstract
2532
+ allocStack = B.createAllocStack(declarationLoc, newValue->getType(),
2533
+ std::nullopt,
2534
+ DoesNotHaveDynamicLifetime,
2535
+ IsNotLexical,
2536
+ IsNotFromVarDecl,
2537
+ DoesNotUseMoveableValueDebugInfo,
2538
+ /*skipVarDeclAssert*/ true);
2539
+ storeBorrow = B.createStoreBorrow(declarationLoc, newValue, allocStack);
2540
+ }
2541
+
2542
+ // Record the addressable representation.
2543
+ auto &addressableBuffer = VarLocs[decl].addressableBuffer;
2544
+ addressableBuffer.state
2545
+ = std::make_unique<VarLoc::AddressableBuffer::State>(reabstraction,
2546
+ allocStack,
2547
+ storeBorrow);
2548
+ auto *newState = addressableBuffer.state.get();
2549
+
2550
+ // Emit cleanups on any paths where we previously would have cleaned up
2551
+ // the addressable representation if it had been forced earlier.
2552
+ decltype(addressableBuffer.cleanupPoints) cleanupPoints;
2553
+ cleanupPoints.swap(addressableBuffer.cleanupPoints);
2554
+
2555
+ for (SILInstruction *cleanupPoint : cleanupPoints) {
2556
+ SavedInsertionPointRAII insertCleanup(B, cleanupPoint);
2557
+ deallocateAddressable(*this, cleanupPoint->getLoc(), *newState);
2558
+ cleanupPoint->eraseFromParent();
2559
+ }
2560
+
2561
+ return storeBorrow;
2562
+ }
2563
+
2409
2564
void BlackHoleInitialization::performPackExpansionInitialization(
2410
2565
SILGenFunction &SGF,
2411
2566
SILLocation loc,
@@ -2437,3 +2592,9 @@ void BlackHoleInitialization::copyOrInitValueInto(SILGenFunction &SGF, SILLocati
2437
2592
value = SGF.B.createMoveValue(loc, value);
2438
2593
SGF.B.createIgnoredUse(loc, value.getValue());
2439
2594
}
2595
+
2596
+ SILGenFunction::VarLoc::AddressableBuffer::~AddressableBuffer() {
2597
+ for (auto cleanupPoint : cleanupPoints) {
2598
+ cleanupPoint->eraseFromParent();
2599
+ }
2600
+ }
0 commit comments