Skip to content

Commit 84b055c

Browse files
committed
introduce 'AggressiveBorrowing' experimental feature
This is a SILGen-oriented feature and set of small fixes that helps avoid emitting copies when they're not needed. The primary change when turning on this feature is the avoidance of injecting LoadExpr's to deal with lvalue reads, in favor of implicit BorrowExpr's
1 parent 7f0adef commit 84b055c

File tree

11 files changed

+64
-2
lines changed

11 files changed

+64
-2
lines changed

include/swift/Basic/Features.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,9 @@ EXPERIMENTAL_FEATURE(MoveOnlyTuples, true)
344344
EXPERIMENTAL_FEATURE(MoveOnlyPartialReinitialization, true)
345345
EXPERIMENTAL_FEATURE(ConsumeSelfInDeinit, true)
346346

347+
/// Borrow values by default more aggressively in SILGen.
348+
EXPERIMENTAL_FEATURE(AggressiveBorrowing, false)
349+
347350
EXPERIMENTAL_FEATURE(AccessLevelOnImport, true)
348351

349352
/// Disable the special behavior of of explicit 'nonisolated' vs. being

lib/AST/ASTVerifier.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2499,6 +2499,19 @@ class Verifier : public ASTWalker {
24992499
verifyCheckedBase(E);
25002500
}
25012501

2502+
void verifyChecked(BorrowExpr *E) {
2503+
PrettyStackTraceExpr debugStack(Ctx, "verifying BorrowExpr", E);
2504+
2505+
auto toType = E->getType();
2506+
auto fromType = E->getSubExpr()->getType();
2507+
2508+
if (!fromType->hasLValueType())
2509+
error("borrow source must be an l-value", E);
2510+
2511+
if (toType->hasLValueType())
2512+
error("borrow result must be an r-value", E);
2513+
}
2514+
25022515
void verifyChecked(ABISafeConversionExpr *E) {
25032516
PrettyStackTraceExpr debugStack(Ctx, "verify ABISafeConversionExpr", E);
25042517

lib/AST/FeatureSet.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ UNINTERESTING_FEATURE(OldOwnershipOperatorSpellings)
9292
UNINTERESTING_FEATURE(MoveOnlyEnumDeinits)
9393
UNINTERESTING_FEATURE(MoveOnlyTuples)
9494
UNINTERESTING_FEATURE(MoveOnlyPartialReinitialization)
95+
UNINTERESTING_FEATURE(AggressiveBorrowing)
9596
UNINTERESTING_FEATURE(AccessLevelOnImport)
9697
UNINTERESTING_FEATURE(AllowNonResilientAccessInPackage)
9798
UNINTERESTING_FEATURE(ClientBypassResilientAccessInPackage)

lib/SILGen/SILGenDecl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,6 +1683,8 @@ void SILGenFunction::emitPatternBinding(PatternBindingDecl *PBD, unsigned idx,
16831683
}
16841684
}
16851685

1686+
// Form an evaluation scope for the initializing expression
1687+
FormalEvaluationScope writeback(*this);
16861688
emitExprInto(initExpr, initialization.get());
16871689
}
16881690

lib/SILGen/SILGenExpr.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ namespace {
467467

468468
RValue visitStringLiteralExpr(StringLiteralExpr *E, SGFContext C);
469469
RValue visitLoadExpr(LoadExpr *E, SGFContext C);
470+
RValue visitBorrowExpr(BorrowExpr *E, SGFContext C);
470471
RValue visitDerivedToBaseExpr(DerivedToBaseExpr *E, SGFContext C);
471472
RValue visitMetatypeConversionExpr(MetatypeConversionExpr *E,
472473
SGFContext C);
@@ -1110,6 +1111,21 @@ RValue RValueEmitter::visitLoadExpr(LoadExpr *E, SGFContext C) {
11101111
C.withFollowingSideEffects());
11111112
}
11121113

1114+
RValue RValueEmitter::visitBorrowExpr(BorrowExpr *E, SGFContext C_Ignored) {
1115+
assert(!SGF.getTypeLowering(E->getType()).getLoweredType().isAddress()
1116+
&& "maybe unhandled address-only type?");
1117+
1118+
// NOTE: You should NOT add an evaluation scope here!
1119+
// The callers of this visitor should have established a scope already that
1120+
// encompasses the use of the borrowed RValue that we return.
1121+
ASSERT(SGF.isInFormalEvaluationScope() && "emit borrow_expr without scope?");
1122+
1123+
LValue lv = SGF.emitLValue(E->getSubExpr(), SGFAccessKind::BorrowedObjectRead);
1124+
auto substFormalType = lv.getSubstFormalType();
1125+
ManagedValue mv = SGF.emitBorrowedLValue(E, std::move(lv));
1126+
return RValue(SGF, E, substFormalType, mv);
1127+
}
1128+
11131129
SILValue SILGenFunction::emitTemporaryAllocation(SILLocation loc, SILType ty,
11141130
HasDynamicLifetime_t dynamic,
11151131
IsLexical_t isLexical,

lib/SILGen/SILGenLValue.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3756,7 +3756,7 @@ RValue SILGenFunction::emitRValueForNonMemberVarDecl(SILLocation loc,
37563756
// This is a 'let', so we can make guarantees.
37573757
return RValue(*this, loc, formalRValueType,
37583758
C.isGuaranteedPlusZeroOk()
3759-
? Result : Result.copyUnmanaged(*this, loc));
3759+
? Result : Result.ensurePlusOne(*this, loc));
37603760
}
37613761

37623762
LValue lv = emitLValueForNonMemberVarDecl(

lib/SILGen/SILGenStmt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,7 @@ void SILGenFunction::emitReturnExpr(SILLocation branchLoc,
808808
loweredRetTy, loweredResultTy);
809809
RV = RValue(*this, ret, emitConvertedRValue(ret, conversion));
810810
} else {
811-
RV = emitRValue(ret);
811+
RV = emitRValue(ret, SGFContext::AllowImmediatePlusZero);
812812
}
813813

814814
std::move(RV)

lib/Sema/CSApply.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7264,6 +7264,13 @@ Expr *ExprRewriter::coerceExistential(Expr *expr, Type toType,
72647264
}
72657265

72667266
Expr *ConstraintSystem::addImplicitLoadExpr(Expr *expr) {
7267+
/// If aggressive borrowing is enabled, don't emit a LoadExpr.
7268+
if (DC->getASTContext().LangOpts.hasFeature(Feature::AggressiveBorrowing)) {
7269+
return TypeChecker::addImplicitBorrowExpr(
7270+
getASTContext(), expr, [this](Expr *expr) { return getType(expr); },
7271+
[this](Expr *expr, Type type) { setType(expr, type); });
7272+
}
7273+
72677274
return TypeChecker::addImplicitLoadExpr(
72687275
getASTContext(), expr, [this](Expr *expr) { return getType(expr); },
72697276
[this](Expr *expr, Type type) { setType(expr, type); });

lib/Sema/MiscDiagnostics.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,10 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
487487
}
488488

489489
void checkBorrowExpr(BorrowExpr *borrowExpr) {
490+
// FIXME: revisit whether the restrictions are needed for explicit borrows
491+
if (Ctx.LangOpts.hasFeature(AggressiveBorrowing))
492+
return;
493+
490494
// Allow for a chain of member_ref exprs that end in a decl_ref expr.
491495
auto *subExpr = borrowExpr->getSubExpr();
492496
while (auto *memberRef = dyn_cast<MemberRefExpr>(subExpr))

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,16 @@ bool TypeChecker::checkedCastMaySucceed(Type t1, Type t2, DeclContext *dc) {
11301130
return (kind != CheckedCastKind::Unresolved);
11311131
}
11321132

1133+
Expr *
1134+
TypeChecker::addImplicitBorrowExpr(ASTContext &Ctx, Expr *E,
1135+
std::function<Type(Expr *)> getType,
1136+
std::function<void(Expr *, Type)> setType) {
1137+
auto objectType = getType(E)->getRValueType();
1138+
auto *BE = BorrowExpr::createImplicit(Ctx, E->getLoc(), E, objectType);
1139+
setType(BE, objectType);
1140+
return BE;
1141+
}
1142+
11331143
Expr *
11341144
TypeChecker::addImplicitLoadExpr(ASTContext &Context, Expr *expr,
11351145
std::function<Type(Expr *)> getType,

0 commit comments

Comments
 (0)