@@ -3539,27 +3539,198 @@ Expr *ArgumentSource::findStorageReferenceExprForBorrow() && {
3539
3539
ManagedValue
3540
3540
SILGenFunction::tryEmitAddressableParameterAsAddress (ArgumentSource &&arg,
3541
3541
ValueOwnership ownership) {
3542
+ if (!arg.isExpr ()) {
3543
+ return ManagedValue ();
3544
+ }
3545
+
3542
3546
// If the function takes an addressable parameter, and its argument is
3543
3547
// a reference to an addressable declaration with compatible ownership,
3544
3548
// forward the address along in-place.
3545
- if (arg.isExpr ()) {
3546
- auto origExpr = std::move (arg).asKnownExpr ();
3547
- auto expr = origExpr;
3549
+ auto origExpr = std::move (arg).asKnownExpr ();
3550
+ auto expr = origExpr;
3551
+
3552
+ // If the expression does not have a stable address to return, then restore
3553
+ // the ArgumentSource and return a null value to the caller.
3554
+ auto notAddressable = [&] {
3555
+ arg = ArgumentSource (origExpr);
3556
+ return ManagedValue ();
3557
+ };
3558
+
3559
+ if (auto le = dyn_cast<LoadExpr>(expr)) {
3560
+ expr = le->getSubExpr ();
3561
+ }
3562
+ if (auto dre = dyn_cast<DeclRefExpr>(expr)) {
3563
+ if (auto param = dyn_cast<VarDecl>(dre->getDecl ())) {
3564
+ if (auto addr = getLocalVariableAddressableBuffer (param, expr,
3565
+ ownership)) {
3566
+ return ManagedValue::forBorrowedAddressRValue (addr);
3567
+ }
3568
+ }
3569
+ }
3570
+
3571
+ // Property or subscript member accesses may also be addressable.
3572
+
3573
+ AccessKind accessKind;
3574
+ switch (ownership) {
3575
+ case ValueOwnership::Shared:
3576
+ case ValueOwnership::Default:
3577
+ accessKind = AccessKind::Read;
3578
+ break ;
3579
+ case ValueOwnership::Owned:
3580
+ case ValueOwnership::InOut:
3581
+ accessKind = AccessKind::ReadWrite;
3582
+ break ;
3583
+ }
3584
+
3585
+ LookupExpr *lookupExpr;
3586
+ AbstractStorageDecl *memberStorage;
3587
+ SubstitutionMap subs;
3588
+ AccessSemantics accessSemantics;
3589
+ PreparedArguments indices;
3590
+
3591
+ if (auto mre = dyn_cast<MemberRefExpr>(expr)) {
3592
+ lookupExpr = mre;
3593
+ memberStorage = dyn_cast<VarDecl>(mre->getMember ().getDecl ());
3594
+ subs = mre->getMember ().getSubstitutions ();
3595
+ accessSemantics = mre->getAccessSemantics ();
3596
+ } else if (auto se = dyn_cast<SubscriptExpr>(expr)) {
3597
+ lookupExpr = se;
3598
+ auto subscriptDecl = cast<SubscriptDecl>(se->getMember ().getDecl ());
3599
+ memberStorage = subscriptDecl;
3600
+ subs = se->getMember ().getSubstitutions ();
3601
+ accessSemantics = se->getAccessSemantics ();
3548
3602
3549
- if (auto le = dyn_cast<LoadExpr>(expr)) {
3550
- expr = le->getSubExpr ();
3551
- }
3552
- if (auto dre = dyn_cast<DeclRefExpr>(expr)) {
3553
- if (auto param = dyn_cast<VarDecl>(dre->getDecl ())) {
3554
- if (auto addr = getLocalVariableAddressableBuffer (param, expr,
3555
- ownership)) {
3556
- return ManagedValue::forBorrowedAddressRValue (addr);
3557
- }
3603
+ indices = PreparedArguments (
3604
+ subscriptDecl->getInterfaceType ()->castTo <AnyFunctionType>()
3605
+ ->getParams (),
3606
+ se->getArgs ());
3607
+ } else {
3608
+ return notAddressable ();
3609
+ }
3610
+
3611
+ if (!memberStorage) {
3612
+ return notAddressable ();
3613
+ }
3614
+
3615
+ auto strategy = memberStorage->getAccessStrategy (accessSemantics, accessKind,
3616
+ SGM.M .getSwiftModule (), F.getResilienceExpansion (),
3617
+ std::make_pair<>(expr->getSourceRange (), FunctionDC),
3618
+ /* old abi (doesn't matter here)*/ false );
3619
+
3620
+ switch (strategy.getKind ()) {
3621
+ case AccessStrategy::Storage: {
3622
+ auto vd = cast<VarDecl>(memberStorage);
3623
+ // TODO: Is it possible and/or useful for class storage to be
3624
+ // addressable?
3625
+ if (!vd->getDeclContext ()->getInnermostTypeContext ()
3626
+ ->getDeclaredTypeInContext ()->getStructOrBoundGenericStruct ()) {
3627
+ return notAddressable ();
3628
+ }
3629
+
3630
+ // If the storage holds the fully-abstracted representation of the
3631
+ // type, then we can use its address.
3632
+ auto absBaseTy = getLoweredType (AbstractionPattern::getOpaque (),
3633
+ lookupExpr->getBase ()->getType ()->getWithoutSpecifierType ());
3634
+ auto memberTy = absBaseTy.getFieldType (vd, &F);
3635
+ auto absMemberTy = getLoweredType (AbstractionPattern::getOpaque (),
3636
+ lookupExpr->getType ()->getWithoutSpecifierType ());
3637
+
3638
+ if (memberTy.getAddressType () != absMemberTy.getAddressType ()) {
3639
+ // The storage is not fully abstracted, so it can't serve as a
3640
+ // stable address.
3641
+ return notAddressable ();
3642
+ }
3643
+
3644
+ // Otherwise, we can project the field address from the stable address
3645
+ // of the base, if it has one. Try to get the stable address for the
3646
+ // base.
3647
+ auto baseAddr = tryEmitAddressableParameterAsAddress (
3648
+ ArgumentSource (lookupExpr->getBase ()), ownership);
3649
+
3650
+ if (!baseAddr) {
3651
+ return notAddressable ();
3652
+ }
3653
+
3654
+ // Project the field's address.
3655
+ auto fieldAddr = B.createStructElementAddr (lookupExpr,
3656
+ baseAddr.getValue (), vd);
3657
+ return ManagedValue::forBorrowedAddressRValue (fieldAddr);
3658
+ }
3659
+
3660
+ case AccessStrategy::DirectToAccessor:
3661
+ case AccessStrategy::DispatchToAccessor: {
3662
+ // Non-addressor accessors don't produce stable addresses.
3663
+ if (strategy.getAccessor () != AccessorKind::Address
3664
+ && strategy.getAccessor () != AccessorKind::MutableAddress) {
3665
+ return notAddressable ();
3666
+ }
3667
+ // TODO: Non-yielding borrow/mutate accessors can also be considered
3668
+ // addressable when we have those.
3669
+
3670
+ auto addressor = memberStorage->getAccessor (strategy.getAccessor ());
3671
+ auto addressorRef = SILDeclRef (addressor, SILDeclRef::Kind::Func);
3672
+ auto absMemberTy = getLoweredType (AbstractionPattern::getOpaque (),
3673
+ lookupExpr->getType ()->getWithoutSpecifierType ())
3674
+ .getAddressType ();
3675
+
3676
+ // Evaluate the base in the current formal access scope.
3677
+ ManagedValue base;
3678
+ // If the addressor wants the base addressable, try to honor that
3679
+ // request.
3680
+ auto addressorSelf = addressor->getImplicitSelfDecl ();
3681
+ if (addressorSelf->isAddressable ()
3682
+ || getTypeLowering (lookupExpr->getBase ()->getType ()
3683
+ ->getWithoutSpecifierType ())
3684
+ .getRecursiveProperties ().isAddressableForDependencies ()) {
3685
+ ValueOwnership baseOwnership = addressorSelf->isInOut ()
3686
+ ? ValueOwnership::InOut
3687
+ : ValueOwnership::Shared;
3688
+
3689
+ base = tryEmitAddressableParameterAsAddress (
3690
+ ArgumentSource (lookupExpr->getBase ()), baseOwnership);
3691
+ }
3692
+
3693
+ // Otherwise, project the base as an lvalue.
3694
+ if (!base) {
3695
+ SGFAccessKind silAccess;
3696
+ switch (accessKind) {
3697
+ case AccessKind::Read:
3698
+ silAccess = SGFAccessKind::BorrowedAddressRead;
3699
+ break ;
3700
+ case AccessKind::ReadWrite:
3701
+ case AccessKind::Write:
3702
+ silAccess = SGFAccessKind::ReadWrite;
3703
+ break ;
3558
3704
}
3705
+
3706
+ LValue lv = emitLValue (lookupExpr, silAccess);
3707
+
3708
+ drillToLastComponent (lookupExpr->getBase (), std::move (lv), base);
3559
3709
}
3560
- arg = ArgumentSource (origExpr);
3710
+
3711
+ // Materialize the base outside of the scope of the addressor call,
3712
+ // since the returned address may depend on the materialized
3713
+ // representation, even if it isn't transitively addressable.
3714
+ auto baseTy = lookupExpr->getBase ()->getType ()->getCanonicalType ();
3715
+ ArgumentSource baseArg = prepareAccessorBaseArgForFormalAccess (
3716
+ lookupExpr->getBase (), base, baseTy, addressorRef);
3717
+
3718
+ // Invoke the addressor to directly produce the address.
3719
+ return emitAddressorAccessor (lookupExpr,
3720
+ addressorRef, subs,
3721
+ std::move (baseArg),
3722
+ /* super*/ false , /* direct accessor use*/ true ,
3723
+ std::move (indices),
3724
+ absMemberTy, /* on self*/ false );
3561
3725
}
3562
- return ManagedValue ();
3726
+
3727
+ case AccessStrategy::MaterializeToTemporary:
3728
+ case AccessStrategy::DispatchToDistributedThunk:
3729
+ // These strategies never produce a value with a stable address.
3730
+ return notAddressable ();
3731
+ }
3732
+
3733
+ llvm_unreachable (" uncovered switch!" );
3563
3734
}
3564
3735
3565
3736
namespace {
@@ -7284,6 +7455,34 @@ ArgumentSource AccessorBaseArgPreparer::prepare() {
7284
7455
return prepareAccessorObjectBaseArg ();
7285
7456
}
7286
7457
7458
+ ArgumentSource SILGenFunction::prepareAccessorBaseArgForFormalAccess (
7459
+ SILLocation loc,
7460
+ ManagedValue base,
7461
+ CanType baseFormalType,
7462
+ SILDeclRef accessor) {
7463
+ if (!base) {
7464
+ return ArgumentSource ();
7465
+ }
7466
+
7467
+ base = base.formalAccessBorrow (*this , loc);
7468
+ // If the base needs to be materialized, do so in
7469
+ // the outer formal evaluation scope, since an addressor or
7470
+ // other dependent value may want to point into the materialization.
7471
+ auto &baseInfo = getConstantInfo (getTypeExpansionContext (), accessor);
7472
+
7473
+ if (!baseInfo.FormalPattern .isForeign ()) {
7474
+ auto baseFnTy = baseInfo.SILFnType ;
7475
+
7476
+ if (baseFnTy->getSelfParameter ().isFormalIndirect ()
7477
+ && base.getType ().isObject ()
7478
+ && silConv.useLoweredAddresses ()) {
7479
+ base = base.formallyMaterialize (*this , loc);
7480
+ }
7481
+ }
7482
+
7483
+ return prepareAccessorBaseArg (loc, base, baseFormalType, accessor);
7484
+ }
7485
+
7287
7486
ArgumentSource SILGenFunction::prepareAccessorBaseArg (SILLocation loc,
7288
7487
ManagedValue base,
7289
7488
CanType baseFormalType,
@@ -7603,10 +7802,7 @@ ManagedValue SILGenFunction::emitAddressorAccessor(
7603
7802
7604
7803
emission.addCallSite (loc, std::move (subscriptIndices));
7605
7804
7606
- // Unsafe{Mutable}Pointer<T> or
7607
- // (Unsafe{Mutable}Pointer<T>, Builtin.UnknownPointer) or
7608
- // (Unsafe{Mutable}Pointer<T>, Builtin.NativePointer) or
7609
- // (Unsafe{Mutable}Pointer<T>, Builtin.NativePointer?) or
7805
+ // Result must be Unsafe{Mutable}Pointer<T>
7610
7806
SmallVector<ManagedValue, 2 > results;
7611
7807
emission.apply ().getAll (results);
7612
7808
0 commit comments