Skip to content

Commit a87988b

Browse files
authored
Merge pull request swiftlang#23526 from gottesmm/pr-8a32670da832a8c0a68f4aaf94d9ff512d133fbd
2 parents 68d5e37 + 4ebd6d0 commit a87988b

File tree

6 files changed

+76
-171
lines changed

6 files changed

+76
-171
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 14 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,150 +2030,30 @@ RValue RValueEmitter::visitTupleExpr(TupleExpr *E, SGFContext C) {
20302030
return result;
20312031
}
20322032

2033-
namespace {
2034-
2035-
/// A helper function with context that tries to emit member refs of nominal
2036-
/// types avoiding the conservative lvalue logic.
2037-
class NominalTypeMemberRefRValueEmitter {
2038-
using SelfTy = NominalTypeMemberRefRValueEmitter;
2039-
2040-
/// The member ref expression we are emitting.
2041-
MemberRefExpr *Expr;
2042-
2043-
/// The passed in SGFContext.
2044-
SGFContext Context;
2045-
2046-
/// The typedecl of the base expression of the member ref expression.
2047-
NominalTypeDecl *Base;
2048-
2049-
/// The field of the member.
2050-
VarDecl *Field;
2051-
2052-
public:
2053-
2054-
NominalTypeMemberRefRValueEmitter(MemberRefExpr *Expr, SGFContext Context,
2055-
NominalTypeDecl *Base)
2056-
: Expr(Expr), Context(Context), Base(Base),
2057-
Field(cast<VarDecl>(Expr->getMember().getDecl())) {}
2058-
2059-
/// Emit the RValue.
2060-
Optional<RValue> emit(SILGenFunction &SGF) {
2061-
// If we don't have a class or a struct, bail.
2062-
if (!isa<ClassDecl>(Base) && !isa<StructDecl>(Base))
2063-
return None;
2064-
2065-
// Check that we have a stored access strategy. If we don't bail.
2066-
AccessStrategy strategy =
2067-
Field->getAccessStrategy(Expr->getAccessSemantics(), AccessKind::Read,
2068-
SGF.SGM.M.getSwiftModule(),
2069-
SGF.F.getResilienceExpansion());
2070-
if (strategy.getKind() != AccessStrategy::Storage)
2071-
return None;
2072-
2073-
FormalEvaluationScope scope(SGF);
2074-
if (isa<StructDecl>(Base))
2075-
return emitStructDecl(SGF);
2076-
assert(isa<ClassDecl>(Base) && "Expected class");
2077-
return emitClassDecl(SGF);
2078-
}
2079-
2080-
NominalTypeMemberRefRValueEmitter(const SelfTy &) = delete;
2081-
NominalTypeMemberRefRValueEmitter(SelfTy &&) = delete;
2082-
~NominalTypeMemberRefRValueEmitter() = default;
2083-
2084-
private:
2085-
RValue emitStructDecl(SILGenFunction &SGF) {
2086-
ManagedValue base =
2087-
SGF.emitRValueAsSingleValue(Expr->getBase(),
2088-
SGFContext::AllowImmediatePlusZero);
2089-
CanType baseFormalType =
2090-
Expr->getBase()->getType()->getCanonicalType();
2091-
assert(baseFormalType->isMaterializable());
2092-
2093-
RValue result =
2094-
SGF.emitRValueForStorageLoad(Expr, base, baseFormalType,
2095-
Expr->isSuper(),
2096-
Field, {},
2097-
Expr->getMember().getSubstitutions(),
2098-
Expr->getAccessSemantics(),
2099-
Expr->getType(), Context);
2100-
return result;
2101-
}
2102-
2103-
Optional<RValue> emitClassDecl(SILGenFunction &SGF) {
2104-
// If guaranteed plus zero is not ok, we bail.
2105-
if (!Context.isGuaranteedPlusZeroOk())
2106-
return None;
2107-
2108-
// If the field is not a let, bail. We need to use the lvalue logic.
2109-
if (!Field->isLet())
2110-
return None;
2111-
2112-
// If we are emitting a delegating init super and we have begun the
2113-
// super.init call, since self has been exclusively borrowed, we need to be
2114-
// conservative and use the lvalue machinery. This ensures that we properly
2115-
// create FormalEvaluationScopes around the access to self.
2116-
//
2117-
// TODO: This currently turns off this optimization for /all/ classes that
2118-
// are accessed as a direct argument to a super.init call. In the future, we
2119-
// should be able to be less conservative here by pattern matching if
2120-
// something /can not/ be self.
2121-
if (SGF.SelfInitDelegationState == SILGenFunction::DidExclusiveBorrowSelf)
2122-
return None;
2123-
2124-
// Ok, now we know that we are able to emit our base at guaranteed plus zero
2125-
// emit base.
2126-
ManagedValue base =
2127-
SGF.emitRValueAsSingleValue(Expr->getBase(), Context);
2128-
2129-
CanType baseFormalType =
2130-
Expr->getBase()->getType()->getCanonicalType();
2131-
assert(baseFormalType->isMaterializable());
2132-
2133-
// And then emit our property using whether or not base is at +0 to
2134-
// discriminate whether or not the base was guaranteed.
2135-
RValue result =
2136-
SGF.emitRValueForStorageLoad(Expr, base, baseFormalType,
2137-
Expr->isSuper(),
2138-
Field, {},
2139-
Expr->getMember().getSubstitutions(),
2140-
Expr->getAccessSemantics(),
2141-
Expr->getType(), Context,
2142-
base.isPlusZeroRValueOrTrivial());
2143-
return std::move(result);
2144-
}
2145-
};
2146-
2147-
} // end anonymous namespace
2148-
2149-
RValue RValueEmitter::visitMemberRefExpr(MemberRefExpr *E, SGFContext C) {
2150-
assert(!E->getType()->is<LValueType>() &&
2033+
RValue RValueEmitter::visitMemberRefExpr(MemberRefExpr *e,
2034+
SGFContext resultCtx) {
2035+
assert(!e->getType()->is<LValueType>() &&
21512036
"RValueEmitter shouldn't be called on lvalues");
21522037

2153-
if (isa<TypeDecl>(E->getMember().getDecl())) {
2038+
if (isa<TypeDecl>(e->getMember().getDecl())) {
21542039
// Emit the metatype for the associated type.
2155-
visit(E->getBase());
2156-
SILValue MT =
2157-
SGF.B.createMetatype(E, SGF.getLoweredLoadableType(E->getType()));
2158-
return RValue(SGF, E, ManagedValue::forUnmanaged(MT));
2040+
visit(e->getBase());
2041+
SILValue mt =
2042+
SGF.B.createMetatype(e, SGF.getLoweredLoadableType(e->getType()));
2043+
return RValue(SGF, e, ManagedValue::forUnmanaged(mt));
21592044
}
21602045

2161-
// If we have a nominal type decl as our base, try to emit the base rvalue's
2162-
// member using special logic that will let us avoid extra retains
2163-
// and releases.
2164-
if (auto *N = E->getBase()->getType()->getNominalOrBoundGenericNominal())
2165-
if (auto RV = NominalTypeMemberRefRValueEmitter(E, C, N).emit(SGF))
2166-
return RValue(std::move(RV.getValue()));
2167-
21682046
// Everything else should use the l-value logic.
21692047

21702048
// Any writebacks for this access are tightly scoped.
21712049
FormalEvaluationScope scope(SGF);
21722050

2173-
LValue lv = SGF.emitLValue(E, SGFAccessKind::OwnedObjectRead);
2174-
// We can't load at +0 without further analysis, since the formal access into
2175-
// the lvalue will end immediately.
2176-
return SGF.emitLoadOfLValue(E, std::move(lv), C.withFollowingSideEffects());
2051+
LValue lv = SGF.emitLValue(e, SGFAccessKind::OwnedObjectRead);
2052+
2053+
// Otherwise, we can't load at +0 without further analysis, since the formal
2054+
// access into the lvalue will end immediately.
2055+
return SGF.emitLoadOfLValue(e, std::move(lv),
2056+
resultCtx.withFollowingSideEffects());
21772057
}
21782058

21792059
RValue RValueEmitter::visitDynamicMemberRefExpr(DynamicMemberRefExpr *E,

lib/SILGen/SILGenLValue.cpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -721,13 +721,16 @@ namespace {
721721

722722
ManagedValue project(SILGenFunction &SGF, SILLocation loc,
723723
ManagedValue base) && override {
724-
assert(base.getType().isObject() &&
725-
"base for ref element component must be an object");
726724
assert(base.getType().hasReferenceSemantics() &&
727725
"base for ref element component must be a reference type");
726+
728727
// Borrow the ref element addr using formal access. If we need the ref
729728
// element addr, we will load it in this expression.
730-
base = base.formalAccessBorrow(SGF, loc);
729+
if (base.getType().isAddress()) {
730+
base = SGF.B.createFormalAccessLoadBorrow(loc, base);
731+
} else {
732+
base = base.formalAccessBorrow(SGF, loc);
733+
}
731734
SILValue result =
732735
SGF.B.createRefElementAddr(loc, base.getUnmanagedValue(),
733736
Field, SubstFieldType);
@@ -1903,11 +1906,19 @@ namespace {
19031906
RValue
19041907
TranslationPathComponent::get(SILGenFunction &SGF, SILLocation loc,
19051908
ManagedValue base, SGFContext c) && {
1906-
// Load the original value.
1907-
RValue baseVal(SGF, loc, getSubstFormalType(),
1908-
SGF.emitLoad(loc, base.getValue(),
1909-
SGF.getTypeLowering(base.getType()),
1910-
SGFContext(), IsNotTake));
1909+
// Inline constructor.
1910+
RValue baseVal = [&]() -> RValue {
1911+
// If our base is an object, just put it into an RValue and return.
1912+
if (base.getType().isObject()) {
1913+
return RValue(SGF, loc, getSubstFormalType(), base);
1914+
}
1915+
1916+
// Otherwise, load the value and put it into an RValue.
1917+
return RValue(SGF, loc, getSubstFormalType(),
1918+
SGF.emitLoad(loc, base.getValue(),
1919+
SGF.getTypeLowering(base.getType()),
1920+
SGFContext(), IsNotTake));
1921+
}();
19111922

19121923
// Map the base value to its substituted representation.
19131924
return std::move(*this).translate(SGF, loc, std::move(baseVal), c);
@@ -1916,6 +1927,8 @@ TranslationPathComponent::get(SILGenFunction &SGF, SILLocation loc,
19161927
void TranslationPathComponent::set(SILGenFunction &SGF, SILLocation loc,
19171928
ArgumentSource &&valueSource,
19181929
ManagedValue base) && {
1930+
assert(base.getType().isAddress() &&
1931+
"Only support setting bases that have addresses");
19191932
RValue value = std::move(valueSource).getAsRValue(SGF);
19201933

19211934
// Map the value to the original pattern.
@@ -2229,6 +2242,7 @@ static ManagedValue visitRecNonInOutBase(SILGenLValue &SGL, Expr *e,
22292242
}
22302243

22312244
// Ok, at this point we know that re-abstraction is not required.
2245+
22322246
SGFContext ctx;
22332247

22342248
if (auto *dre = dyn_cast<DeclRefExpr>(e)) {
@@ -4136,8 +4150,6 @@ void SILGenFunction::emitAssignToLValue(SILLocation loc, RValue &&src,
41364150
void SILGenFunction::emitAssignToLValue(SILLocation loc,
41374151
ArgumentSource &&src,
41384152
LValue &&dest) {
4139-
assert(dest.getAccessKind() == SGFAccessKind::Write);
4140-
41414153
// Enter a FormalEvaluationScope so that formal access to independent LValue
41424154
// components do not overlap. Furthermore, use an ArgumentScope to force
41434155
// cleanup of materialized LValues immediately, before evaluating the next

test/SILGen/guaranteed_self.swift

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -451,36 +451,45 @@ class LetFieldClass {
451451
// CHECK-LABEL: sil hidden [ossa] @$s15guaranteed_self13LetFieldClassC10letkMethod{{[_0-9a-zA-Z]*}}F : $@convention(method) (@guaranteed LetFieldClass) -> () {
452452
// CHECK: bb0([[CLS:%.*]] : @guaranteed $LetFieldClass):
453453
// CHECK: [[KRAKEN_ADDR:%.*]] = ref_element_addr [[CLS]] : $LetFieldClass, #LetFieldClass.letk
454-
// CHECK-NEXT: [[KRAKEN:%.*]] = load_borrow [[KRAKEN_ADDR]]
454+
// CHECK-NEXT: [[KRAKEN:%.*]] = load [copy] [[KRAKEN_ADDR]]
455455
// CHECK-NEXT: [[KRAKEN_METH:%.*]] = class_method [[KRAKEN]]
456456
// CHECK-NEXT: apply [[KRAKEN_METH]]([[KRAKEN]])
457457
// CHECK: [[KRAKEN_ADDR:%.*]] = ref_element_addr [[CLS]] : $LetFieldClass, #LetFieldClass.letk
458458
// CHECK-NEXT: [[KRAKEN:%.*]] = load [copy] [[KRAKEN_ADDR]]
459-
// CHECK: [[BORROWED_KRAKEN:%.*]] = begin_borrow [[KRAKEN]]
459+
// CHECK: [[REBORROWED_KRAKEN:%.*]] = begin_borrow [[KRAKEN]]
460460
// CHECK: [[DESTROY_SHIP_FUN:%.*]] = function_ref @$s15guaranteed_self11destroyShipyyAA6KrakenCF : $@convention(thin) (@guaranteed Kraken) -> ()
461-
// CHECK-NEXT: apply [[DESTROY_SHIP_FUN]]([[BORROWED_KRAKEN]])
462-
// CHECK-NEXT: end_borrow [[BORROWED_KRAKEN]]
461+
// CHECK-NEXT: apply [[DESTROY_SHIP_FUN]]([[REBORROWED_KRAKEN]])
462+
// CHECK-NEXT: end_borrow [[REBORROWED_KRAKEN]]
463+
// CHECK-NEXT: destroy_value [[KRAKEN]]
463464
// CHECK-NEXT: [[KRAKEN_BOX:%.*]] = alloc_box ${ var Kraken }
464465
// CHECK-NEXT: [[PB:%.*]] = project_box [[KRAKEN_BOX]]
465466
// CHECK-NEXT: [[KRAKEN_ADDR:%.*]] = ref_element_addr [[CLS]] : $LetFieldClass, #LetFieldClass.letk
466-
// CHECK-NEXT: [[KRAKEN2:%.*]] = load [copy] [[KRAKEN_ADDR]]
467-
// CHECK-NEXT: store [[KRAKEN2]] to [init] [[PB]]
467+
// CHECK-NEXT: [[KRAKEN:%.*]] = load [copy] [[KRAKEN_ADDR]]
468+
// CHECK-NEXT: store [[KRAKEN]] to [init] [[PB]]
468469
// CHECK-NEXT: [[READ:%.*]] = begin_access [read] [unknown] [[PB]] : $*Kraken
469470
// CHECK-NEXT: [[KRAKEN_COPY:%.*]] = load [copy] [[READ]]
470471
// CHECK-NEXT: end_access [[READ]] : $*Kraken
471472
// CHECK: [[DESTROY_SHIP_FUN:%.*]] = function_ref @$s15guaranteed_self11destroyShipyyAA6KrakenCF : $@convention(thin) (@guaranteed Kraken) -> ()
472473
// CHECK-NEXT: apply [[DESTROY_SHIP_FUN]]([[KRAKEN_COPY]])
473474
// CHECK-NEXT: destroy_value [[KRAKEN_COPY]]
474475
// CHECK-NEXT: destroy_value [[KRAKEN_BOX]]
475-
// CHECK-NEXT: destroy_value [[KRAKEN]]
476476
// CHECK-NEXT: tuple
477477
// CHECK-NEXT: return
478+
// CHECK: } // end sil function
478479
func letkMethod() {
479-
letk.enrage()
480-
let ll = letk
481-
destroyShip(ll)
482-
var lv = letk
483-
destroyShip(lv)
480+
do {
481+
letk.enrage()
482+
}
483+
484+
do {
485+
let ll = letk
486+
destroyShip(ll)
487+
}
488+
489+
do {
490+
var lv = letk
491+
destroyShip(lv)
492+
}
484493
}
485494

486495
// CHECK-LABEL: sil hidden [ossa] @$s15guaranteed_self13LetFieldClassC10varkMethod{{[_0-9a-zA-Z]*}}F : $@convention(method) (@guaranteed LetFieldClass) -> () {
@@ -534,6 +543,8 @@ class ClassIntTreeNode {
534543
// CHECK-NOT: destroy_value
535544
// CHECK: copy_value
536545
// CHECK-NOT: copy_value
546+
// CHECK: destroy_value
547+
// CHECK: destroy_value
537548
// CHECK-NOT: destroy_value
538549
// CHECK: return
539550
func find(_ v : Int) -> ClassIntTreeNode {

test/SILGen/let_decls.swift

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -407,22 +407,26 @@ struct StructMemberTest {
407407
}
408408
// CHECK-LABEL: sil hidden [ossa] @$s9let_decls16StructMemberTestV016testRecursiveIntD4LoadSiyF : $@convention(method) (@guaranteed StructMemberTest)
409409
// CHECK: bb0([[ARG:%.*]] : @guaranteed $StructMemberTest):
410-
// CHECK: debug_value %0 : $StructMemberTest, let, name "self"
411-
// CHECK: %2 = struct_extract %0 : $StructMemberTest, #StructMemberTest.s
412-
// CHECK: %3 = struct_extract %2 : $AnotherStruct, #AnotherStruct.i
413-
// CHECK-NOT: destroy_value %0 : $StructMemberTest
414-
// CHECK: return %3 : $Int
410+
// CHECK: [[EXT_1:%.*]] = struct_extract [[ARG]] : $StructMemberTest, #StructMemberTest.s
411+
// CHECK: [[EXT_1_COPY:%.*]] = copy_value [[EXT_1]]
412+
// CHECK: [[EXT_1_COPY_BORROW:%.*]] = begin_borrow [[EXT_1_COPY]]
413+
// CHECK: [[EXT_2:%.*]] = struct_extract [[EXT_1_COPY_BORROW]] : $AnotherStruct, #AnotherStruct.i
414+
// CHECK: destroy_value [[EXT_1_COPY]]
415+
// CHECK: return [[EXT_2]] : $Int
416+
// CHECK: } // end sil function '$s9let_decls16StructMemberTestV016testRecursiveIntD4LoadSiyF'
415417

416418
func testTupleMemberLoad() -> Int {
417419
return t.1.i
418420
}
419421
// CHECK-LABEL: sil hidden [ossa] @$s9let_decls16StructMemberTestV09testTupleD4LoadSiyF : $@convention(method) (@guaranteed StructMemberTest)
420-
// CHECK: bb0(%0 : @guaranteed $StructMemberTest):
421-
// CHECK-NEXT: debug_value %0 : $StructMemberTest, let, name "self"
422-
// CHECK-NEXT: [[T0:%.*]] = struct_extract %0 : $StructMemberTest, #StructMemberTest.t
423-
// CHECK-NEXT: ({{%.*}}, [[T2:%.*]]) = destructure_tuple [[T0]]
424-
// CHECK-NEXT: [[T3:%.*]] = struct_extract [[T2]] : $AnotherStruct, #AnotherStruct.i
425-
// CHECK-NEXT: return [[T3]] : $Int
422+
// CHECK: bb0([[ARG]] : @guaranteed $StructMemberTest):
423+
// CHECK: [[T0:%.*]] = struct_extract [[ARG]] : $StructMemberTest, #StructMemberTest.t
424+
// CHECK: [[T0_COPY:%.*]] = copy_value [[T0]]
425+
// CHECK: ({{%.*}}, [[T2:%.*]]) = destructure_tuple [[T0_COPY]]
426+
// CHECK: [[T2_BORROW:%.*]] = begin_borrow [[T2]]
427+
// CHECK: [[T3:%.*]] = struct_extract [[T2_BORROW]] : $AnotherStruct, #AnotherStruct.i
428+
// CHECK: return [[T3]] : $Int
429+
// CHECK: } // end sil function '$s9let_decls16StructMemberTestV09testTupleD4LoadSiyF'
426430

427431
}
428432

test/SILGen/property_abstraction.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ struct Foo<T, U> {
1414
// CHECK-LABEL: sil hidden [ossa] @$s20property_abstraction4getF{{[_0-9a-zA-Z]*}}Foo{{.*}}F : $@convention(thin) (@guaranteed Foo<Int, Int>) -> @owned @callee_guaranteed (Int) -> Int {
1515
// CHECK: bb0([[X_ORIG:%.*]] : @guaranteed $Foo<Int, Int>):
1616
// CHECK: [[F_ORIG:%.*]] = struct_extract [[X_ORIG]] : $Foo<Int, Int>, #Foo.f
17-
// CHECK: [[F_ORIG_COPY:%.*]] = copy_value [[F_ORIG]]
1817
// CHECK: [[REABSTRACT_FN:%.*]] = function_ref @$s{{.*}}TR :
18+
// CHECK: [[F_ORIG_COPY:%.*]] = copy_value [[F_ORIG]]
1919
// CHECK: [[F_SUBST:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACT_FN]]([[F_ORIG_COPY]])
2020
// CHECK: return [[F_SUBST]]
2121
// CHECK: } // end sil function '$s20property_abstraction4getF{{[_0-9a-zA-Z]*}}F'

test/SILOptimizer/access_marker_verify.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -904,11 +904,9 @@ internal struct CanCastStruct<Base : Hashable> : CanCast {
904904
// CHECK: checked_cast_addr_br take_always CanCast in [[TEMP_BASE]] : $*CanCast to CanCastStruct<T> in [[TEMP_SUB_ADR]] : $*CanCastStruct<T>
905905
// CHECK-NOT: begin_access
906906
// CHECK: [[TEMP_DATA:%.*]] = unchecked_take_enum_data_addr [[TEMP_SUB]] : $*Optional<CanCastStruct<T>>, #Optional.some!enumelt.1
907-
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unsafe] [[TEMP_DATA]] : $*CanCastStruct<T>
908-
// CHECK: [[BASE_ADR:%.*]] = struct_element_addr [[ACCESS]] : $*CanCastStruct<T>, #CanCastStruct.base
909907
// CHECK-NOT: begin_access
908+
// CHECK: [[BASE_ADR:%.*]] = struct_element_addr [[TEMP_DATA]] : $*CanCastStruct<T>, #CanCastStruct.base
910909
// CHECK: copy_addr [[BASE_ADR]] to [initialization] [[OUT_ENUM]] : $*T
911-
// CHECK: end_access [[ACCESS]] : $*CanCastStruct<T>
912910
// CHECK-NOT: begin_access
913911
// CHECK: inject_enum_addr %0 : $*Optional<T>, #Optional.some!enumelt.1
914912
// CHECK-LABEL: } // end sil function '$s20access_marker_verify13CanCastStructV5unboxqd__SgySHRd__lF'

0 commit comments

Comments
 (0)