Skip to content

[sil-opaque-values] More SILGen support. #11038

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 18, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,8 @@ class SILBuilder {
}

LoadBorrowInst *createLoadBorrow(SILLocation Loc, SILValue LV) {
assert(LV->getType().isLoadable(F.getModule()));
assert(!SILModuleConventions(F.getModule()).useLoweredAddresses()
|| LV->getType().isLoadable(F.getModule()));
return insert(new (F.getModule())
LoadBorrowInst(getSILDebugLocation(Loc), LV));
}
Expand Down
3 changes: 2 additions & 1 deletion lib/SIL/SILVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1236,7 +1236,8 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
F.hasQualifiedOwnership(),
"Inst with qualified ownership in a function that is not qualified");
require(LBI->getType().isObject(), "Result of load must be an object");
require(LBI->getType().isLoadable(LBI->getModule()),
require(!fnConv.useLoweredAddresses()
|| LBI->getType().isLoadable(LBI->getModule()),
"Load must have a loadable type");
require(LBI->getOperand()->getType().isAddress(),
"Load operand must be an address");
Expand Down
16 changes: 12 additions & 4 deletions lib/SILGen/SILGenConvert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -907,12 +907,20 @@ SILGenFunction::emitOpenExistential(

existentialType = existentialValue.getType();
assert(existentialType.isObject());
if (loweredOpenedType.isAddress()) {
archetypeMV = ManagedValue::forUnmanaged(
B.createOpenExistentialBox(loc, existentialValue.getValue(),
loweredOpenedType));
} else {
assert(!silConv.useLoweredAddresses());
archetypeMV = ManagedValue::forUnmanaged(
B.createOpenExistentialBoxValue(loc, existentialValue.getValue(),
loweredOpenedType));
}
// NB: Don't forward the cleanup, because consuming a boxed value won't
// consume the box reference.
archetypeMV = ManagedValue::forUnmanaged(B.createOpenExistentialBox(
loc, existentialValue.getValue(), loweredOpenedType.getAddressType()));
// The boxed value can't be assumed to be uniquely referenced. We can never
// consume it.
// The boxed value can't be assumed to be uniquely referenced.
// We can never consume it.
// TODO: We could use isUniquelyReferenced to shorten the duration of
// the box to the point that the opaque value is copied out.
isUnique = false;
Expand Down
11 changes: 7 additions & 4 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ ManagedValue SILGenFunction::emitManagedLoadCopy(SILLocation loc, SILValue v,
return ManagedValue::forUnmanaged(v);
if (v.getOwnershipKind() == ValueOwnershipKind::Trivial)
return ManagedValue::forUnmanaged(v);
assert(!lowering.isAddressOnly() && "cannot retain an unloadable type");
assert((!lowering.isAddressOnly() || !silConv.useLoweredAddresses()) &&
"cannot retain an unloadable type");
return emitManagedRValueWithCleanup(v, lowering);
}

Expand All @@ -105,7 +106,8 @@ SILGenFunction::emitManagedLoadBorrow(SILLocation loc, SILValue v,
return ManagedValue::forUnmanaged(v);
}

assert(!lowering.isAddressOnly() && "cannot retain an unloadable type");
assert((!lowering.isAddressOnly() || !silConv.useLoweredAddresses()) &&
"cannot retain an unloadable type");
auto *lbi = B.createLoadBorrow(loc, v);
return emitManagedBorrowedRValueWithCleanup(v, lbi, lowering);
}
Expand All @@ -124,7 +126,8 @@ ManagedValue SILGenFunction::emitManagedStoreBorrow(
lowering.emitStore(B, loc, v, addr, StoreOwnershipQualifier::Trivial);
return ManagedValue::forUnmanaged(v);
}
assert(!lowering.isAddressOnly() && "cannot retain an unloadable type");
assert((!lowering.isAddressOnly() || !silConv.useLoweredAddresses()) &&
"cannot retain an unloadable type");
auto *sbi = B.createStoreBorrow(loc, v, addr);
return emitManagedBorrowedRValueWithCleanup(sbi->getSrc(), sbi, lowering);
}
Expand Down Expand Up @@ -3989,7 +3992,7 @@ RValue RValueEmitter::visitBindOptionalExpr(BindOptionalExpr *E, SGFContext C) {
auto &optTL = SGF.getTypeLowering(E->getSubExpr()->getType());

ManagedValue optValue;
if (optTL.isLoadable()) {
if (!SGF.silConv.useLoweredAddresses() || optTL.isLoadable()) {
optValue = SGF.emitRValueAsSingleValue(E->getSubExpr());
} else {
auto temp = SGF.emitTemporary(E, optTL);
Expand Down
78 changes: 74 additions & 4 deletions test/SILGen/opaque_values_silgen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -489,10 +489,9 @@ func s210______compErasure(_ x: Foo & Error) -> Error {
// CHECK-LABEL: sil hidden @_T020opaque_values_silgen21s220_____openExistBoxSSs5Error_pF : $@convention(thin) (@owned Error) -> @owned String {
// CHECK: bb0([[ARG:%.*]] : $Error):
// CHECK: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
// CHECK: [[OPAQUE_ARG:%.*]] = open_existential_box [[BORROWED_ARG]] : $Error to $*@opened({{.*}}) Error
// CHECK: [[LOAD_ALLOC:%.*]] = load [copy] [[OPAQUE_ARG]]
// CHECK: [[OPAQUE_ARG:%.*]] = open_existential_box_value [[BORROWED_ARG]] : $Error to $@opened({{.*}}) Error
// CHECK: [[ALLOC_OPEN:%.*]] = alloc_stack $@opened({{.*}}) Error
// CHECK: store [[LOAD_ALLOC]] to [init] [[ALLOC_OPEN]]
// CHECK: store_borrow [[OPAQUE_ARG]] to [[ALLOC_OPEN]]
// CHECK: dealloc_stack [[ALLOC_OPEN]]
// CHECK: end_borrow [[BORROWED_ARG]] from [[ARG]]
// CHECK: destroy_value [[ARG]] : $Error
Expand Down Expand Up @@ -983,7 +982,7 @@ func s460______________foo<Element>(p: UnsafePointer<Element>) -> UnsafeBufferPo
return UnsafeBufferPointer(start: p, count: 1)
}

// Test emitNativeToCBridgedNonoptionalValue
// Test emitNativeToCBridgedNonoptionalValue.
// ---
// CHECK-objc-LABEL: sil hidden @_T020opaque_values_silgen21s470________nativeToCyXlyp7fromAny_tF : $@convention(thin) (@in Any) -> @owned AnyObject {
// CHECK-objc bb0(%0 : $Any):
Expand All @@ -1003,6 +1002,77 @@ func s470________nativeToC(fromAny any: Any) -> AnyObject {
}
#endif

// Test emitOpenExistential.
// ---
// CHECK-LABEL: sil hidden @_T020opaque_values_silgen21s480_________getErroryps0F0_p04someF0_tF : $@convention(thin) (@owned Error) -> @out Any {
// CHECK: bb0(%0 : $Error):
// CHECK: [[BORROW:%.*]] = begin_borrow %0 : $Error
// CHECK: [[VAL:%.*]] = open_existential_box_value [[BORROW]] : $Error to $@opened("{{.*}}") Error
// CHECK: [[COPY:%.*]] = copy_value [[VAL]] : $@opened("{{.*}}") Error
// CHECK: [[ANY:%.*]] = init_existential_value [[COPY]] : $@opened("{{.*}}") Error, $@opened("{{.*}}") Error, $Any
// CHECK: destroy_value %0 : $Error
// CHECK: return [[ANY]] : $Any
// CHECK-LABEL: } // end sil function '_T020opaque_values_silgen21s480_________getErroryps0F0_p04someF0_tF'
func s480_________getError(someError: Error) -> Any {
return someError
}

// Test SILBuilder.createLoadBorrow.
// ---
// CHECK-LABEL: sil private @_T020opaque_values_silgen21s490_______loadBorrowyyF3FooL_V3foo7ElementQzSg5IndexQz3pos_tF : $@convention(method) <Elements where Elements : Collection> (@in Elements.Index, @inout Foo<Elements>) -> @out Optional<Elements.Element> {
// CHECK: bb0(%0 : $Elements.Index, %1 : $*Foo<Elements>):
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] %1 : $*Foo<Elements>
// CHECK: [[LOAD:%.*]] = load_borrow [[READ]] : $*Foo<Elements>
// CHECK: end_access [[READ]] : $*Foo<Elements>
// CHECK: [[EXTRACT:%.*]] = struct_extract [[LOAD]] : $Foo<Elements>, #<abstract function>Foo._elements
// CHECK: [[COPYELT:%.*]] = copy_value [[EXTRACT]] : $Elements
// CHECK: [[BORROW:%.*]] = begin_borrow %0 : $Elements.Index
// CHECK: [[COPYIDX:%.*]] = copy_value [[BORROW]] : $Elements.Index
// CHECK: [[WT:%.*]] = witness_method $Elements, #Collection.subscript!getter.1 : <Self where Self : Collection> (Self) -> (Self.Index) -> Self.Element : $@convention(witness_method) <τ_0_0 where τ_0_0 : Collection> (@in τ_0_0.Index, @in_guaranteed τ_0_0) -> @out τ_0_0.Element
// CHECK: %{{.*}} = apply [[WT]]<Elements>([[COPYIDX]], [[COPYELT]]) : $@convention(witness_method) <τ_0_0 where τ_0_0 : Collection> (@in τ_0_0.Index, @in_guaranteed τ_0_0) -> @out τ_0_0.Element
// CHECK: destroy_value [[COPYELT]] : $Elements
// CHECK: [[ENUM:%.*]] = enum $Optional<Elements.Element>, #Optional.some!enumelt.1, %12 : $Elements.Element
// CHECK: end_borrow [[BORROW]] from %0 : $Elements.Index, $Elements.Index
// CHECK: end_borrow [[LOAD]] from [[READ]] : $Foo<Elements>, $*Foo<Elements>
// CHECK: destroy_value %0 : $Elements.Index
// CHECK: return %14 : $Optional<Elements.Element>
// CHECK-LABEL: } // end sil function '_T020opaque_values_silgen21s490_______loadBorrowyyF3FooL_V3foo7ElementQzSg5IndexQz3pos_tF'

func s490_______loadBorrow() {
struct Foo<Elements : Collection> {
internal let _elements: Elements

public mutating func foo(pos: Elements.Index) -> Elements.Element? {
return _elements[pos]
}
}
var foo = Foo(_elements: [])
_ = foo.foo(pos: 1)
}

protocol ConvertibleToP {
func asP() -> P
}

// Test visitBindOptionalExpr
// ---
// CHECK-LABEL: sil hidden @_T020opaque_values_silgen21s500_______getAnyHashAA1P_pSgAA14ConvertibleToP_pSgF : $@convention(thin) (@in Optional<ConvertibleToP>) -> @out Optional<P> {
// CHECK: bb0(%0 : $Optional<ConvertibleToP>):
// CHECK: [[BORROW:%.*]] = begin_borrow %0 : $Optional<ConvertibleToP>
// CHECK: [[COPY:%.*]] = copy_value [[BORROW]] : $Optional<ConvertibleToP>
// CHECK: [[DATA:%.*]] = unchecked_enum_data [[COPY]] : $Optional<ConvertibleToP>, #Optional.some!enumelt.1
// CHECK: [[VAL:%.*]] = open_existential_value [[DATA]] : $ConvertibleToP to $@opened("{{.*}}") ConvertibleToP
// CHECK: [[WT:%.*]] = witness_method $@opened("{{.*}}") ConvertibleToP, #ConvertibleToP.asP!1 : <Self where Self : ConvertibleToP> (Self) -> () -> P, %12 : $@opened("{{.*}}") ConvertibleToP : $@convention(witness_method) <τ_0_0 where τ_0_0 : ConvertibleToP> (@in_guaranteed τ_0_0) -> @out P
// CHECK: [[AS_P:%.*]] = apply [[WT]]<@opened("{{.*}}") ConvertibleToP>(%12) : $@convention(witness_method) <τ_0_0 where τ_0_0 : ConvertibleToP> (@in_guaranteed τ_0_0) -> @out P
// CHECK: [[ENUM:%.*]] = enum $Optional<P>, #Optional.some!enumelt.1, [[AS_P]] : $P
// CHECK: destroy_value [[DATA]] : $ConvertibleToP
// CHECK: end_borrow [[BORROW]] from %0 : $Optional<ConvertibleToP>, $Optional<ConvertibleToP>
// CHECK: br bb{{.*}}([[ENUM]] : $Optional<P>)
// CHECK: // end sil function '_T020opaque_values_silgen21s500_______getAnyHashAA1P_pSgAA14ConvertibleToP_pSgF'
func s500_______getAnyHash(_ value: ConvertibleToP?) -> P? {
return value?.asP()
}

// Tests conditional value casts and correspondingly generated reabstraction thunk, with <T> types
// ---
// CHECK-LABEL: sil hidden @_T020opaque_values_silgen21s999_____condTFromAnyyyp_xtlF : $@convention(thin) <T> (@in Any, @in T) -> () {
Expand Down