@@ -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
+ SILGenFunction::VarLoc &loc) {
685
+ SGF.B .createEndBorrow (l, loc.addressableBuffer .state ->storeBorrow );
686
+ SGF.B .createDeallocStack (l, loc.addressableBuffer .state ->allocStack );
687
+ if (loc.addressableBuffer .state ->reabstraction ) {
688
+ SGF.B .createDestroyValue (l, loc.addressableBuffer .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 (loc.addressableBuffer .state ) {
708
+ // The addressable buffer was forced, so clean it up now.
709
+ deallocateAddressable (SGF, l, loc);
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,7 +2364,7 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
2309
2364
}
2310
2365
};
2311
2366
2312
- auto loc = VarLocs[vd];
2367
+ auto & loc = VarLocs[vd];
2313
2368
2314
2369
// For a heap variable, the box is responsible for the value. We just need
2315
2370
// to give up our retain count on it.
@@ -2406,6 +2461,101 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
2406
2461
llvm_unreachable (" unhandled case" );
2407
2462
}
2408
2463
2464
+ void
2465
+ SILGenFunction::enterLocalVariableAddressableBufferScope (VarDecl *decl) {
2466
+ Cleanups.pushCleanup <DeallocateLocalVariableAddressableBuffer>(decl);
2467
+ }
2468
+
2469
+ SILValue
2470
+ SILGenFunction::getLocalVariableAddressableBuffer (VarDecl *decl,
2471
+ SILLocation curLoc,
2472
+ ValueOwnership ownership) {
2473
+ auto foundVarLoc = VarLocs.find (decl);
2474
+ if (foundVarLoc == VarLocs.end ()) {
2475
+ return SILValue ();
2476
+ }
2477
+
2478
+ auto &varLoc = foundVarLoc->second ;
2479
+ SILType fullyAbstractedTy = getLoweredType (AbstractionPattern::getOpaque (),
2480
+ decl->getTypeInContext ()->getRValueType ());
2481
+
2482
+ // Check whether the bound value is inherently suitable for addressability.
2483
+ // It must already be in memory and fully abstracted.
2484
+ if (varLoc.value ->getType ().isAddress ()
2485
+ && fullyAbstractedTy.getASTType ()==varLoc.value ->getType ().getASTType ()) {
2486
+ SILValue address = varLoc.value ;
2487
+ // Begin an access if the address is mutable.
2488
+ if (varLoc.access != SILAccessEnforcement::Unknown) {
2489
+ address = B.emitBeginAccess (curLoc, address,
2490
+ ownership == ValueOwnership::InOut ? SILAccessKind::Modify
2491
+ : SILAccessKind::Read,
2492
+ varLoc.access );
2493
+ }
2494
+ return address;
2495
+ }
2496
+
2497
+ // We can't retroactively introduce a reabstracted representation for a
2498
+ // mutable binding (since we would now have two mutable memory locations
2499
+ // representing the same value).
2500
+ if (varLoc.access != SILAccessEnforcement::Unknown) {
2501
+ return SILValue ();
2502
+ }
2503
+
2504
+ assert (ownership == ValueOwnership::Shared);
2505
+
2506
+ // Check whether the in-memory representation has already been forced.
2507
+ if (auto &state = varLoc.addressableBuffer .state ) {
2508
+ return state->storeBorrow ;
2509
+ }
2510
+
2511
+ // Otherwise, force the addressable representation.
2512
+ SILValue reabstraction, allocStack, storeBorrow;
2513
+ {
2514
+ SavedInsertionPointRAII save (B);
2515
+ B.setInsertionPoint (varLoc.value ->getNextInstruction ());
2516
+ auto declarationLoc = varLoc.value ->getDefiningInsertionPoint ()->getLoc ();
2517
+
2518
+ // Reabstract if necessary.
2519
+ auto value = varLoc.value ;
2520
+ reabstraction = SILValue ();
2521
+ if (value->getType ().getASTType () != fullyAbstractedTy.getASTType ()){
2522
+ auto reabstracted = emitSubstToOrigValue (curLoc,
2523
+ ManagedValue::forBorrowedRValue (value),
2524
+ AbstractionPattern::getOpaque (),
2525
+ decl->getTypeInContext ()->getCanonicalType (),
2526
+ SGFContext ());
2527
+ reabstraction = reabstracted.forward (*this );
2528
+ value = reabstraction;
2529
+ }
2530
+ // TODO: reabstract
2531
+ allocStack = B.createAllocStack (declarationLoc, value->getType (),
2532
+ std::nullopt,
2533
+ DoesNotHaveDynamicLifetime,
2534
+ IsNotLexical,
2535
+ IsNotFromVarDecl,
2536
+ DoesNotUseMoveableValueDebugInfo,
2537
+ /* skipVarDeclAssert*/ true );
2538
+ storeBorrow = B.createStoreBorrow (declarationLoc, value, allocStack);
2539
+ }
2540
+
2541
+ // Record the addressable representation.
2542
+ varLoc.addressableBuffer .state
2543
+ = std::make_unique<VarLoc::AddressableBuffer::State>(reabstraction,
2544
+ allocStack,
2545
+ storeBorrow);
2546
+
2547
+ // Emit cleanups on any paths where we previously would have cleaned up
2548
+ // the addressable representation if it had been forced earlier.
2549
+ for (SILInstruction *cleanupPoint : varLoc.addressableBuffer .cleanupPoints ) {
2550
+ SavedInsertionPointRAII insertCleanup (B, cleanupPoint);
2551
+ deallocateAddressable (*this , cleanupPoint->getLoc (), varLoc);
2552
+ cleanupPoint->eraseFromParent ();
2553
+ }
2554
+ varLoc.addressableBuffer .cleanupPoints .clear ();
2555
+
2556
+ return storeBorrow;
2557
+ }
2558
+
2409
2559
void BlackHoleInitialization::performPackExpansionInitialization (
2410
2560
SILGenFunction &SGF,
2411
2561
SILLocation loc,
@@ -2437,3 +2587,9 @@ void BlackHoleInitialization::copyOrInitValueInto(SILGenFunction &SGF, SILLocati
2437
2587
value = SGF.B .createMoveValue (loc, value);
2438
2588
SGF.B .createIgnoredUse (loc, value.getValue ());
2439
2589
}
2590
+
2591
+ SILGenFunction::VarLoc::AddressableBuffer::~AddressableBuffer () {
2592
+ for (auto cleanupPoint : cleanupPoints) {
2593
+ cleanupPoint->eraseFromParent ();
2594
+ }
2595
+ }
0 commit comments