mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Teach EagerSpecializer how to use the new form of the @_specialize attribute
In addition to supporting the creation of full specializations, the EagerSpecializer changes contain some code for generating the layout-constrained partial specializations as well.
This commit is contained in:
@@ -27,6 +27,8 @@
|
||||
/// will be a tradeoff between utility of the attribute vs. cost of the check.
|
||||
|
||||
#define DEBUG_TYPE "eager-specializer"
|
||||
#include "swift/AST/GenericEnvironment.h"
|
||||
#include "swift/AST/Type.h"
|
||||
#include "swift/SIL/SILFunction.h"
|
||||
#include "swift/SILOptimizer/PassManager/Transforms.h"
|
||||
#include "swift/SILOptimizer/Utils/Generics.h"
|
||||
@@ -129,8 +131,9 @@ static void addReturnValueImpl(SILBasicBlock *RetBB, SILBasicBlock *NewRetBB,
|
||||
}
|
||||
|
||||
/// Adds a CFG edge from the unterminated NewRetBB to a merged "return" block.
|
||||
static void addReturnValue(SILBasicBlock *NewRetBB, SILValue NewRetVal) {
|
||||
auto *RetBB = &*NewRetBB->getParent()->findReturnBB();
|
||||
static void addReturnValue(SILBasicBlock *NewRetBB, SILBasicBlock *OldRetBB,
|
||||
SILValue NewRetVal) {
|
||||
auto *RetBB = OldRetBB;
|
||||
addReturnValueImpl(RetBB, NewRetBB, NewRetVal);
|
||||
}
|
||||
|
||||
@@ -150,6 +153,7 @@ emitApplyWithRethrow(SILBuilder &Builder,
|
||||
SILLocation Loc,
|
||||
SILValue FuncRef,
|
||||
CanSILFunctionType CanSILFuncTy,
|
||||
SubstitutionList Subs,
|
||||
ArrayRef<SILValue> CallArgs,
|
||||
void (*EmitCleanup)(SILBuilder&, SILLocation)) {
|
||||
|
||||
@@ -158,13 +162,15 @@ emitApplyWithRethrow(SILBuilder &Builder,
|
||||
|
||||
SILBasicBlock *ErrorBB = F.createBasicBlock();
|
||||
SILBasicBlock *NormalBB = F.createBasicBlock();
|
||||
|
||||
Builder.createTryApply(Loc,
|
||||
FuncRef,
|
||||
SILType::getPrimitiveObjectType(CanSILFuncTy),
|
||||
SubstitutionList(),
|
||||
Subs,
|
||||
CallArgs,
|
||||
NormalBB,
|
||||
ErrorBB);
|
||||
|
||||
{
|
||||
// Emit the rethrow logic.
|
||||
Builder.emitBlock(ErrorBB);
|
||||
@@ -188,27 +194,69 @@ emitApplyWithRethrow(SILBuilder &Builder,
|
||||
ValueOwnershipKind::Owned);
|
||||
}
|
||||
|
||||
/// Emits code to invoke the specified nonpolymorphic CalleeFunc using the
|
||||
/// Emits code to invoke the specified specialized CalleeFunc using the
|
||||
/// provided SILBuilder.
|
||||
///
|
||||
///
|
||||
/// TODO: Move this to Utils.
|
||||
static SILValue
|
||||
emitInvocation(SILBuilder &Builder, SILLocation Loc,
|
||||
emitInvocation(SILBuilder &Builder,
|
||||
const ReabstractionInfo &ReInfo,
|
||||
SILLocation Loc,
|
||||
SILFunction *CalleeFunc,
|
||||
ArrayRef<SILValue> CallArgs,
|
||||
void (*EmitCleanup)(SILBuilder&, SILLocation)) {
|
||||
|
||||
auto *FuncRefInst = Builder.createFunctionRef(Loc, CalleeFunc);
|
||||
auto CanSILFuncTy = CalleeFunc->getLoweredFunctionType();
|
||||
assert(!CanSILFuncTy->isPolymorphic());
|
||||
auto CalleeSubstFnTy = CanSILFuncTy;
|
||||
SubstitutionList Subs;
|
||||
if (CanSILFuncTy->isPolymorphic()) {
|
||||
// Create a substituted callee type.
|
||||
assert(CanSILFuncTy == ReInfo.getSpecializedType() &&
|
||||
"Types should be the same");
|
||||
|
||||
// We form here the list of substitutions and the substituted callee
|
||||
// type. For specializations with layout constraints, we claim that
|
||||
// the substitution T satisfies the specialized requirement
|
||||
// 'TS : LayoutConstraint', where LayoutConstraint could be
|
||||
// e.g. _Trivial(64). We claim it, because we ensure it by the
|
||||
// method how this call is constructed.
|
||||
// This is a hack and works currently just by coincidence.
|
||||
// But it is not quite true from the SIL type system
|
||||
// point of view as we do not really cast at the SIL level the original
|
||||
// parameter value of type T into a more specialized generic
|
||||
// type 'TS : LayoutConstraint'.
|
||||
//
|
||||
// TODO: Introduce a proper way to express such a cast.
|
||||
// It could be an instruction similar to checked_cast_br, e.g.
|
||||
// something like:
|
||||
// 'checked_constraint_cast_br %1 : T to $opened("") <TS : _Trivial(64)>',
|
||||
// where <TS: _Trivial(64)> introduces a new archetype with the given
|
||||
// constraints.
|
||||
if (ReInfo.getSpecializedType()->isPolymorphic()) {
|
||||
Subs = ReInfo.getCallerParamSubstitutions();
|
||||
CalleeSubstFnTy = CanSILFuncTy->substGenericArgs(
|
||||
Builder.getModule(), ReInfo.getCallerParamSubstitutions());
|
||||
assert(!CalleeSubstFnTy->isPolymorphic() &&
|
||||
"Substituted callee type should not be polymorphic");
|
||||
assert(!CalleeSubstFnTy->hasTypeParameter() &&
|
||||
"Substituted callee type should not have type parameters");
|
||||
}
|
||||
}
|
||||
|
||||
auto CalleeSILSubstFnTy = SILType::getPrimitiveObjectType(CalleeSubstFnTy);
|
||||
SILFunctionConventions fnConv(CalleeSILSubstFnTy.castTo<SILFunctionType>(),
|
||||
Builder.getModule());
|
||||
|
||||
if (!CanSILFuncTy->hasErrorResult()) {
|
||||
assert(!CanSILFuncTy->isPolymorphic());
|
||||
return Builder.createApply(CalleeFunc->getLocation(), FuncRefInst, CallArgs,
|
||||
false);
|
||||
return Builder.createApply(
|
||||
CalleeFunc->getLocation(), FuncRefInst, CalleeSILSubstFnTy,
|
||||
fnConv.getSILResultType(), Subs, CallArgs, false);
|
||||
}
|
||||
return emitApplyWithRethrow(Builder, CalleeFunc->getLocation(), FuncRefInst,
|
||||
CanSILFuncTy, CallArgs, EmitCleanup);
|
||||
return emitApplyWithRethrow(Builder, CalleeFunc->getLocation(),
|
||||
FuncRefInst, CalleeSubstFnTy, Subs,
|
||||
CallArgs,
|
||||
EmitCleanup);
|
||||
}
|
||||
|
||||
/// Returns the thick metatype for the given SILType.
|
||||
@@ -222,25 +270,26 @@ namespace {
|
||||
/// Helper class for emitting code to dispatch to a specialized function.
|
||||
class EagerDispatch {
|
||||
SILFunction *GenericFunc;
|
||||
#if 0
|
||||
const SILSpecializeAttr &SA;
|
||||
#endif
|
||||
const ReabstractionInfo &ReInfo;
|
||||
const SILFunctionConventions substConv;
|
||||
|
||||
SILBuilder Builder;
|
||||
SILLocation Loc;
|
||||
// Function to check if a given object is a class.
|
||||
SILFunction *IsClassF;
|
||||
|
||||
public:
|
||||
// Instantiate a SILBuilder for inserting instructions at the top of the
|
||||
// original generic function.
|
||||
EagerDispatch(SILFunction *GenericFunc, const SILSpecializeAttr &SA,
|
||||
EagerDispatch(SILFunction *GenericFunc,
|
||||
const ReabstractionInfo &ReInfo)
|
||||
: GenericFunc(GenericFunc), ReInfo(ReInfo),
|
||||
substConv(ReInfo.getSubstitutedType(), GenericFunc->getModule()),
|
||||
Builder(*GenericFunc), Loc(GenericFunc->getLocation()) {
|
||||
|
||||
Builder.setCurrentDebugScope(GenericFunc->getDebugScope());
|
||||
IsClassF = Builder.getModule().hasFunction(
|
||||
"_swift_isClassOrObjCExistentialType", SILLinkage::PublicExternal);
|
||||
assert(IsClassF);
|
||||
}
|
||||
|
||||
void emitDispatchTo(SILFunction *NewFunc);
|
||||
@@ -249,7 +298,23 @@ protected:
|
||||
void emitTypeCheck(SILBasicBlock *FailedTypeCheckBB,
|
||||
SubstitutableType *ParamTy, Type SubTy);
|
||||
|
||||
SILValue emitArgumentCast(SILFunctionArgument *OrigArg, unsigned Idx);
|
||||
void emitTrivialAndSizeCheck(SILBasicBlock *FailedTypeCheckBB,
|
||||
SubstitutableType *ParamTy, Type SubTy,
|
||||
LayoutConstraint Layout);
|
||||
|
||||
void emitIsTrivialCheck(SILBasicBlock *FailedTypeCheckBB,
|
||||
SubstitutableType *ParamTy, Type SubTy,
|
||||
LayoutConstraint Layout);
|
||||
|
||||
void emitRefCountedObjectCheck(SILBasicBlock *FailedTypeCheckBB,
|
||||
SubstitutableType *ParamTy, Type SubTy,
|
||||
LayoutConstraint Layout);
|
||||
|
||||
void emitLayoutCheck(SILBasicBlock *FailedTypeCheckBB,
|
||||
SubstitutableType *ParamTy, Type SubTy);
|
||||
|
||||
SILValue emitArgumentCast(CanSILFunctionType CalleeSubstFnTy,
|
||||
SILFunctionArgument *OrigArg, unsigned Idx);
|
||||
|
||||
SILValue emitArgumentConversion(SmallVectorImpl<SILValue> &CallArgs);
|
||||
};
|
||||
@@ -259,7 +324,7 @@ protected:
|
||||
/// given specialized function. Converts call arguments. Emits an invocation of
|
||||
/// the specialized function. Handle the return value.
|
||||
void EagerDispatch::emitDispatchTo(SILFunction *NewFunc) {
|
||||
|
||||
SILBasicBlock *OldReturnBB = &*GenericFunc->findReturnBB();
|
||||
// 1. Emit a cascading sequence of type checks blocks.
|
||||
|
||||
// First split the entry BB, moving all instructions to the FailedTypeCheckBB.
|
||||
@@ -270,26 +335,49 @@ void EagerDispatch::emitDispatchTo(SILFunction *NewFunc) {
|
||||
// Iterate over all dependent types in the generic signature, which will match
|
||||
// the specialized attribute's substitution list. Visit only
|
||||
// SubstitutableTypes, skipping DependentTypes.
|
||||
// TODO: Uncomment when Generics.cpp is updated to use the
|
||||
// new @_specialize attribute for partial specializations.
|
||||
#if 0
|
||||
auto GenericSig =
|
||||
GenericFunc->getLoweredFunctionType()->getGenericSignature();
|
||||
|
||||
auto SubIt = SA.getSubstitutions().begin();
|
||||
auto SubEnd = SA.getSubstitutions().end();
|
||||
for (auto DepTy : GenericSig->getAllDependentTypes()) {
|
||||
auto SubIt = ReInfo.getClonerParamSubstitutions().begin();
|
||||
auto SubEnd = ReInfo.getClonerParamSubstitutions().end();
|
||||
auto DepTypes = GenericSig->getAllDependentTypes();
|
||||
for (auto DepTy : DepTypes) {
|
||||
assert(SubIt != SubEnd && "Not enough substitutions.");
|
||||
|
||||
if (auto ParamTy = DepTy->getAs<SubstitutableType>())
|
||||
emitTypeCheck(FailedTypeCheckBB, ParamTy, SubIt->getReplacement());
|
||||
if (auto ParamTy = DepTy->getAs<SubstitutableType>()) {
|
||||
auto Replacement = SubIt->getReplacement();
|
||||
auto GenericEnv = ReInfo.getSpecializedGenericEnvironment();
|
||||
if (!Replacement->hasArchetype()) {
|
||||
if (GenericEnv)
|
||||
Replacement = GenericEnv->mapTypeIntoContext(Replacement);
|
||||
assert(!Replacement->hasTypeParameter());
|
||||
// Dispatch on concrete type.
|
||||
emitTypeCheck(FailedTypeCheckBB, ParamTy, Replacement);
|
||||
} else {
|
||||
// If Replacement has a layout constraint, then dispatch based
|
||||
// on its size and the fact that it is trivial.
|
||||
auto LayoutInfo = Replacement->getLayoutConstraint();
|
||||
if (LayoutInfo && LayoutInfo->isTrivial()) {
|
||||
// Emit a check that it is a trivial type of a certain size.
|
||||
emitTrivialAndSizeCheck(FailedTypeCheckBB, ParamTy,
|
||||
GenericEnv->mapTypeIntoContext(Replacement),
|
||||
LayoutInfo);
|
||||
} else if (LayoutInfo && LayoutInfo->isRefCountedObject()) {
|
||||
// Emit a check that it is an object of a reference counted type.
|
||||
emitRefCountedObjectCheck(FailedTypeCheckBB, ParamTy,
|
||||
GenericEnv->mapTypeIntoContext(Replacement),
|
||||
LayoutInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
++SubIt;
|
||||
}
|
||||
assert(SubIt == SubEnd && "Too many substitutions.");
|
||||
(void) SubEnd;
|
||||
#else
|
||||
static_cast<void>(FailedTypeCheckBB);
|
||||
#endif
|
||||
|
||||
if (OldReturnBB == &EntryBB) {
|
||||
OldReturnBB = FailedTypeCheckBB;
|
||||
}
|
||||
|
||||
// 2. Convert call arguments, casting and adjusting for calling convention.
|
||||
|
||||
SmallVector<SILValue, 8> CallArgs;
|
||||
@@ -300,7 +388,8 @@ void EagerDispatch::emitDispatchTo(SILFunction *NewFunc) {
|
||||
// Emit any rethrow with no cleanup since all args have been forwarded and
|
||||
// nothing has been locally allocated or copied.
|
||||
auto NoCleanup = [](SILBuilder&, SILLocation){};
|
||||
SILValue Result = emitInvocation(Builder, Loc, NewFunc, CallArgs, NoCleanup);
|
||||
SILValue Result =
|
||||
emitInvocation(Builder, ReInfo, Loc, NewFunc, CallArgs, NoCleanup);
|
||||
|
||||
// 4. Handle the return value.
|
||||
|
||||
@@ -323,7 +412,7 @@ void EagerDispatch::emitDispatchTo(SILFunction *NewFunc) {
|
||||
auto resultTy = GenericFunc->getConventions().getSILResultType();
|
||||
auto GenResultTy = GenericFunc->mapTypeIntoContext(resultTy);
|
||||
auto CastResult = Builder.createUncheckedBitCast(Loc, Result, GenResultTy);
|
||||
addReturnValue(Builder.getInsertionBB(), CastResult);
|
||||
addReturnValue(Builder.getInsertionBB(), OldReturnBB, CastResult);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,10 +461,138 @@ emitTypeCheck(SILBasicBlock *FailedTypeCheckBB, SubstitutableType *ParamTy,
|
||||
Builder.emitBlock(SuccessBB);
|
||||
}
|
||||
|
||||
void EagerDispatch::emitIsTrivialCheck(SILBasicBlock *FailedTypeCheckBB,
|
||||
SubstitutableType *ParamTy, Type SubTy,
|
||||
LayoutConstraint Layout) {
|
||||
auto &Ctx = Builder.getASTContext();
|
||||
// Instantiate a thick metatype for T.Type
|
||||
auto ContextTy = GenericFunc->mapTypeIntoContext(ParamTy);
|
||||
auto GenericMT = Builder.createMetatype(
|
||||
Loc, getThickMetatypeType(ContextTy->getCanonicalType()));
|
||||
auto BoolTy = SILType::getBuiltinIntegerType(1, Ctx);
|
||||
Substitution Sub(ContextTy, {});
|
||||
|
||||
// Emit a check that it is a pod object.
|
||||
auto IsPOD = Builder.createBuiltin(Loc, Ctx.getIdentifier("ispod"), BoolTy,
|
||||
Sub, {GenericMT});
|
||||
auto *SuccessBB = Builder.getFunction().createBasicBlock();
|
||||
Builder.createCondBranch(Loc, IsPOD, SuccessBB, FailedTypeCheckBB);
|
||||
Builder.emitBlock(SuccessBB);
|
||||
}
|
||||
|
||||
void EagerDispatch::emitTrivialAndSizeCheck(SILBasicBlock *FailedTypeCheckBB,
|
||||
SubstitutableType *ParamTy,
|
||||
Type SubTy,
|
||||
LayoutConstraint Layout) {
|
||||
if (Layout->isAddressOnlyTrivial()) {
|
||||
emitIsTrivialCheck(FailedTypeCheckBB, ParamTy, SubTy, Layout);
|
||||
return;
|
||||
}
|
||||
auto &Ctx = Builder.getASTContext();
|
||||
// Instantiate a thick metatype for T.Type
|
||||
auto ContextTy = GenericFunc->mapTypeIntoContext(ParamTy);
|
||||
auto GenericMT = Builder.createMetatype(
|
||||
Loc, getThickMetatypeType(ContextTy->getCanonicalType()));
|
||||
|
||||
auto WordTy = SILType::getBuiltinWordType(Ctx);
|
||||
auto BoolTy = SILType::getBuiltinIntegerType(1, Ctx);
|
||||
Substitution Sub(ContextTy, {});
|
||||
auto ParamSize = Builder.createBuiltin(Loc, Ctx.getIdentifier("sizeof"),
|
||||
WordTy, Sub, { GenericMT });
|
||||
auto LayoutSize =
|
||||
Builder.createIntegerLiteral(Loc, WordTy, Layout->getTrivialSizeInBytes());
|
||||
const char *CmpOpName = Layout->isFixedSizeTrivial() ? "cmp_eq" : "cmp_le";
|
||||
auto Cmp =
|
||||
Builder.createBuiltinBinaryFunction(Loc, CmpOpName, WordTy,
|
||||
BoolTy,
|
||||
{ParamSize, LayoutSize});
|
||||
|
||||
auto *SuccessBB1 = Builder.getFunction().createBasicBlock();
|
||||
Builder.createCondBranch(Loc, Cmp, SuccessBB1, FailedTypeCheckBB);
|
||||
Builder.emitBlock(SuccessBB1);
|
||||
// Emit a check that it is a pod object.
|
||||
// TODO: Perform this check before all the fixed size checks!
|
||||
auto IsPOD = Builder.createBuiltin(Loc, Ctx.getIdentifier("ispod"),
|
||||
BoolTy, Sub, { GenericMT });
|
||||
auto *SuccessBB2 = Builder.getFunction().createBasicBlock();
|
||||
Builder.createCondBranch(Loc, IsPOD, SuccessBB2, FailedTypeCheckBB);
|
||||
Builder.emitBlock(SuccessBB2);
|
||||
}
|
||||
|
||||
void EagerDispatch::emitRefCountedObjectCheck(SILBasicBlock *FailedTypeCheckBB,
|
||||
SubstitutableType *ParamTy,
|
||||
Type SubTy,
|
||||
LayoutConstraint Layout) {
|
||||
auto &Ctx = Builder.getASTContext();
|
||||
// Instantiate a thick metatype for T.Type
|
||||
auto ContextTy = GenericFunc->mapTypeIntoContext(ParamTy);
|
||||
auto GenericMT = Builder.createMetatype(
|
||||
Loc, getThickMetatypeType(ContextTy->getCanonicalType()));
|
||||
|
||||
auto Int8Ty = SILType::getBuiltinIntegerType(8, Ctx);
|
||||
auto BoolTy = SILType::getBuiltinIntegerType(1, Ctx);
|
||||
Substitution Sub(ContextTy, {});
|
||||
|
||||
// Emit a check that it is a reference-counted object.
|
||||
// TODO: Perform this check before all fixed size checks.
|
||||
// FIXME: What builtin do we use to check it????
|
||||
auto CanBeClass = Builder.createBuiltin(
|
||||
Loc, Ctx.getIdentifier("canBeClass"), Int8Ty, Sub, {GenericMT});
|
||||
auto ClassConst =
|
||||
Builder.createIntegerLiteral(Loc, Int8Ty, 1);
|
||||
auto Cmp1 =
|
||||
Builder.createBuiltinBinaryFunction(Loc, "cmp_eq", Int8Ty,
|
||||
BoolTy,
|
||||
{CanBeClass, ClassConst});
|
||||
|
||||
auto *SuccessBB = Builder.getFunction().createBasicBlock();
|
||||
auto *MayBeCalssCheckBB = Builder.getFunction().createBasicBlock();
|
||||
Builder.createCondBranch(Loc, Cmp1, SuccessBB,
|
||||
MayBeCalssCheckBB);
|
||||
|
||||
Builder.emitBlock(MayBeCalssCheckBB);
|
||||
|
||||
auto MayBeClassConst =
|
||||
Builder.createIntegerLiteral(Loc, Int8Ty, 2);
|
||||
auto Cmp2 =
|
||||
Builder.createBuiltinBinaryFunction(Loc, "cmp_eq", Int8Ty,
|
||||
BoolTy,
|
||||
{CanBeClass, MayBeClassConst});
|
||||
|
||||
auto *IsClassCheckBB = Builder.getFunction().createBasicBlock();
|
||||
Builder.createCondBranch(Loc, Cmp2, IsClassCheckBB,
|
||||
FailedTypeCheckBB);
|
||||
|
||||
Builder.emitBlock(IsClassCheckBB);
|
||||
|
||||
auto *FRI = Builder.createFunctionRef(Loc, IsClassF);
|
||||
auto CanFnTy = IsClassF->getLoweredFunctionType()->substGenericArgs(
|
||||
Builder.getModule(), {Sub});
|
||||
auto SILFnTy = SILType::getPrimitiveObjectType(CanFnTy);
|
||||
SILFunctionConventions fnConv(CanFnTy, Builder.getModule());
|
||||
auto SILResultTy = fnConv.getSILResultType();
|
||||
auto IsClassRuntimeCheck =
|
||||
Builder.createApply(Loc, FRI, SILFnTy, SILResultTy, {Sub}, {GenericMT},
|
||||
/* isNonThrowing */ false);
|
||||
// Extract the i1 from the Bool struct.
|
||||
StructDecl *BoolStruct = cast<StructDecl>(Ctx.getBoolDecl());
|
||||
auto Members = BoolStruct->lookupDirect(Ctx.Id_value_);
|
||||
assert(Members.size() == 1 &&
|
||||
"Bool should have only one property with name '_value'");
|
||||
auto Member = dyn_cast<VarDecl>(Members[0]);
|
||||
assert(Member &&"Bool should have a property with name '_value' of type Int1");
|
||||
auto BoolValue =
|
||||
Builder.emitStructExtract(Loc, IsClassRuntimeCheck, Member, BoolTy);
|
||||
Builder.createCondBranch(Loc, BoolValue, SuccessBB, FailedTypeCheckBB);
|
||||
|
||||
Builder.emitBlock(SuccessBB);
|
||||
}
|
||||
|
||||
/// Cast a generic argument to its specialized type.
|
||||
SILValue EagerDispatch::emitArgumentCast(SILFunctionArgument *OrigArg,
|
||||
SILValue EagerDispatch::emitArgumentCast(CanSILFunctionType CalleeSubstFnTy,
|
||||
SILFunctionArgument *OrigArg,
|
||||
unsigned Idx) {
|
||||
SILFunctionConventions substConv(ReInfo.getSubstitutedType(),
|
||||
SILFunctionConventions substConv(CalleeSubstFnTy,
|
||||
Builder.getModule());
|
||||
auto CastTy = substConv.getSILArgumentType(Idx);
|
||||
assert(CastTy.isAddress()
|
||||
@@ -401,13 +618,32 @@ emitArgumentConversion(SmallVectorImpl<SILValue> &CallArgs) {
|
||||
auto OrigArgs = GenericFunc->begin()->getFunctionArguments();
|
||||
assert(OrigArgs.size() == substConv.getNumSILArguments()
|
||||
&& "signature mismatch");
|
||||
// Create a substituted callee type.
|
||||
auto SubstitutedType = ReInfo.getSubstitutedType();
|
||||
auto SpecializedType = ReInfo.getSpecializedType();
|
||||
auto CanSILFuncTy = SubstitutedType;
|
||||
auto CalleeSubstFnTy = CanSILFuncTy;
|
||||
if (CanSILFuncTy->isPolymorphic()) {
|
||||
CalleeSubstFnTy = CanSILFuncTy->substGenericArgs(
|
||||
Builder.getModule(), ReInfo.getCallerParamSubstitutions());
|
||||
assert(!CalleeSubstFnTy->isPolymorphic() &&
|
||||
"Substituted callee type should not be polymorphic");
|
||||
assert(!CalleeSubstFnTy->hasTypeParameter() &&
|
||||
"Substituted callee type should not have type parameters");
|
||||
|
||||
SubstitutedType = CalleeSubstFnTy;
|
||||
SpecializedType =
|
||||
ReInfo.createSpecializedType(SubstitutedType, Builder.getModule());
|
||||
}
|
||||
|
||||
assert(OrigArgs.size() == ReInfo.getNumArguments() && "signature mismatch");
|
||||
|
||||
CallArgs.reserve(OrigArgs.size());
|
||||
SILValue StoreResultTo;
|
||||
for (auto *OrigArg : OrigArgs) {
|
||||
unsigned ArgIdx = OrigArg->getIndex();
|
||||
|
||||
auto CastArg = emitArgumentCast(OrigArg, ArgIdx);
|
||||
auto CastArg = emitArgumentCast(SubstitutedType, OrigArg, ArgIdx);
|
||||
DEBUG(dbgs() << " Cast generic arg: "; CastArg->print(dbgs()));
|
||||
|
||||
if (!substConv.useLoweredAddresses()) {
|
||||
@@ -431,6 +667,15 @@ emitArgumentConversion(SmallVectorImpl<SILValue> &CallArgs) {
|
||||
if (ReInfo.isParamConverted(paramIdx)) {
|
||||
// An argument is converted from indirect to direct. Instead of the
|
||||
// address we pass the loaded value.
|
||||
// FIXME: If type of CastArg is an archetype, but it is loadable because
|
||||
// of a layout constraint on the caller side, we have a problem here
|
||||
// We need to load the value on the caller side, but this archetype is
|
||||
// not statically known to be loadable on the caller side (though we
|
||||
// have proven dynamically that it has a fixed size).
|
||||
// We can try to load it as an int value of width N, but then it is not
|
||||
// clear how to convert it into a value of the archetype type, which is
|
||||
// expected. May be we should pass it as @in parameter and make it
|
||||
// loadable on the caller's side?
|
||||
SILValue Val = Builder.createLoad(Loc, CastArg,
|
||||
LoadOwnershipQualifier::Unqualified);
|
||||
CallArgs.push_back(Val);
|
||||
@@ -455,9 +700,6 @@ public:
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
// TODO: Uncomment when Generics.cpp is updated to use the
|
||||
// new @_specialize attribute for partial specializations.
|
||||
#if 0
|
||||
/// Specializes a generic function for a concrete type list.
|
||||
static SILFunction *eagerSpecialize(SILFunction *GenericFunc,
|
||||
const SILSpecializeAttr &SA,
|
||||
@@ -475,66 +717,67 @@ static SILFunction *eagerSpecialize(SILFunction *GenericFunc,
|
||||
[]{ dbgs() << ", "; });
|
||||
dbgs() << "> with ";
|
||||
SA.print(dbgs()); dbgs() << "\n");
|
||||
|
||||
// Create a specialized function.
|
||||
// TODO: Uncomment when Generics.cpp is updated to use the
|
||||
// new @_specialize attribute for partial specializations.
|
||||
#if 0
|
||||
|
||||
GenericFuncSpecializer
|
||||
FuncSpecializer(GenericFunc, SA.getSubstitutions(),
|
||||
FuncSpecializer(GenericFunc, ReInfo.getClonerParamSubstitutions(),
|
||||
GenericFunc->isFragile(), ReInfo);
|
||||
|
||||
SILFunction *NewFunc = FuncSpecializer.trySpecialization();
|
||||
if (!NewFunc)
|
||||
DEBUG(dbgs() << " Failed. Cannot specialize function.\n");
|
||||
return NewFunc;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Run the pass.
|
||||
void EagerSpecializerTransform::run() {
|
||||
if (!EagerSpecializeFlag)
|
||||
return;
|
||||
|
||||
|
||||
// Process functions in any order.
|
||||
bool Changed = false;
|
||||
for (auto &F : *getModule()) {
|
||||
if (!F.shouldOptimize()) {
|
||||
DEBUG(dbgs() << " Cannot specialize function " << F.getName()
|
||||
<< " marked to be excluded from optimizations.\n");
|
||||
<< " marked to be excluded from optimizations.\n");
|
||||
continue;
|
||||
}
|
||||
// Only specialize functions in their home module.
|
||||
if (F.isExternalDeclaration() || F.isAvailableExternally())
|
||||
continue;
|
||||
|
||||
if (!F.getLoweredFunctionType()->getGenericSignature())
|
||||
continue;
|
||||
|
||||
// Create a specialized function with ReabstractionInfo for each attribute.
|
||||
SmallVector<SILFunction*, 8> SpecializedFuncs;
|
||||
SmallVector<SILFunction *, 8> SpecializedFuncs;
|
||||
SmallVector<ReabstractionInfo, 4> ReInfoVec;
|
||||
ReInfoVec.reserve(F.getSpecializeAttrs().size());
|
||||
|
||||
// TODO: Uncomment when Generics.cpp is updated to use the
|
||||
// new @_specialize attribute for partial specializations.
|
||||
#if 0
|
||||
// TODO: Use a decision-tree to reduce the amount of dynamic checks being
|
||||
// performed.
|
||||
for (auto *SA : F.getSpecializeAttrs()) {
|
||||
ReInfoVec.emplace_back(&F, SA->getSubstitutions());
|
||||
auto AttrRequirements = SA->getRequirements();
|
||||
ReInfoVec.emplace_back(&F, AttrRequirements);
|
||||
auto *NewFunc = eagerSpecialize(&F, *SA, ReInfoVec.back());
|
||||
|
||||
SpecializedFuncs.push_back(NewFunc);
|
||||
|
||||
if (SA->isExported()) {
|
||||
NewFunc->setKeepAsPublic(true);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Emit a type check and dispatch to each specialized function.
|
||||
// TODO: Optimize the dispatch code to minimize the amount
|
||||
// of checks. Use decision trees for this purpose.
|
||||
for_each3(F.getSpecializeAttrs(), SpecializedFuncs, ReInfoVec,
|
||||
[&](const SILSpecializeAttr *SA, SILFunction *NewFunc,
|
||||
const ReabstractionInfo &ReInfo) {
|
||||
if (NewFunc) {
|
||||
Changed = true;
|
||||
EagerDispatch(&F, *SA, ReInfo).emitDispatchTo(NewFunc);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
[&](const SILSpecializeAttr *SA, SILFunction *NewFunc,
|
||||
const ReabstractionInfo &ReInfo) {
|
||||
if (NewFunc) {
|
||||
Changed = true;
|
||||
EagerDispatch(&F, ReInfo).emitDispatchTo(NewFunc);
|
||||
}
|
||||
});
|
||||
// As specializations are created, the attributes should be removed.
|
||||
F.clearSpecializeAttrs();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user