Skip to content

Commit 4eaabd1

Browse files
authored
Merge pull request #14461 from jckarter/open-existential-lvalue-evaluation-order-5.0
[5.0] SILGen: Open existential lvalues on entry into an OpenExistentialExpr again.
2 parents a839a9d + 9a42ce1 commit 4eaabd1

File tree

7 files changed

+73
-54
lines changed

7 files changed

+73
-54
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5091,15 +5091,34 @@ RValue RValueEmitter::emitForceValue(ForceValueExpr *loc, Expr *E,
50915091
void SILGenFunction::emitOpenExistentialExprImpl(
50925092
OpenExistentialExpr *E,
50935093
llvm::function_ref<void(Expr *)> emitSubExpr) {
5094-
Optional<FormalEvaluationScope> writebackScope;
5095-
50965094
// Emit the existential value.
50975095
if (E->getExistentialValue()->getType()->is<LValueType>()) {
5098-
bool inserted = OpaqueValueExprs.insert({E->getOpaqueValue(), E}).second;
5096+
// Open the existential container right away. We need the dynamic type
5097+
// to be opened in order to evaluate the subexpression.
5098+
AccessKind accessKind;
5099+
if (E->hasLValueAccessKind())
5100+
accessKind = E->getLValueAccessKind();
5101+
else
5102+
accessKind = E->getExistentialValue()->getLValueAccessKind();
5103+
auto lv = emitLValue(E->getExistentialValue(), accessKind);
5104+
auto formalOpenedType = E->getOpaqueValue()->getType()
5105+
->getWithoutSpecifierType()
5106+
->getCanonicalType();
5107+
lv = emitOpenExistentialLValue(E, std::move(lv),
5108+
CanArchetypeType(E->getOpenedArchetype()),
5109+
formalOpenedType,
5110+
accessKind);
5111+
5112+
auto addr = emitAddressOfLValue(E, std::move(lv), accessKind);
5113+
bool inserted = OpaqueLValues.insert({E->getOpaqueValue(),
5114+
{addr.getValue(), formalOpenedType}})
5115+
.second;
50995116
(void)inserted;
51005117
assert(inserted && "already have this opened existential?");
51015118

51025119
emitSubExpr(E->getSubExpr());
5120+
assert(OpaqueLValues.count(E->getOpaqueValue()) == 0
5121+
&& "opened existential not removed?");
51035122
return;
51045123
}
51055124

@@ -5126,6 +5145,12 @@ RValue RValueEmitter::visitOpenExistentialExpr(OpenExistentialExpr *E,
51265145
return RValue(SGF, E, *result);
51275146
}
51285147

5148+
Optional<FormalEvaluationScope> scope;
5149+
// Begin an evaluation scope for an lvalue existential opened into an
5150+
// rvalue expression.
5151+
if (E->getExistentialValue()->getType()->is<LValueType>())
5152+
scope.emplace(SGF);
5153+
51295154
return SGF.emitOpenExistentialExpr<RValue>(E,
51305155
[&](Expr *subExpr) -> RValue {
51315156
return visit(subExpr, C);

lib/SILGen/SILGenFunction.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,10 +1417,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
14171417
llvm::SmallDenseMap<OpaqueValueExpr *, OpaqueValueState>
14181418
OpaqueValues;
14191419

1420-
/// A mapping from opaque value expressions to the open-existential
1421-
/// expression that determines them, used while lowering lvalues.
1422-
llvm::SmallDenseMap<OpaqueValueExpr *, OpenExistentialExpr *>
1423-
OpaqueValueExprs;
1420+
/// A mapping from opaque value lvalue expressions to the address of the
1421+
/// opened value in memory.
1422+
llvm::SmallDenseMap<OpaqueValueExpr *, std::pair<SILValue, CanType>>
1423+
OpaqueLValues;
14241424

14251425
/// RAII object that introduces a temporary binding for an opaque value.
14261426
///

lib/SILGen/SILGenLValue.cpp

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,20 +2208,18 @@ LValue SILGenLValue::visitOpaqueValueExpr(OpaqueValueExpr *e,
22082208
AccessKind accessKind,
22092209
LValueOptions options) {
22102210
// Handle an opaque lvalue that refers to an opened existential.
2211-
auto known = SGF.OpaqueValueExprs.find(e);
2212-
if (known != SGF.OpaqueValueExprs.end()) {
2213-
// Dig the open-existential expression out of the list.
2214-
OpenExistentialExpr *opened = known->second;
2215-
SGF.OpaqueValueExprs.erase(known);
2216-
2217-
// Do formal evaluation of the underlying existential lvalue.
2218-
auto lv = visitRec(opened->getExistentialValue(), accessKind, options);
2219-
lv = SGF.emitOpenExistentialLValue(
2220-
opened, std::move(lv),
2221-
CanArchetypeType(opened->getOpenedArchetype()),
2222-
e->getType()->getWithoutSpecifierType()->getCanonicalType(),
2223-
accessKind);
2224-
return lv;
2211+
auto known = SGF.OpaqueLValues.find(e);
2212+
if (known != SGF.OpaqueLValues.end()) {
2213+
// Dig the opened address out of the list.
2214+
SILValue opened = known->second.first;
2215+
CanType openedType = known->second.second;
2216+
SGF.OpaqueLValues.erase(known);
2217+
2218+
// Continue formal evaluation of the lvalue from this address.
2219+
return LValue::forAddress(ManagedValue::forLValue(opened),
2220+
None,
2221+
AbstractionPattern(openedType),
2222+
openedType);
22252223
}
22262224

22272225
assert(SGF.OpaqueValues.count(e) && "Didn't bind OpaqueValueExpr");
@@ -2513,29 +2511,12 @@ LValue SILGenLValue::visitTupleElementExpr(TupleElementExpr *e,
25132511
LValue SILGenLValue::visitOpenExistentialExpr(OpenExistentialExpr *e,
25142512
AccessKind accessKind,
25152513
LValueOptions options) {
2516-
// If the opaque value is not an lvalue, open the existential immediately.
2517-
if (!e->getOpaqueValue()->getType()->is<LValueType>()) {
2518-
return SGF.emitOpenExistentialExpr<LValue>(e,
2519-
[&](Expr *subExpr) -> LValue {
2520-
return visitRec(subExpr,
2521-
accessKind,
2522-
options);
2523-
});
2524-
}
2525-
2526-
// Record the fact that we're opening this existential. The actual
2527-
// opening operation will occur when we see the OpaqueValueExpr.
2528-
bool inserted = SGF.OpaqueValueExprs.insert({e->getOpaqueValue(), e}).second;
2529-
(void)inserted;
2530-
assert(inserted && "already have this opened existential?");
2531-
2532-
// Visit the subexpression.
2533-
LValue lv = visitRec(e->getSubExpr(), accessKind, options);
2534-
2535-
// Sanity check that we did see the OpaqueValueExpr.
2536-
assert(SGF.OpaqueValueExprs.count(e->getOpaqueValue()) == 0 &&
2537-
"opened existential not removed?");
2538-
return lv;
2514+
return SGF.emitOpenExistentialExpr<LValue>(e,
2515+
[&](Expr *subExpr) -> LValue {
2516+
return visitRec(subExpr,
2517+
accessKind,
2518+
options);
2519+
});
25392520
}
25402521

25412522
static LValueTypeData

test/SILGen/assignment.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ protocol P {
4343
// CHECK-LABEL: sil hidden @$S10assignment15copyRightToLeft1pyAA1P_pz_tF : $@convention(thin) (@inout P) -> () {
4444
func copyRightToLeft(p: inout P) {
4545
// CHECK: bb0(%0 : @trivial $*P):
46+
// CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*P
47+
// CHECK: [[WRITE_OPEN:%.*]] = open_existential_addr mutable_access [[WRITE]]
4648
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] %0 : $*P
4749
// CHECK: [[READ_OPEN:%.*]] = open_existential_addr immutable_access [[READ]]
4850
// CHECK: end_access [[READ]] : $*P
49-
// CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*P
50-
// CHECK: [[WRITE_OPEN:%.*]] = open_existential_addr mutable_access [[WRITE]]
5151
// CHECK: end_access [[WRITE]] : $*P
5252
p.left = p.right
5353
}

test/SILGen/class_bound_protocols.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,22 +192,23 @@ func takesInheritsMutatingMethod(x: inout InheritsMutatingMethod,
192192
// CHECK-NEXT: [[X_PAYLOAD:%.*]] = open_existential_ref [[X_VALUE]] : $InheritsMutatingMethod to $@opened("{{.*}}") InheritsMutatingMethod
193193
// CHECK-NEXT: [[TEMPORARY:%.*]] = alloc_stack $@opened("{{.*}}") InheritsMutatingMethod
194194
// CHECK-NEXT: store [[X_PAYLOAD]] to [init] [[TEMPORARY]] : $*@opened("{{.*}}") InheritsMutatingMethod
195-
// CHECK-NEXT: [[X_PAYLOAD_RELOADED:%.*]] = load [take] [[TEMPORARY]]
195+
// CHECK-NEXT: [[X_PAYLOAD_RELOADED:%.*]] = load_borrow [[TEMPORARY]]
196196
//
197197
// ** *NOTE* This extra copy is here since RValue invariants enforce that all
198198
// ** loadable objects are actually loaded. So we form the RValue and
199199
// ** load... only to then need to store the value back in a stack location to
200200
// ** pass to an in_guaranteed method. PredictableMemOpts is able to handle this
201201
// ** type of temporary codegen successfully.
202202
// CHECK-NEXT: [[TEMPORARY_2:%.*]] = alloc_stack $@opened("{{.*}}") InheritsMutatingMethod
203-
// CHECK-NEXT: store [[X_PAYLOAD_RELOADED:%.*]] to [init] [[TEMPORARY_2]]
203+
// CHECK-NEXT: store_borrow [[X_PAYLOAD_RELOADED:%.*]] to [[TEMPORARY_2]]
204204
//
205205
// CHECK-NEXT: [[METHOD:%.*]] = witness_method $@opened("{{.*}}") InheritsMutatingMethod, #HasMutatingMethod.mutatingCounter!getter.1 : <Self where Self : HasMutatingMethod> (Self) -> () -> Value, [[X_PAYLOAD]] : $@opened("{{.*}}") InheritsMutatingMethod : $@convention(witness_method: HasMutatingMethod) <τ_0_0 where τ_0_0 : HasMutatingMethod> (@in_guaranteed τ_0_0) -> Value
206206
// CHECK-NEXT: [[RESULT_VALUE:%.*]] = apply [[METHOD]]<@opened("{{.*}}") InheritsMutatingMethod>([[TEMPORARY_2]]) : $@convention(witness_method: HasMutatingMethod) <τ_0_0 where τ_0_0 : HasMutatingMethod> (@in_guaranteed τ_0_0) -> Value
207-
// CHECK-NEXT: destroy_addr [[TEMPORARY_2]] : $*@opened("{{.*}}") InheritsMutatingMethod
208207
// CHECK-NEXT: dealloc_stack [[TEMPORARY_2]]
209-
// CHECK-NEXT: end_access [[X_ADDR]] : $*InheritsMutatingMethod
208+
// CHECK-NEXT: end_borrow [[X_PAYLOAD_RELOADED]]
210209
// CHECK-NEXT: assign [[RESULT_VALUE]] to [[RESULT]] : $*Value
210+
// CHECK-NEXT: destroy_addr [[TEMPORARY]]
211+
// CHECK-NEXT: end_access [[X_ADDR]]
211212
// CHECK-NEXT: dealloc_stack [[TEMPORARY]] : $*@opened("{{.*}}") InheritsMutatingMethod
212213
// CHECK-NEXT: dealloc_stack [[RESULT_BOX]] : $*Value
213214
_ = x.mutatingCounter

test/SILGen/properties.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,12 +1190,12 @@ protocol NonmutatingProtocol {
11901190
// CHECK-NEXT: [[C_FIELD_PAYLOAD:%.*]] = open_existential_addr immutable_access [[C_FIELD_BOX]] : $*NonmutatingProtocol to $*@opened("{{.*}}") NonmutatingProtocol
11911191
// CHECK-NEXT: [[C_FIELD_COPY:%.*]] = alloc_stack $@opened("{{.*}}") NonmutatingProtocol
11921192
// CHECK-NEXT: copy_addr [[C_FIELD_PAYLOAD]] to [initialization] [[C_FIELD_COPY]] : $*@opened("{{.*}}") NonmutatingProtocol
1193-
// CHECK-NEXT: destroy_addr [[C_FIELD_BOX]] : $*NonmutatingProtocol
1194-
// CHECK-NEXT: destroy_value [[C]] : $ReferenceType
11951193
// CHECK-NEXT: [[GETTER:%.*]] = witness_method $@opened("{{.*}}") NonmutatingProtocol, #NonmutatingProtocol.x!getter.1 : <Self where Self : NonmutatingProtocol> (Self) -> () -> Int, [[C_FIELD_PAYLOAD]] : $*@opened("{{.*}}") NonmutatingProtocol : $@convention(witness_method: NonmutatingProtocol) <τ_0_0 where τ_0_0 : NonmutatingProtocol> (@in_guaranteed τ_0_0) -> Int
11961194
// CHECK-NEXT: [[RESULT_VALUE:%.*]] = apply [[GETTER]]<@opened("{{.*}}") NonmutatingProtocol>([[C_FIELD_COPY]]) : $@convention(witness_method: NonmutatingProtocol) <τ_0_0 where τ_0_0 : NonmutatingProtocol> (@in_guaranteed τ_0_0) -> Int
11971195
// CHECK-NEXT: assign [[RESULT_VALUE]] to [[UNINIT]] : $*Int
11981196
// CHECK-NEXT: destroy_addr [[C_FIELD_COPY]] : $*@opened("{{.*}}") NonmutatingProtocol
1197+
// CHECK-NEXT: destroy_addr [[C_FIELD_BOX]] : $*NonmutatingProtocol
1198+
// CHECK-NEXT: destroy_value [[C]] : $ReferenceType
11991199
// CHECK-NEXT: dealloc_stack [[C_FIELD_COPY]] : $*@opened("{{.*}}") NonmutatingProtocol
12001200
// CHECK-NEXT: dealloc_stack [[C_FIELD_BOX]] : $*NonmutatingProtocol
12011201
// CHECK-NEXT: dealloc_stack [[RESULT]] : $*Int

test/SILGen/protocols.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ func use_subscript_rvalue_get(_ i : Int) -> Int {
2626
// CHECK: [[PROJ:%[0-9]+]] = open_existential_addr immutable_access [[READ]] : $*SubscriptableGet to $*[[OPENED:@opened(.*) SubscriptableGet]]
2727
// CHECK: [[ALLOCSTACK:%[0-9]+]] = alloc_stack $[[OPENED]]
2828
// CHECK: copy_addr [[PROJ]] to [initialization] [[ALLOCSTACK]] : $*[[OPENED]]
29-
// CHECK-NEXT: end_access [[READ]] : $*SubscriptableGet
3029
// CHECK-NEXT: [[METH:%[0-9]+]] = witness_method $[[OPENED]], #SubscriptableGet.subscript!getter.1
3130
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[METH]]<[[OPENED]]>(%0, [[ALLOCSTACK]])
3231
// CHECK-NEXT: destroy_addr [[ALLOCSTACK]]
32+
// CHECK-NEXT: end_access [[READ]] : $*SubscriptableGet
3333
// CHECK-NEXT: dealloc_stack [[ALLOCSTACK]] : $*[[OPENED]]
3434
// CHECK-NEXT: return [[RESULT]]
3535

@@ -133,9 +133,9 @@ func use_property_rvalue_get() -> Int {
133133
// CHECK: [[PROJ:%[0-9]+]] = open_existential_addr immutable_access [[READ]] : $*PropertyWithGetter to $*[[OPENED:@opened(.*) PropertyWithGetter]]
134134
// CHECK: [[COPY:%.*]] = alloc_stack $[[OPENED]]
135135
// CHECK-NEXT: copy_addr [[PROJ]] to [initialization] [[COPY]] : $*[[OPENED]]
136-
// CHECK-NEXT: end_access [[READ]] : $*PropertyWithGetter
137136
// CHECK-NEXT: [[METH:%[0-9]+]] = witness_method $[[OPENED]], #PropertyWithGetter.a!getter.1
138137
// CHECK-NEXT: apply [[METH]]<[[OPENED]]>([[COPY]])
138+
// CHECK: end_access [[READ]] : $*PropertyWithGetter
139139

140140
func use_property_lvalue_get() -> Int {
141141
return propertyGetSet.b
@@ -458,3 +458,15 @@ public func test(_ p: Proto) {
458458
// CHECK-LABEL: sil_witness_table hidden StructWithStoredClassProperty: PropertyWithGetter module protocols {
459459
// CHECK-NEXT: method #PropertyWithGetter.a!getter.1: {{.*}} : @$S9protocols29StructWithStoredClassPropertyVAA0fC6GetterA2aDP1aSivgTW
460460
// CHECK-NEXT: }
461+
462+
//
463+
// rdar://problem/37031037
464+
//
465+
466+
protocol MethodWithDefaultArgGenerator {}
467+
extension MethodWithDefaultArgGenerator {
468+
mutating func foo(_ x: Int = 0) {}
469+
}
470+
func invokeMethodWithDefaultArg(x: inout MethodWithDefaultArgGenerator) {
471+
x.foo()
472+
}

0 commit comments

Comments
 (0)