Skip to content

Commit 5f5ed55

Browse files
committed
[silgen] When emitting a curry thunk, if the canonical type of the function differs from the actual function type in a non-ABI compatible way, use a canonical function thunk instead of a convert_function.
convert_function can only be used for to convert in between ABI compatible functions. rdar://34222540
1 parent af56e84 commit 5f5ed55

File tree

5 files changed

+443
-3
lines changed

5 files changed

+443
-3
lines changed

lib/SILGen/SILGenFunction.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,13 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
569569
CanAnyFunctionType funcTy,
570570
CanAnyFunctionType blockTy,
571571
CanSILFunctionType loweredBlockTy);
572-
572+
573+
/// Given a non-canonical function type, create a thunk for the function's
574+
/// canonical type.
575+
ManagedValue emitCanonicalFunctionThunk(SILLocation loc, ManagedValue fn,
576+
CanSILFunctionType nonCanonicalTy,
577+
CanSILFunctionType canonicalTy);
578+
573579
/// Thunk with the signature of a base class method calling a derived class
574580
/// method.
575581
///

lib/SILGen/SILGenPoly.cpp

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3407,3 +3407,148 @@ void SILGenFunction::emitProtocolWitness(Type selfType,
34073407
scope.pop();
34083408
B.createReturn(loc, reqtResultValue);
34093409
}
3410+
3411+
//===----------------------------------------------------------------------===//
3412+
// Conversion to Canonical SILFunctionType Thunks
3413+
//===----------------------------------------------------------------------===//
3414+
3415+
static void translateParametersForCanonicalFunctionThunk(
3416+
SILGenFunction &SGF, SILLocation loc,
3417+
ArrayRef<ManagedValue> origParamValues,
3418+
ArrayRef<SILParameterInfo> newParamInfos,
3419+
SmallVectorImpl<ManagedValue> &newParams) {
3420+
assert(origParamValues.size() == newParamInfos.size());
3421+
3422+
for (auto T : llvm::zip(origParamValues, newParamInfos)) {
3423+
ManagedValue origParam;
3424+
SILParameterInfo newParamInfo;
3425+
std::tie(origParam, newParamInfo) = T;
3426+
3427+
if (origParam.getType().isTrivial(SGF.getModule())) {
3428+
newParams.emplace_back(origParam);
3429+
continue;
3430+
}
3431+
3432+
if (origParam.hasCleanup()) {
3433+
// If we have a +1 value and the non-canonical function expects a
3434+
// guaranteed parameter, borrow the parameter. Otherwise just pass off the
3435+
// +1 value.
3436+
if (newParamInfo.isGuaranteed()) {
3437+
origParam = origParam.borrow(SGF, loc);
3438+
}
3439+
newParams.emplace_back(origParam);
3440+
continue;
3441+
}
3442+
3443+
// Otherwise, if we have a +0 value and we want to pass it off as a +1
3444+
// value, perform the copy.
3445+
if (newParamInfo.isConsumed()) {
3446+
origParam = origParam.copy(SGF, loc);
3447+
}
3448+
newParams.emplace_back(origParam);
3449+
}
3450+
}
3451+
3452+
static void buildCanonicalFunctionThunkBody(SILGenFunction &SGF,
3453+
SILLocation loc,
3454+
CanSILFunctionType nonCanonicalTy,
3455+
CanSILFunctionType canonicalTy) {
3456+
SGF.F.setBare(IsBare);
3457+
SGF.F.setThunk(IsThunk);
3458+
3459+
FullExpr scope(SGF.Cleanups, CleanupLocation::get(loc));
3460+
FormalEvaluationScope formalEvalScope(SGF);
3461+
3462+
// Collect the thunk params, creating arguments for each parameter.
3463+
SmallVector<ManagedValue, 8> origParams;
3464+
SGF.collectThunkParams(loc, origParams);
3465+
3466+
// Then translate our parameters into new params.
3467+
SmallVector<ManagedValue, 8> newParams;
3468+
translateParametersForCanonicalFunctionThunk(
3469+
SGF, loc,
3470+
// We drop the front so we don't process the thunked function here. We
3471+
// handle that later.
3472+
llvm::makeArrayRef(origParams).drop_back(1),
3473+
nonCanonicalTy->getParameters(), newParams);
3474+
3475+
// Then grab the function we are going to call from the last parameter.
3476+
ManagedValue fn = origParams.back();
3477+
3478+
// Collect the arguments.
3479+
SmallVector<SILValue, 8> args;
3480+
3481+
// Add all of the indirect results. We can just add the SILValues directly to
3482+
// the args array since we do not need to perform any transformations upon
3483+
// them because:
3484+
//
3485+
// 1. Reabstraction can not occur as a result of a canonical/non-canonical
3486+
// mismatch.
3487+
// 2. SILGenFunction::collectThunkParams(...) does not create cleanups when it
3488+
// creates arguments.
3489+
SILFunctionConventions fnConv(canonicalTy, SGF.SGM.M);
3490+
transform(range(fnConv.getNumIndirectSILResults()), std::back_inserter(args),
3491+
[&](unsigned Index) -> SILValue {
3492+
return SGF.F.begin()->getArgument(Index);
3493+
});
3494+
3495+
// and then the rest of the arguments besides the first argument. Here we have
3496+
// to forward the arguments since collectThunkParams /does/ create cleanups
3497+
// for the parameters.
3498+
forwardFunctionArguments(SGF, loc, nonCanonicalTy, newParams, args);
3499+
3500+
// Perform the call.
3501+
SILValue result =
3502+
SGF.emitApplyWithRethrow(loc, fn.forward(SGF), fn.getType(), {}, args);
3503+
3504+
formalEvalScope.pop();
3505+
scope.pop();
3506+
SGF.B.createReturn(loc, result);
3507+
}
3508+
3509+
ManagedValue
3510+
SILGenFunction::emitCanonicalFunctionThunk(SILLocation loc, ManagedValue fn,
3511+
CanSILFunctionType nonCanonicalTy,
3512+
CanSILFunctionType canonicalTy) {
3513+
canonicalTy = canonicalTy->getWithRepresentation(
3514+
SILFunctionType::Representation::Thick);
3515+
3516+
SubstitutionMap contextSubs, interfaceSubs;
3517+
GenericEnvironment *genericEnv = nullptr;
3518+
3519+
// These two are not used here -- but really, bridging thunks
3520+
// should be emitted using the formal AST type, not the lowered
3521+
// type
3522+
CanType inputSubstType;
3523+
CanType outputSubstType;
3524+
auto thunkTy = buildThunkType(nonCanonicalTy, canonicalTy, inputSubstType,
3525+
outputSubstType, genericEnv, interfaceSubs);
3526+
auto thunk = SGM.getOrCreateReabstractionThunk(thunkTy, nonCanonicalTy,
3527+
canonicalTy, F.isSerialized());
3528+
if (thunk->empty()) {
3529+
thunk->setGenericEnvironment(genericEnv);
3530+
SILGenFunction thunkSGF(SGM, *thunk);
3531+
auto loc = RegularLocation::getAutoGeneratedLocation();
3532+
buildCanonicalFunctionThunkBody(thunkSGF, loc, nonCanonicalTy, canonicalTy);
3533+
}
3534+
3535+
CanSILFunctionType substFnTy = thunkTy;
3536+
3537+
SmallVector<Substitution, 4> subs;
3538+
if (auto genericSig = thunkTy->getGenericSignature()) {
3539+
genericSig->getSubstitutions(interfaceSubs, subs);
3540+
substFnTy = thunkTy->substGenericArgs(F.getModule(), interfaceSubs);
3541+
}
3542+
3543+
// Create it in the current function.
3544+
auto thunkValue = B.createFunctionRef(loc, thunk);
3545+
ManagedValue thunkedFn = B.createPartialApply(
3546+
loc, thunkValue, SILType::getPrimitiveObjectType(substFnTy), subs, {fn},
3547+
SILType::getPrimitiveObjectType(canonicalTy));
3548+
if (canonicalTy->isNoEscape()) {
3549+
auto &funcTL = getTypeLowering(canonicalTy);
3550+
thunkedFn =
3551+
B.createConvertFunction(loc, thunkedFn, funcTL.getLoweredType());
3552+
}
3553+
return thunkedFn;
3554+
}

lib/SILGen/SILGenThunk.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,18 @@ void SILGenFunction::emitCurryThunk(SILDeclRef thunk) {
268268
toFn->getType(), /*appliedParams=*/1, SGM.M, subs, calleeConvention);
269269
SILValue toClosure =
270270
B.createPartialApply(vd, toFn, substTy, subs, {selfArg}, closureTy);
271-
if (resultTy != closureTy)
272-
toClosure = B.createConvertFunction(vd, toClosure, resultTy);
271+
if (resultTy != closureTy) {
272+
CanSILFunctionType resultFnTy = resultTy.castTo<SILFunctionType>();
273+
CanSILFunctionType closureFnTy = closureTy.castTo<SILFunctionType>();
274+
if (resultFnTy->isABICompatibleWith(closureFnTy).isCompatible()) {
275+
toClosure = B.createConvertFunction(vd, toClosure, resultTy);
276+
} else {
277+
toClosure =
278+
emitCanonicalFunctionThunk(vd, ManagedValue::forUnmanaged(toClosure),
279+
closureFnTy, resultFnTy)
280+
.forward(*this);
281+
}
282+
}
273283
B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(vd), toClosure);
274284
}
275285

test/SILGen/guaranteed_normal_args.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ case none
1616
case some(T)
1717
}
1818

19+
func _diagnoseUnexpectedNilOptional(_filenameStart: Builtin.RawPointer,
20+
_filenameLength: Builtin.Word,
21+
_filenameIsASCII: Builtin.Int1,
22+
_line: Builtin.Word) {
23+
// This would usually contain an assert, but we don't need one since we are
24+
// just emitting SILGen.
25+
}
26+
1927
class Klass {
2028
init() {}
2129
}
@@ -99,3 +107,4 @@ struct ReabstractionThunkTest : Protocol {
99107
processInput(input)
100108
}
101109
}
110+

0 commit comments

Comments
 (0)