Skip to content

Commit a25edb2

Browse files
committed
Make Builtin.addressForBorrow work with addressable parameters.
1 parent 5c4406b commit a25edb2

File tree

4 files changed

+111
-42
lines changed

4 files changed

+111
-42
lines changed

lib/SILGen/SILGenApply.cpp

+33-23
Original file line numberDiff line numberDiff line change
@@ -3410,6 +3410,34 @@ Expr *ArgumentSource::findStorageReferenceExprForBorrow() && {
34103410
return lvExpr;
34113411
}
34123412

3413+
ManagedValue
3414+
SILGenFunction::tryEmitAddressableParameterAsAddress(ArgumentSource &&arg,
3415+
ValueOwnership ownership) {
3416+
// If the function takes an addressable parameter, and its argument is
3417+
// a reference to an addressable declaration with compatible ownership,
3418+
// forward the address along in-place.
3419+
if (arg.isExpr()) {
3420+
auto origExpr = std::move(arg).asKnownExpr();
3421+
auto expr = origExpr;
3422+
3423+
if (auto le = dyn_cast<LoadExpr>(expr)) {
3424+
expr = le->getSubExpr();
3425+
}
3426+
if (auto dre = dyn_cast<DeclRefExpr>(expr)) {
3427+
if (auto param = dyn_cast<ParamDecl>(dre->getDecl())) {
3428+
if (VarLocs.count(param)
3429+
&& VarLocs[param].addressable
3430+
&& param->getValueOwnership() == ownership) {
3431+
auto addr = VarLocs[param].value;
3432+
return ManagedValue::forBorrowedAddressRValue(addr);
3433+
}
3434+
}
3435+
}
3436+
arg = ArgumentSource(origExpr);
3437+
}
3438+
return ManagedValue();
3439+
}
3440+
34133441
namespace {
34143442

34153443
class ArgEmitter {
@@ -3515,29 +3543,11 @@ class ArgEmitter {
35153543
// If the function takes an addressable parameter, and its argument is
35163544
// a reference to an addressable declaration with compatible ownership,
35173545
// forward the address along in-place.
3518-
if (arg.isExpr()) {
3519-
arg.dump();
3520-
auto origExpr = std::move(arg).asKnownExpr();
3521-
auto expr = origExpr;
3522-
3523-
if (auto le = dyn_cast<LoadExpr>(expr)) {
3524-
expr = le->getSubExpr();
3525-
}
3526-
if (auto dre = dyn_cast<DeclRefExpr>(expr)) {
3527-
if (auto param = dyn_cast<ParamDecl>(dre->getDecl())) {
3528-
if (SGF.VarLocs.count(param)
3529-
&& SGF.VarLocs[param].addressable
3530-
&& param->getValueOwnership() == origParam->getValueOwnership()) {
3531-
auto addr = SGF.VarLocs[param].value;
3532-
claimNextParameters(1);
3533-
Args.push_back(ManagedValue::forBorrowedAddressRValue(addr));
3534-
return;
3535-
}
3536-
}
3537-
}
3538-
llvm::errs() << "couldn't lower as addressable\n";
3539-
arg = ArgumentSource(origExpr);
3540-
arg.dump();
3546+
if (auto addr = SGF.tryEmitAddressableParameterAsAddress(std::move(arg),
3547+
origParam->getValueOwnership())) {
3548+
claimNextParameters(1);
3549+
Args.push_back(addr);
3550+
return;
35413551
}
35423552
}
35433553

lib/SILGen/SILGenBuiltin.cpp

+30-19
Original file line numberDiff line numberDiff line change
@@ -492,27 +492,38 @@ static ManagedValue emitBuiltinAddressOfBorrowBuiltins(SILGenFunction &SGF,
492492
auto argument = (*argsOrError)[0];
493493

494494
SILValue addr;
495-
// Try to borrow the argument at +0. We only support if it's
496-
// naturally emitted borrowed in memory.
497-
auto borrow = SGF.emitRValue(argument, SGFContext::AllowGuaranteedPlusZero)
498-
.getAsSingleValue(SGF, argument);
499-
if (!SGF.F.getConventions().useLoweredAddresses()) {
500-
auto &context = SGF.getASTContext();
501-
auto identifier =
502-
stackProtected
503-
? context.getIdentifier("addressOfBorrowOpaque")
504-
: context.getIdentifier("unprotectedAddressOfBorrowOpaque");
505-
auto builtin = SGF.B.createBuiltin(loc, identifier, rawPointerType,
506-
substitutions, {borrow.getValue()});
507-
return ManagedValue::forObjectRValueWithoutOwnership(builtin);
508-
}
495+
// Try to borrow the argument at +0 indirect.
496+
// If the argument is a reference to a borrowed addressable parameter, then
497+
// use that parameter's stable address.
498+
if (auto addressableAddr = SGF.tryEmitAddressableParameterAsAddress(
499+
ArgumentSource(argument),
500+
ValueOwnership::Shared)) {
501+
addr = addressableAddr.getValue();
502+
} else {
503+
// We otherwise only support the builtin applied to values that
504+
// are naturally emitted borrowed in memory. (But it would probably be good
505+
// to phase this out since it's not really well-defined how long
506+
// the resulting pointer is good for without something like addressability.)
507+
auto borrow = SGF.emitRValue(argument, SGFContext::AllowGuaranteedPlusZero)
508+
.getAsSingleValue(SGF, argument);
509+
if (!SGF.F.getConventions().useLoweredAddresses()) {
510+
auto &context = SGF.getASTContext();
511+
auto identifier =
512+
stackProtected
513+
? context.getIdentifier("addressOfBorrowOpaque")
514+
: context.getIdentifier("unprotectedAddressOfBorrowOpaque");
515+
auto builtin = SGF.B.createBuiltin(loc, identifier, rawPointerType,
516+
substitutions, {borrow.getValue()});
517+
return ManagedValue::forObjectRValueWithoutOwnership(builtin);
518+
}
509519

510-
if (!borrow.isPlusZero() || !borrow.getType().isAddress()) {
511-
SGF.SGM.diagnose(argument->getLoc(), diag::non_borrowed_indirect_addressof);
512-
return SGF.emitUndef(rawPointerType);
513-
}
520+
if (!borrow.isPlusZero() || !borrow.getType().isAddress()) {
521+
SGF.SGM.diagnose(argument->getLoc(), diag::non_borrowed_indirect_addressof);
522+
return SGF.emitUndef(rawPointerType);
523+
}
514524

515-
addr = borrow.getValue();
525+
addr = borrow.getValue();
526+
}
516527

517528
// Take the address argument and cast it to RawPointer.
518529
SILValue result = SGF.B.createAddressToPointer(loc, addr, rawPointerType,

lib/SILGen/SILGenFunction.h

+10
Original file line numberDiff line numberDiff line change
@@ -1424,6 +1424,16 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
14241424
ManagedValue manageBufferForExprResult(SILValue buffer,
14251425
const TypeLowering &bufferTL,
14261426
SGFContext C);
1427+
1428+
/// Tries to emit an argument referring to an addressable parameter as the
1429+
/// stable address of the parameter.
1430+
///
1431+
/// Returns a null ManagedValue if the argument is not a parameter reference,
1432+
/// the referenced parameter is not addressable, or the requested
1433+
/// \c ownership is not compatible with the parameter's ownership. \c arg
1434+
/// is consumed only if the operation succeeds.
1435+
ManagedValue tryEmitAddressableParameterAsAddress(ArgumentSource &&arg,
1436+
ValueOwnership ownership);
14271437

14281438
//===--------------------------------------------------------------------===//
14291439
// Type conversions for expr emission and thunks
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// RUN: %target-swift-frontend -emit-sil -enable-experimental-feature BuiltinModule -enable-experimental-feature LifetimeDependence -enable-experimental-feature AddressableTypes %s | %FileCheck %s
2+
3+
// REQUIRES: swift_feature_BuiltinModule
4+
// REQUIRES: swift_feature_AddressableTypes
5+
// REQUIRES: swift_feature_LifetimeDependence
6+
7+
import Builtin
8+
9+
@_addressableForDependencies
10+
struct Node {
11+
var id: String
12+
13+
var ref: NodeRef {
14+
// CHECK-LABEL: sil {{.*}}@${{.*}}4NodeV3ref{{.*}}Vvg :
15+
// CHECK-SAME: (@in_guaranteed Node) ->
16+
@lifetime(borrow self)
17+
borrowing get {
18+
// CHECK: bb0(%0 : @noImplicitCopy $*Node):
19+
// CHECK: [[REF:%.*]] = apply {{.*}}(%0,
20+
// CHECK: mark_dependence [nonescaping] [[REF]] on %0
21+
return NodeRef(node: self)
22+
}
23+
}
24+
}
25+
26+
struct NodeRef: ~Escapable {
27+
private var parent: UnsafePointer<Node>
28+
29+
// CHECK-LABEL: sil {{.*}}@${{.*}}7NodeRefV4node{{.*}}fC :
30+
// CHECK-SAME: (@in_guaranteed Node,
31+
@lifetime(borrow node)
32+
init(node: borrowing Node) {
33+
// CHECK: bb0(%0 : @noImplicitCopy $*Node,
34+
// CHECK: [[RAW_PTR:%.*]] = address_to_pointer {{.*}}%0
35+
// CHECK: struct $UnsafePointer<Node> ([[RAW_PTR]])
36+
self.parent = UnsafePointer(Builtin.addressOfBorrow(node))
37+
}
38+
}

0 commit comments

Comments
 (0)