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