Skip to content

Commit cb0be34

Browse files
authored
Merge pull request swiftlang#15313 from slavapestov/fix-noescape
Clean up SILGen's noescape closure implementation
2 parents cbf157f + 597bea3 commit cb0be34

17 files changed

+228
-153
lines changed

include/swift/SIL/SILBuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1943,6 +1943,8 @@ class SILBuilder {
19431943
/// lowering for the non-address value.
19441944
void emitDestroyValueOperation(SILLocation Loc, SILValue v) {
19451945
assert(!v->getType().isAddress());
1946+
if (v.getOwnershipKind() == ValueOwnershipKind::Trivial)
1947+
return;
19461948
auto &lowering = getTypeLowering(v->getType());
19471949
lowering.emitDestroyValue(*this, Loc, v);
19481950
}

lib/SILGen/SILGenConvert.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,23 @@ SILGenFunction::emitOptionalToOptional(SILLocation loc,
365365
SILType resultTy,
366366
ValueTransformRef transformValue,
367367
SGFContext C) {
368+
auto &Ctx = getASTContext();
369+
370+
// If the input is known to be 'none' just emit a 'none' value of the right
371+
// result type right away.
372+
auto &resultTL = getTypeLowering(resultTy);
373+
374+
if (auto *EI = dyn_cast<EnumInst>(input.getValue())) {
375+
if (EI->getElement() == Ctx.getOptionalNoneDecl()) {
376+
if (!(resultTL.isAddressOnly() && silConv.useLoweredAddresses())) {
377+
SILValue none = B.createEnum(loc, SILValue(), EI->getElement(),
378+
resultTy);
379+
return emitManagedRValueWithCleanup(none);
380+
}
381+
}
382+
}
383+
384+
// Otherwise perform a dispatch.
368385
auto contBB = createBasicBlock();
369386
auto isNotPresentBB = createBasicBlock();
370387
auto isPresentBB = createBasicBlock();
@@ -377,8 +394,7 @@ SILGenFunction::emitOptionalToOptional(SILLocation loc,
377394
assert(noOptResultTy);
378395

379396
// Create a temporary for the output optional.
380-
auto &resultTL = getTypeLowering(resultTy);
381-
397+
//
382398
// If the result is address-only, we need to return something in memory,
383399
// otherwise the result is the BBArgument in the merge point.
384400
// TODO: use the SGFContext passed in.
@@ -399,7 +415,7 @@ SILGenFunction::emitOptionalToOptional(SILLocation loc,
399415
// possible.
400416
if (getTypeLowering(input.getType()).isAddressOnly() &&
401417
silConv.useLoweredAddresses()) {
402-
auto *someDecl = B.getASTContext().getOptionalSomeDecl();
418+
auto *someDecl = Ctx.getOptionalSomeDecl();
403419
input = B.createUncheckedTakeEnumDataAddr(
404420
loc, input, someDecl, input.getType().getOptionalObjectType());
405421
}

lib/SILGen/SILGenFunction.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1637,7 +1637,9 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
16371637
CanType &inputSubstType,
16381638
CanType &outputSubstType,
16391639
GenericEnvironment *&genericEnv,
1640-
SubstitutionMap &interfaceSubs);
1640+
SubstitutionMap &interfaceSubs,
1641+
bool withoutActuallyEscaping=false);
1642+
16411643
//===--------------------------------------------------------------------===//
16421644
// NoEscaping to Escaping closure thunk
16431645
//===--------------------------------------------------------------------===//

lib/SILGen/SILGenPoly.cpp

Lines changed: 18 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -2720,7 +2720,8 @@ CanSILFunctionType SILGenFunction::buildThunkType(
27202720
CanType &inputSubstType,
27212721
CanType &outputSubstType,
27222722
GenericEnvironment *&genericEnv,
2723-
SubstitutionMap &interfaceSubs) {
2723+
SubstitutionMap &interfaceSubs,
2724+
bool withoutActuallyEscaping) {
27242725
assert(!expectedType->isPolymorphic());
27252726
assert(!sourceType->isPolymorphic());
27262727

@@ -2733,6 +2734,9 @@ CanSILFunctionType SILGenFunction::buildThunkType(
27332734
auto extInfo = expectedType->getExtInfo()
27342735
.withRepresentation(SILFunctionType::Representation::Thin);
27352736

2737+
if (withoutActuallyEscaping)
2738+
extInfo = extInfo.withNoEscape(false);
2739+
27362740
// Does the thunk type involve archetypes other than opened existentials?
27372741
bool hasArchetypes = false;
27382742
// Does the thunk type involve an open existential type?
@@ -2937,103 +2941,17 @@ static ManagedValue createThunk(SILGenFunction &SGF,
29372941

29382942
static CanSILFunctionType buildWithoutActuallyEscapingThunkType(
29392943
SILGenFunction &SGF, CanSILFunctionType &noEscapingType,
2940-
CanSILFunctionType &escapingType, GenericEnvironment *&genericEnv,
2941-
SubstitutionMap &contextSubs) {
2944+
CanSILFunctionType &escapingType, GenericEnvironment *&genericEnv) {
29422945

29432946
assert(escapingType->getExtInfo() ==
29442947
noEscapingType->getExtInfo().withNoEscape(false));
29452948

2946-
// Strip the closure properties.
2947-
auto extInfo = noEscapingType->getExtInfo()
2948-
.withRepresentation(SILFunctionType::Representation::Thin)
2949-
.withNoEscape(false);
2950-
2951-
// Inherit the context's generic signature if the closure uses generic
2952-
// parameters.
2953-
assert(noEscapingType->hasArchetype() == escapingType->hasArchetype());
2954-
CanGenericSignature genericSig;
2955-
if (noEscapingType->hasArchetype()) {
2956-
genericSig = SGF.F.getLoweredFunctionType()->getGenericSignature();
2957-
genericEnv = SGF.F.getGenericEnvironment();
2958-
auto subsArray = SGF.F.getForwardingSubstitutions();
2959-
contextSubs = genericSig->getSubstitutionMap(subsArray);
2960-
}
2961-
2962-
auto substIntoThunkContext = [&](CanType t) -> CanType {
2963-
return t.subst(
2964-
[&](SubstitutableType *type) -> Type {
2965-
return Type(type).subst(contextSubs);
2966-
},
2967-
LookUpConformanceInSubstitutionMap(contextSubs),
2968-
SubstFlags::AllowLoweredTypes)
2969-
->getCanonicalType();
2970-
};
2971-
2972-
escapingType = cast<SILFunctionType>(substIntoThunkContext(escapingType));
2973-
noEscapingType = cast<SILFunctionType>(substIntoThunkContext(noEscapingType));
2974-
2975-
// If our parent function was pseudogeneric, this thunk must also be
2976-
// pseudogeneric, since we have no way to pass generic parameters.
2977-
if (genericSig)
2978-
if (SGF.F.getLoweredFunctionType()->isPseudogeneric())
2979-
extInfo = extInfo.withIsPseudogeneric();
2980-
2981-
// Add the function type as the parameter.
2982-
auto contextConvention =
2983-
SILType::getPrimitiveObjectType(noEscapingType).isTrivial(SGF.getModule())
2984-
? ParameterConvention::Direct_Unowned
2985-
: ParameterConvention::Direct_Guaranteed;
2986-
SmallVector<SILParameterInfo, 4> params;
2987-
params.append(noEscapingType->getParameters().begin(),
2988-
noEscapingType->getParameters().end());
2989-
params.push_back({noEscapingType,
2990-
noEscapingType->getExtInfo().hasContext()
2991-
? contextConvention
2992-
: ParameterConvention::Direct_Unowned});
2993-
2994-
// Map the parameter and expected types out of context to get the interface
2995-
// type of the thunk.
2996-
SmallVector<SILParameterInfo, 4> interfaceParams;
2997-
interfaceParams.reserve(params.size());
2998-
for (auto &param : params) {
2999-
auto paramIfaceTy = param.getType()->mapTypeOutOfContext();
3000-
interfaceParams.push_back(
3001-
SILParameterInfo(paramIfaceTy->getCanonicalType(genericSig),
3002-
param.getConvention()));
3003-
}
3004-
3005-
SmallVector<SILYieldInfo, 4> interfaceYields;
3006-
for (auto &yield : noEscapingType->getYields()) {
3007-
auto yieldIfaceTy = yield.getType()->mapTypeOutOfContext();
3008-
auto interfaceYield =
3009-
yield.getWithType(yieldIfaceTy->getCanonicalType(genericSig));
3010-
interfaceYields.push_back(interfaceYield);
3011-
}
3012-
3013-
SmallVector<SILResultInfo, 4> interfaceResults;
3014-
for (auto &result : noEscapingType->getResults()) {
3015-
auto resultIfaceTy = result.getType()->mapTypeOutOfContext();
3016-
auto interfaceResult =
3017-
result.getWithType(resultIfaceTy->getCanonicalType(genericSig));
3018-
interfaceResults.push_back(interfaceResult);
3019-
}
3020-
3021-
Optional<SILResultInfo> interfaceErrorResult;
3022-
if (noEscapingType->hasErrorResult()) {
3023-
auto errorResult = noEscapingType->getErrorResult();
3024-
auto errorIfaceTy = errorResult.getType()->mapTypeOutOfContext();
3025-
interfaceErrorResult = SILResultInfo(
3026-
errorIfaceTy->getCanonicalType(genericSig),
3027-
noEscapingType->getErrorResult().getConvention());
3028-
}
3029-
3030-
// The type of the thunk function.
3031-
return SILFunctionType::get(genericSig, extInfo,
3032-
noEscapingType->getCoroutineKind(),
3033-
ParameterConvention::Direct_Unowned,
3034-
interfaceParams, interfaceYields,
3035-
interfaceResults, interfaceErrorResult,
3036-
SGF.getASTContext());
2949+
CanType inputSubstType, outputSubstType;
2950+
SubstitutionMap interfaceSubs;
2951+
return SGF.buildThunkType(noEscapingType, escapingType,
2952+
inputSubstType, outputSubstType,
2953+
genericEnv, interfaceSubs,
2954+
/*withoutActuallyEscaping=*/true);
30372955
}
30382956

30392957
static void buildWithoutActuallyEscapingThunkBody(SILGenFunction &SGF) {
@@ -3085,12 +3003,11 @@ SILGenFunction::createWithoutActuallyEscapingClosure(
30853003
.withNoEscape(false));
30863004

30873005
GenericEnvironment *genericEnv = nullptr;
3088-
SubstitutionMap contextSubs;
30893006
auto noEscapingFnTy =
30903007
noEscapingFunctionValue.getType().castTo<SILFunctionType>();
30913008

30923009
auto thunkType = buildWithoutActuallyEscapingThunkType(
3093-
*this, noEscapingFnTy, escapingFnTy, genericEnv, contextSubs);
3010+
*this, noEscapingFnTy, escapingFnTy, genericEnv);
30943011

30953012
auto *thunk = SGM.getOrCreateReabstractionThunk(
30963013
thunkType, noEscapingFnTy, escapingFnTy, F.isSerialized());
@@ -3101,19 +3018,17 @@ SILGenFunction::createWithoutActuallyEscapingClosure(
31013018
buildWithoutActuallyEscapingThunkBody(thunkSGF);
31023019
}
31033020

3104-
CanSILFunctionType substFnType = thunkType;
3105-
SmallVector<Substitution, 4> subs;
3106-
if (auto genericSig = thunkType->getGenericSignature()) {
3107-
genericSig->getSubstitutions(contextSubs, subs);
3108-
substFnType = thunkType->substGenericArgs(F.getModule(), contextSubs);
3109-
}
3021+
CanSILFunctionType substFnType = thunkType->substGenericArgs(
3022+
F.getModule(), thunk->getForwardingSubstitutions());
31103023

31113024
// Create it in our current function.
31123025
auto thunkValue = B.createFunctionRef(loc, thunk);
31133026
SILValue noEscapeValue =
31143027
noEscapingFunctionValue.ensurePlusOne(*this, loc).forward(*this);
31153028
SingleValueInstruction *thunkedFn = B.createPartialApply(
3116-
loc, thunkValue, SILType::getPrimitiveObjectType(substFnType), subs,
3029+
loc, thunkValue,
3030+
SILType::getPrimitiveObjectType(substFnType),
3031+
thunk->getForwardingSubstitutions(),
31173032
noEscapeValue,
31183033
SILType::getPrimitiveObjectType(escapingFnTy));
31193034
// We need to ensure the 'lifetime' of the trivial values context captures. As

lib/Sema/CSApply.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1965,6 +1965,41 @@ namespace {
19651965
type = defaultType;
19661966
}
19671967

1968+
// By far the most common 'nil' literal is for Optional<T>.none.
1969+
//
1970+
// Emit this case directly instead of calling Optional.init(nilLiteral:),
1971+
// since this generates more efficient SIL.
1972+
if (auto objectType = type->getOptionalObjectType()) {
1973+
auto *nilDecl = tc.Context.getOptionalNoneDecl();
1974+
tc.validateDecl(nilDecl);
1975+
if (!nilDecl->hasInterfaceType())
1976+
return nullptr;
1977+
1978+
SubstitutionList subs = {Substitution(objectType, {})};
1979+
ConcreteDeclRef concreteDeclRef(tc.Context, nilDecl, subs);
1980+
1981+
auto nilType = FunctionType::get(
1982+
{MetatypeType::get(type)}, type);
1983+
auto *nilRefExpr = new (tc.Context) DeclRefExpr(
1984+
concreteDeclRef, DeclNameLoc(expr->getLoc()),
1985+
/*implicit=*/true, AccessSemantics::Ordinary,
1986+
nilType);
1987+
cs.cacheType(nilRefExpr);
1988+
1989+
auto *typeExpr = TypeExpr::createImplicitHack(
1990+
expr->getLoc(),
1991+
type,
1992+
tc.Context);
1993+
cs.cacheType(typeExpr);
1994+
1995+
auto *callExpr = new (tc.Context) DotSyntaxCallExpr(
1996+
nilRefExpr, expr->getLoc(), typeExpr, type);
1997+
callExpr->setImplicit(true);
1998+
cs.cacheType(callExpr);
1999+
2000+
return callExpr;
2001+
}
2002+
19682003
DeclName initName(tc.Context, DeclBaseName::createConstructor(),
19692004
{ tc.Context.Id_nilLiteral });
19702005
return convertLiteral(expr, type, cs.getType(expr), protocol,

lib/Sema/MiscDiagnostics.cpp

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,27 +1423,42 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
14231423

14241424
}
14251425

1426-
/// Return true if this is 'nil' type checked as an Optional. This looks
1427-
/// like this:
1428-
/// (call_expr implicit type='Int?'
1429-
/// (constructor_ref_call_expr implicit
1430-
/// (declref_expr implicit decl=Optional.init(nilLiteral:)
1431-
static bool isTypeCheckedOptionalNil(Expr *E) {
1432-
auto CE = dyn_cast<CallExpr>(E->getSemanticsProvidingExpr());
1426+
/// Return true if this is a 'nil' literal. This looks
1427+
/// like this if the type is Optional<T>:
1428+
///
1429+
/// (dot_syntax_call_expr implicit type='Int?'
1430+
/// (declref_expr implicit decl=Optional.none)
1431+
/// (type_expr type=Int?))
1432+
///
1433+
/// Or like this if it is any other ExpressibleByNilLiteral type:
1434+
///
1435+
/// (dot_syntax_call_expr implicit type='Int?'
1436+
/// (declref_expr implicit decl=Optional.none)
1437+
/// (type_expr type=Int?))
1438+
///
1439+
bool isTypeCheckedOptionalNil(Expr *E) {
1440+
auto CE = dyn_cast<ApplyExpr>(E->getSemanticsProvidingExpr());
14331441
if (!CE || !CE->isImplicit())
14341442
return false;
1435-
1443+
1444+
// First case -- Optional.none
1445+
if (auto DRE = dyn_cast<DeclRefExpr>(CE->getSemanticFn()))
1446+
return DRE->getDecl() == TC.Context.getOptionalNoneDecl();
1447+
1448+
// Second case -- init(nilLiteral:)
14361449
auto CRCE = dyn_cast<ConstructorRefCallExpr>(CE->getSemanticFn());
14371450
if (!CRCE || !CRCE->isImplicit()) return false;
1438-
1439-
auto DRE = dyn_cast<DeclRefExpr>(CRCE->getSemanticFn());
1440-
1441-
SmallString<32> NameBuffer;
1442-
auto name = DRE->getDecl()->getFullName().getString(NameBuffer);
1443-
return name == "init(nilLiteral:)";
1451+
1452+
if (auto DRE = dyn_cast<DeclRefExpr>(CRCE->getSemanticFn())) {
1453+
SmallString<32> NameBuffer;
1454+
auto name = DRE->getDecl()->getFullName().getString(NameBuffer);
1455+
return name == "init(nilLiteral:)";
1456+
}
1457+
1458+
return false;
14441459
}
1445-
1446-
1460+
1461+
14471462
/// Warn about surprising implicit optional promotions involving operands to
14481463
/// calls. Specifically, we warn about these expressions when the 'x'
14491464
/// operand is implicitly promoted to optional:

test/IRGen/big_types_corner_cases.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,6 @@ public func enumCallee(_ x: LargeEnum) {
151151
// CHECK-64: [[ALLOC1:%.*]] = alloca %T22big_types_corner_cases9BigStructV
152152
// CHECK-64: [[ALLOC2:%.*]] = alloca %T22big_types_corner_cases9BigStructV
153153
// CHECK-64: [[ALLOC3:%.*]] = alloca %T22big_types_corner_cases9BigStructVSg
154-
// CHECK-64: [[ALLOC4:%.*]] = alloca %T22big_types_corner_cases9BigStructVSg
155154
// CHECK-64: call swiftcc void @"$S22big_types_corner_cases9SuperBaseC4boomAA9BigStructVyF"(%T22big_types_corner_cases9BigStructV* noalias nocapture sret [[ALLOC1]], %T22big_types_corner_cases9SuperBaseC* swiftself {{.*}})
156155
// CHECK: ret void
157156
class SuperBase {

test/IRGen/class_bounded_generics.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,8 @@ class M<T, S: A<T>> {
282282
// CHECK-LABEL: define hidden swiftcc void @"$S22class_bounded_generics14takes_metatypeyyxmlF"(%swift.type*, %swift.type* %T)
283283
func takes_metatype<T>(_: T.Type) {}
284284

285-
// CHECK-LABEL: define hidden swiftcc void @"$S22class_bounded_generics023archetype_with_generic_A11_constraint1tyx_tAA1ACyq_GRbzr0_lF"(%T22class_bounded_generics1AC.2*, %swift.type* %T)
286-
// CHECK: [[ISA_ADDR:%.*]] = bitcast %T22class_bounded_generics1AC.2* %0 to %swift.type**
285+
// CHECK-LABEL: define hidden swiftcc void @"$S22class_bounded_generics023archetype_with_generic_A11_constraint1tyx_tAA1ACyq_GRbzr0_lF"(%T22class_bounded_generics1AC.1*, %swift.type* %T)
286+
// CHECK: [[ISA_ADDR:%.*]] = bitcast %T22class_bounded_generics1AC.1* %0 to %swift.type**
287287
// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]]
288288
// CHECK-NEXT: call swiftcc void @"$S22class_bounded_generics14takes_metatypeyyxmlF"(%swift.type* %T, %swift.type* %T)
289289
// CHECK-NEXT: [[ISA_PTR:%.*]] = bitcast %swift.type* [[ISA]] to %swift.type**
@@ -300,12 +300,12 @@ func archetype_with_generic_class_constraint<T, U>(t: T) where T : A<U> {
300300
// CHECK-LABEL: define hidden swiftcc void @"$S22class_bounded_generics029calls_archetype_with_generic_A11_constraint1ayAA1ACyxG_tlF"(%T22class_bounded_generics1AC*) #0 {
301301
// CHECK: [[ISA_ADDR:%.*]] = getelementptr inbounds %T22class_bounded_generics1AC, %T22class_bounded_generics1AC* %0, i32 0, i32 0, i32 0
302302
// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]]
303-
// CHECK: [[SELF:%.*]] = bitcast %T22class_bounded_generics1AC* %0 to %T22class_bounded_generics1AC.2*
303+
// CHECK: [[SELF:%.*]] = bitcast %T22class_bounded_generics1AC* %0 to %T22class_bounded_generics1AC.1*
304304
// CHECK-NEXT: [[ISA_PTR:%.*]] = bitcast %swift.type* [[ISA]] to %swift.type**
305305
// CHECK-NEXT: [[T_ADDR:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[ISA_PTR]], i64 10
306306
// CHECK-NEXT: [[T:%.*]] = load %swift.type*, %swift.type** [[T_ADDR]]
307307
// CHECK-NEXT: [[A_OF_T:%.*]] = call %swift.type* @"$S22class_bounded_generics1ACMa"(%swift.type* [[T]])
308-
// CHECK-NEXT: call swiftcc void @"$S22class_bounded_generics023archetype_with_generic_A11_constraint1tyx_tAA1ACyq_GRbzr0_lF"(%T22class_bounded_generics1AC.2* [[SELF]], %swift.type* [[A_OF_T]])
308+
// CHECK-NEXT: call swiftcc void @"$S22class_bounded_generics023archetype_with_generic_A11_constraint1tyx_tAA1ACyq_GRbzr0_lF"(%T22class_bounded_generics1AC.1* [[SELF]], %swift.type* [[A_OF_T]])
309309
// CHECK: ret void
310310

311311
func calls_archetype_with_generic_class_constraint<T>(a: A<T>) {

test/IRGen/class_resilience_thunks.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ public func testDispatchThunkDerived(d: Derived) {
2929
// CHECK: call swiftcc void @"$S22resilient_class_thunks4BaseC6takesTyyxFTj"(%swift.opaque* noalias nocapture dereferenceable({{4|8}}) {{%.*}}, %T22resilient_class_thunks4BaseC* swiftself {{%.*}})
3030
d.takesT(0)
3131

32-
// CHECK: call swiftcc void @"$S22resilient_class_thunks7DerivedC8takesIntyySiSgFTj"([[INT]] {{%.*}}, i8 {{%.*}}, %T22resilient_class_thunks7DerivedC* swiftself %0)
32+
// CHECK: call swiftcc void @"$S22resilient_class_thunks7DerivedC8takesIntyySiSgFTj"([[INT]] 0, i8 1, %T22resilient_class_thunks7DerivedC* swiftself %0)
3333
d.takesInt(nil)
3434

35-
// CHECK: call swiftcc void @"$S22resilient_class_thunks4BaseC14takesReferenceyyAA6ObjectCFTj"(%T22resilient_class_thunks6ObjectC* {{%.*}}, %T22resilient_class_thunks4BaseC* swiftself {{%.*}})
35+
// CHECK: call swiftcc void @"$S22resilient_class_thunks4BaseC14takesReferenceyyAA6ObjectCFTj"(%T22resilient_class_thunks6ObjectC* null, %T22resilient_class_thunks4BaseC* swiftself {{%.*}})
3636
d.takesReference(nil)
3737

3838
// CHECK: ret void

0 commit comments

Comments
 (0)