SIL: Uncurry function types within the Swift type system.

Remove uncurry level as a property of SILType/SILFunctionTypeInfo. During SIL type lowering, map a (Type, UncurryLevel) pair to a Swift CanType with the uncurried arguments as a Swift tuple. For example, T -> (U, V) -> W at uncurry level 1 becomes ((U, V), T) -> W--in reverse order to match the low-level calling convention. Update SILGen and IRGen all over the place for this representation change.

SILFunctionTypeInfo is still used in the SILType representation, but it's no longer load-bearing. Everything remaining in it can be derived from a Swift type.

This is an ABI break. Be sure to rebuild clean!

Swift SVN r5296
This commit is contained in:
Joe Groff
2013-05-24 01:51:07 +00:00
parent 9d34624669
commit 5e2779b51e
23 changed files with 750 additions and 750 deletions

View File

@@ -103,6 +103,8 @@ public:
const_bbarg_iterator bbarg_begin() const { return BBArgList.begin(); }
const_bbarg_iterator bbarg_end() const { return BBArgList.end(); }
ArrayRef<SILArgument*> getBBArgs() const { return BBArgList; }
//===--------------------------------------------------------------------===//
// Predecessors and Successors
//===--------------------------------------------------------------------===//

View File

@@ -73,11 +73,6 @@ public:
return LoweredType.getFunctionTypeInfo();
}
/// Returns the uncurry level of this entry point.
unsigned getUncurryLevel() const {
return getFunctionTypeInfo()->getUncurryLevel();
}
/// Returns the calling convention used by this entry point.
AbstractCC getAbstractCC() const {
return getLoweredType().getFunctionCC();

View File

@@ -327,7 +327,13 @@ public:
SILValue getIndirectReturn() const {
assert(hasIndirectReturn() && "apply inst does not have indirect return!");
return getArguments().back();
return getArguments().front();
}
OperandValueArrayRef getArgumentsWithoutIndirectReturn() const {
if (hasIndirectReturn())
return getArguments().slice(1);
return getArguments();
}
static bool classof(const ValueBase *V) {

View File

@@ -143,18 +143,10 @@ public:
return value.getPointer().get<SILFunctionTypeInfo*>();
}
/// Returns the uncurry level of the type. Returns zero for non-function
/// types.
unsigned getUncurryLevel() const;
/// Returns the Swift return type of a function type at the right uncurry
/// level.
/// Returns the Swift return type of a function type.
/// The SILType must refer to a function type.
CanType getFunctionResultType() const {
auto *fty = castTo<AnyFunctionType>();
for (unsigned uncurry = 0; uncurry < getUncurryLevel(); ++uncurry) {
fty = fty->getResult()->castTo<AnyFunctionType>();
}
return CanType(fty->getResult());
}
@@ -266,8 +258,7 @@ class alignas(8) SILFunctionTypeInfo {
// for SILType.
CanType swiftType;
SILType resultType;
unsigned inputTypeCount;
unsigned uncurryCount : 31;
unsigned inputTypeCount : 31;
unsigned indirectReturn : 1;
SILType *getInputTypeBuffer() {
@@ -277,33 +268,20 @@ class alignas(8) SILFunctionTypeInfo {
return reinterpret_cast<SILType const *>(this+1);
}
unsigned *getUncurryBuffer() {
return reinterpret_cast<unsigned*>(getInputTypeBuffer() + inputTypeCount);
}
unsigned const *getUncurryBuffer() const {
return reinterpret_cast<unsigned const *>(
getInputTypeBuffer() + inputTypeCount);
}
SILFunctionTypeInfo(CanType swiftType,
unsigned inputTypeCount,
SILType resultType,
unsigned uncurryCount,
bool hasIndirectReturn)
: swiftType(swiftType),
resultType(resultType),
inputTypeCount(inputTypeCount),
uncurryCount(uncurryCount),
indirectReturn(hasIndirectReturn)
{
assert(uncurryCount >= 1 && "negative uncurry level?!");
}
{}
public:
static SILFunctionTypeInfo *create(CanType swiftType,
ArrayRef<SILType> inputTypes,
SILType resultType,
ArrayRef<unsigned> uncurriedInputCounts,
bool hasIndirectReturn,
SILModule &M);
@@ -329,16 +307,14 @@ public:
/// Get the indirect return argument type. Always an address.
SILType getIndirectReturnType() const {
assert(hasIndirectReturn() && "type doesn't have an indirect return?!");
return getInputTypes().back();
return getInputTypes().front();
}
/// Returns the list of input types, excluding the indirect return argument,
/// if any.
ArrayRef<SILType> getInputTypesWithoutIndirectReturnType() const {
auto inputs = getInputTypes();
return hasIndirectReturn()
? inputs.slice(0, inputs.size() - 1)
: inputs;
return hasIndirectReturn() ? inputs.slice(1) : inputs;
}
/// Returns the type of the return type or the indirect return slot if
@@ -346,49 +322,6 @@ public:
SILType getSemanticResultType() const {
return hasIndirectReturn() ? getIndirectReturnType() : getResultType();
}
/// Get the uncurry level of this type.
unsigned getUncurryLevel() const {
return uncurryCount - 1;
}
/// True if this function type can be curried with a CurryInst.
bool isUncurried() const {
return uncurryCount > 1;
}
/// Returns an ArrayRef containing the offset of the first SIL argument
/// used by each uncurry level of the function. For example, for a simple
/// function of type (Int, Int) -> Int, this will contain {0}. For a curried
/// function (Int, Int)(Int)(Int, (Int, Int)) -> Int, this will contain
/// {0, 2, 3}.
ArrayRef<unsigned> getUncurriedInputBegins() const {
return {getUncurryBuffer(), uncurryCount};
}
/// Returns an ArrayRef containing the offset of the last SIL argument
/// used by each uncurry level of the function. For example, for a simple
/// function of type (Int, Int) -> Int, this will contain {2}. For a curried
/// function (Int, Int)(Int)(Int, (Int, Int)) -> Int, this will contain
/// {2, 3, 6}.
ArrayRef<unsigned> getUncurriedInputEnds() const {
return {getUncurryBuffer()+1, uncurryCount};
}
/// Returns the list of input types needed to partially apply a function of
/// this function type with a CurryInst.
ArrayRef<SILType> getCurryInputTypes() const {
assert(isUncurried());
return {getInputTypeBuffer(), getUncurryBuffer()[uncurryCount-1]};
}
/// Returns the list of input types corresponding to an uncurry level.
ArrayRef<SILType> getInputTypesForCurryLevel(unsigned level) const {
assert(level < uncurryCount && "uncurry level out of range");
return getInputTypes().slice(
getUncurryBuffer()[level],
getUncurryBuffer()[level+1] - getUncurryBuffer()[level]);
}
};
inline CanType SILType::getSwiftRValueType() const {

View File

@@ -255,6 +255,9 @@ public:
OperandValueArrayRef slice(unsigned begin, unsigned length) const {
return OperandValueArrayRef(Operands.slice(begin, length));
}
OperandValueArrayRef slice(unsigned begin) const {
return OperandValueArrayRef(Operands.slice(begin));
}
};
/// An iterator over all uses of a ValueBase.

View File

@@ -169,6 +169,12 @@ public:
}
};
/// Argument order of uncurried functions.
enum class UncurryDirection {
LeftToRight,
RightToLeft
};
/// TypeConverter - helper class for creating and managing TypeLoweringInfos.
class TypeConverter {
llvm::BumpPtrAllocator TypeLoweringInfoBPA;
@@ -183,8 +189,7 @@ class TypeConverter {
const TypeLoweringInfo &makeTypeLoweringInfo(CanType t,
unsigned uncurryLevel);
SILFunctionTypeInfo *makeInfoForFunctionType(AnyFunctionType *ft,
unsigned uncurryLevel);
SILFunctionTypeInfo *makeInfoForFunctionType(AnyFunctionType *ft);
Type makeConstantType(SILConstant constant);
@@ -238,8 +243,11 @@ public:
GenericParamList *genericParams = nullptr) const;
/// Convert a nested function type into an uncurried representation.
static AnyFunctionType *uncurryFunctionType(AnyFunctionType *t,
unsigned uncurryLevel);
static AnyFunctionType *getUncurriedFunctionType(AnyFunctionType *t,
unsigned uncurryLevel);
/// Get the uncurried argument order for a calling convention.
static UncurryDirection getUncurryDirection(AbstractCC cc);
};
} // namespace Lowering

View File

@@ -75,7 +75,7 @@ private:
void externalizeArgument(Explosion &out, Explosion &in,
SmallVectorImpl<std::pair<unsigned, Alignment>> &newByvals,
CanType ty);
void externalizeArguments(Explosion &arg,
void externalizeArguments(Explosion &out, Explosion &in,
SmallVectorImpl<std::pair<unsigned, Alignment>> &newByvals,
CanType inputsTy);
llvm::CallSite emitInvoke(llvm::CallingConv::ID cc, llvm::Value *fn,

View File

@@ -158,13 +158,12 @@ namespace irgen {
ArrayRef<Substitution> subs,
llvm::Value *fn, llvm::Value *data,
ExplosionKind explosionLevel) {
SILFunctionTypeInfo *info = origSILType.getFunctionTypeInfo();
return forKnownFunction(origSILType.getFunctionCC(),
origSILType.getSwiftType(),
substResultType.getSwiftRValueType(),
subs,
fn, data, explosionLevel,
info->getUncurryLevel());
0);
}
/// Prepare a callee for a known function with a known data pointer.

View File

@@ -529,46 +529,13 @@ static CanType decomposeFunctionType(IRGenModule &IGM, CanType type,
SmallVectorImpl<llvm::Type*> &argTypes,
SmallVectorImpl<std::pair<unsigned, Alignment>> &byvals,
llvm::AttributeSet &attrs) {
// Ask SIL's TypeLowering to uncurry the function type.
type = CanType(Lowering::getThinFunctionType(type, cc));
auto fn = cast<AnyFunctionType>(type);
fn = Lowering::TypeConverter::getUncurriedFunctionType(fn, uncurryLevel);
// Save up the formal parameter types.
llvm::SmallVector<AnyFunctionType*, 8> formalFnTypes;
switch (cc) {
case AbstractCC::Freestanding:
case AbstractCC::Method:
formalFnTypes.resize(uncurryLevel+1);
// Save the parameter types in reverse order.
formalFnTypes[uncurryLevel] = fn;
while (uncurryLevel--) {
fn = cast<AnyFunctionType>(CanType(fn->getResult()));
formalFnTypes[uncurryLevel] = fn;
}
break;
case AbstractCC::ObjCMethod:
// An ObjC method should be at uncurry level one, with the first uncurried
// clause taking 'self' and the second taking the method arguments. The
// '_cmd' argument gets magicked in between.
assert(uncurryLevel == 1 && "objc method should be at uncurry level 1");
// self
decomposeFunctionArg(IGM, CanType(fn->getInput()), cc, explosionKind,
argTypes, byvals, attrs);
// _cmd
argTypes.push_back(IGM.Int8PtrTy);
fn = cast<AnyFunctionType>(CanType(fn->getResult()));
formalFnTypes.push_back(fn);
break;
case AbstractCC::C:
// C functions cannot be curried.
assert(uncurryLevel == 0 && "c function cannot be curried");
formalFnTypes.push_back(fn);
break;
}
// Explode the argument clusters.
for (AnyFunctionType *fnTy : formalFnTypes) {
CanType inputTy = CanType(fnTy->getInput());
// Explode the argument.
auto decomposeTopLevelArg = [&](CanType inputTy) {
if (TupleType *tupleTy = inputTy->getAs<TupleType>()) {
for (auto &field : tupleTy->getFields()) {
decomposeFunctionArg(IGM, CanType(field.getType()), cc, explosionKind,
@@ -578,10 +545,29 @@ static CanType decomposeFunctionType(IRGenModule &IGM, CanType type,
decomposeFunctionArg(IGM, inputTy, cc, explosionKind,
argTypes, byvals, attrs);
}
};
if (auto polyTy = dyn_cast<PolymorphicFunctionType>(fnTy))
expandPolymorphicSignature(IGM, polyTy, argTypes);
CanType inputTy = CanType(fn->getInput());
switch (cc) {
case AbstractCC::Freestanding:
case AbstractCC::Method:
case AbstractCC::C:
decomposeTopLevelArg(inputTy);
break;
case AbstractCC::ObjCMethod: {
// ObjC methods take an implicit _cmd argument after the self argument.
TupleType *inputTuple = cast<TupleType>(inputTy);
assert(inputTuple->getFields().size() == 2 && "invalid objc method type");
decomposeTopLevelArg(CanType(inputTuple->getFields()[0].getType()));
argTypes.push_back(IGM.Int8PtrTy);
decomposeTopLevelArg(CanType(inputTuple->getFields()[1].getType()));
break;
}
}
if (auto polyTy = dyn_cast<PolymorphicFunctionType>(fn))
expandPolymorphicSignature(IGM, polyTy, argTypes);
return CanType(fn->getResult());
}
@@ -683,9 +669,8 @@ IRGenModule::getFunctionType(SILType type, ExplosionKind explosionKind,
llvm::AttributeSet &attrs) {
assert(!type.isAddress());
assert(type.is<AnyFunctionType>());
SILFunctionTypeInfo *info = type.getFunctionTypeInfo();
return getFunctionType(type.getFunctionCC(), type.getSwiftType(),
explosionKind, info->getUncurryLevel(),
explosionKind, 0,
extraData, attrs);
}
@@ -1393,24 +1378,17 @@ void CallEmission::externalizeArgument(Explosion &out, Explosion &in,
}
/// Convert exploded Swift arguments into C-compatible arguments.
void CallEmission::externalizeArguments(Explosion &arg,
void CallEmission::externalizeArguments(Explosion &out, Explosion &arg,
SmallVectorImpl<std::pair<unsigned, Alignment>> &newByvals,
CanType inputsTy) {
Explosion externalized(arg.getKind());
if (TupleType *tupleTy = inputsTy->getAs<TupleType>()) {
for (auto &elt : tupleTy->getFields()) {
externalizeArgument(externalized, arg, newByvals,
externalizeArgument(out, arg, newByvals,
elt.getType()->getCanonicalType());
}
} else {
externalizeArgument(externalized, arg, newByvals, inputsTy);
externalizeArgument(out, arg, newByvals, inputsTy);
}
// Sometimes we get extra args such as the selector argument. Pass those
// through.
externalized.add(arg.claimAll());
arg = std::move(externalized);
}
/// Add a new set of arguments to the function.
@@ -1420,12 +1398,32 @@ void CallEmission::addArg(Explosion &arg) {
// Convert arguments to a representation appropriate to the calling
// convention.
switch (CurCallee.getConvention()) {
case AbstractCC::C:
case AbstractCC::ObjCMethod:
externalizeArguments(arg, newByvals,
CanType(CurOrigType->castTo<AnyFunctionType>()->getInput()));
AbstractCC cc = CurCallee.getConvention();
switch (cc) {
case AbstractCC::C: {
Explosion externalized(arg.getKind());
externalizeArguments(externalized, arg, newByvals,
CanType(CurOrigType->castTo<AnyFunctionType>()->getInput()));
arg = std::move(externalized);
break;
}
case AbstractCC::ObjCMethod: {
// The method will be uncurried to (Self, (Args...)). The _cmd argument
// goes in between.
Explosion externalized(arg.getKind());
// self
externalized.add(arg.claimNext());
// _cmd
externalized.add(arg.claimNext());
// method args
TupleType *inputTuple = CurOrigType->castTo<AnyFunctionType>()->getInput()
->castTo<TupleType>();
assert(inputTuple->getFields().size() == 2 && "invalid objc method type");
externalizeArguments(externalized, arg, newByvals,
CanType(inputTuple->getFields()[1].getType()));
arg = std::move(externalized);
break;
}
case AbstractCC::Freestanding:
case AbstractCC::Method:
// Nothing to do.
@@ -1776,18 +1774,6 @@ llvm::Function *irgen::emitFunctionSpecialization(IRGenModule &IGM,
IRGenFunction subIGF(IGM, explosionLevel, spec);
// Unravel the substituted function types for each uncurry level.
unsigned level = substType.getUncurryLevel();
llvm::SmallVector<FunctionType*, 4> uncurriedTypes;
FunctionType *uncurriedType = substType.castTo<FunctionType>();
for (;;) {
uncurriedTypes.push_back(uncurriedType);
if (level-- != 0)
uncurriedType = uncurriedType->getResult()->castTo<FunctionType>();
else
break;
}
Explosion params = subIGF.collectParameters();
// Collect the indirect return address, if present.
@@ -1799,17 +1785,6 @@ llvm::Function *irgen::emitFunctionSpecialization(IRGenModule &IGM,
if (schema.requiresIndirectResult())
indirectReturn = retTI.getAddressForPointer(params.claimNext());
// Collect the LLVM arguments from the thunk, in reverse curry level order.
llvm::SmallVector<Explosion, 2> paramLevels;
for (FunctionType *uncurriedType : reversed(uncurriedTypes)) {
TypeInfo const &argTI = IGM.getFragileTypeInfo(uncurriedType->getInput());
paramLevels.push_back(Explosion(explosionLevel));
argTI.reexplode(subIGF, params, paramLevels.back());
}
assert(params.empty() && "did not claim all parameters?!");
// Apply the arguments in a call to the generic function.
Callee callee = Callee::forKnownFunction(genericType,
retTy,
@@ -1818,12 +1793,9 @@ llvm::Function *irgen::emitFunctionSpecialization(IRGenModule &IGM,
nullptr,
explosionLevel);
CallEmission emission(subIGF, callee);
for (size_t i = 0; i < paramLevels.size(); ++i) {
Explosion &paramLevel = paramLevels.rbegin()[i];
FunctionType *uncurriedType = uncurriedTypes[i];
emission.addSubstitutedArg(CanType(uncurriedType->getInput()), paramLevel);
}
FunctionType *ft = substType.castTo<FunctionType>();
emission.addSubstitutedArg(CanType(ft->getInput()), params);
assert(params.empty() && "did not claim all parameters?!");
// Return the result of the call.
if (indirectReturn.isValid()) {

View File

@@ -427,7 +427,7 @@ CallEmission irgen::prepareObjCMethodRootCall(IRGenFunction &IGF,
auto fnTy = IGF.IGM.getFunctionType(AbstractCC::ObjCMethod,
origType.getSwiftRValueType(),
ExplosionKind::Minimal,
/*uncurryLevel*/ 1,
0,
ExtraData::None,
attrs);
bool indirectResult = requiresExternalIndirectResult(IGF.IGM,
@@ -466,15 +466,13 @@ CallEmission irgen::prepareObjCMethodRootCall(IRGenFunction &IGF,
/// Emit the 'self'/'super' and '_cmd' arguments for an ObjC method dispatch.
void irgen::addObjCMethodCallImplicitArguments(IRGenFunction &IGF,
CallEmission &emission,
Explosion &args,
SILConstant method,
llvm::Value *self,
SILType searchType) {
// Compute the selector.
Selector selector(method.getDecl());
Explosion args(ExplosionKind::Minimal);
// super.constructor references an instance method (even though the
// decl is really a 'static' member).
bool isInstanceMethod
@@ -505,9 +503,6 @@ void irgen::addObjCMethodCallImplicitArguments(IRGenFunction &IGF,
IGF.IGM.getPointerAlignment()));
}
args.add(selectorV);
// Add that to the emission.
emission.addArg(args);
}
/// Create the LLVM function declaration for a thunk that acts like

View File

@@ -47,7 +47,7 @@ namespace irgen {
bool isSuper);
void addObjCMethodCallImplicitArguments(IRGenFunction &IGF,
CallEmission &emission,
Explosion &emission,
SILConstant method,
llvm::Value *self,
SILType searchType);

View File

@@ -1759,11 +1759,12 @@ static llvm::Constant *getValueWitness(IRGenModule &IGM,
return asOpaquePtr(IGM, fn);
}
/// Look through any single-element labelled tuple types.
/// Look through any single-element labelled or curried tuple types.
/// FIXME: We could get fulfillments from any tuple element.
static CanType stripLabel(CanType input) {
if (auto tuple = dyn_cast<TupleType>(input))
if (tuple->getFields().size() == 1)
return stripLabel(CanType(tuple->getFields()[0].getType()));
if (tuple->getFields().size() > 0)
return stripLabel(CanType(tuple->getFields().back().getType()));
return input;
}

View File

@@ -164,25 +164,30 @@ emitPHINodesForBBArgs(IRGenSILFunction &IGF,
return phis;
}
static void emitEntryPointIndirectReturn(IRGenSILFunction &IGF,
static ArrayRef<SILArgument*> emitEntryPointIndirectReturn(
IRGenSILFunction &IGF,
SILBasicBlock *entry,
Explosion &params,
SILFunctionTypeInfo *funcTI,
std::function<bool()> requiresIndirectResult) {
// Map the indirect return if present.
if (funcTI->hasIndirectReturn()) {
SILArgument *ret = entry->bbarg_end()[-1];
SILArgument *ret = entry->bbarg_begin()[0];
SILValue retv(ret, 0);
TypeInfo const &retType = IGF.IGM.getFragileTypeInfo(ret->getType());
IGF.newLoweredAddress(retv, retType.getAddressForPointer(params.claimNext()));
IGF.newLoweredAddress(retv,
retType.getAddressForPointer(params.claimNext()));
return entry->getBBArgs().slice(1);
} else {
// Map an indirect return for a type SIL considers loadable but still
// requires an indirect return at the IR level.
if (requiresIndirectResult()) {
TypeInfo const &retType = IGF.IGM.getFragileTypeInfo(funcTI->getResultType());
TypeInfo const &retType
= IGF.IGM.getFragileTypeInfo(funcTI->getResultType());
IGF.IndirectReturn = retType.getAddressForPointer(params.claimNext());
}
return entry->getBBArgs();
}
}
@@ -195,54 +200,33 @@ static void emitEntryPointArgumentsNativeCC(IRGenSILFunction &IGF,
SILFunctionTypeInfo *funcTI = funcTy.getFunctionTypeInfo();
// Map the indirect return if present.
emitEntryPointIndirectReturn(IGF, entry, params, funcTI,
[&]() -> bool {
TypeInfo const &retType = IGF.IGM.getFragileTypeInfo(funcTI->getResultType());
ExplosionSchema schema = retType.getSchema(IGF.CurExplosionLevel);
ArrayRef<SILArgument*> args
= emitEntryPointIndirectReturn(IGF, entry, params, funcTI,
[&]() -> bool {
TypeInfo const &retType
= IGF.IGM.getFragileTypeInfo(funcTI->getResultType());
ExplosionSchema schema = retType.getSchema(IGF.CurExplosionLevel);
return schema.requiresIndirectResult();
});
return schema.requiresIndirectResult();
});
// Unravel the function types for each uncurry level.
unsigned level = funcTI->getUncurryLevel();
llvm::SmallVector<AnyFunctionType*, 4> uncurriedTypes;
AnyFunctionType *uncurriedType = funcTy.castTo<AnyFunctionType>();
for (;;) {
uncurriedTypes.push_back(uncurriedType);
if (level-- != 0)
uncurriedType = uncurriedType->getResult()->castTo<AnyFunctionType>();
else
break;
// Map the remaining SIL argument to LLVM arguments.
for (SILArgument *arg : args) {
SILValue argv(arg, 0);
TypeInfo const &argType = IGF.getFragileTypeInfo(arg->getType());
if (arg->getType().isAddress()) {
IGF.newLoweredAddress(argv,
argType.getAddressForPointer(params.claimNext()));
continue;
}
Explosion explosion(IGF.CurExplosionLevel);
argType.reexplode(IGF, params, explosion);
IGF.newLoweredExplosion(arg, explosion);
}
// Map LLVM arguments in inner-to-outer curry order to match the Swift
// convention.
level = funcTI->getUncurryLevel();
do {
unsigned from = funcTI->getUncurriedInputBegins()[level],
to = funcTI->getUncurriedInputEnds()[level];
for (auto argi = entry->bbarg_begin() + from,
argend = entry->bbarg_begin() + to;
argi != argend; ++argi) {
SILArgument *arg = *argi;
SILValue argv(arg, 0);
TypeInfo const &argType = IGF.getFragileTypeInfo(arg->getType());
if (arg->getType().isAddress()) {
IGF.newLoweredAddress(argv,
argType.getAddressForPointer(params.claimNext()));
continue;
}
Explosion explosion(IGF.CurExplosionLevel);
argType.reexplode(IGF, params, explosion);
IGF.newLoweredExplosion(arg, explosion);
}
// Bind polymorphic arguments for this uncurry level.
auto fn = uncurriedTypes.back();
uncurriedTypes.pop_back();
if (auto polyFn = dyn_cast<PolymorphicFunctionType>(fn))
emitPolymorphicParameters(IGF, polyFn, params);
} while (level-- != 0);
// Bind polymorphic arguments.
if (auto polyFn = funcTy.getAs<PolymorphicFunctionType>())
emitPolymorphicParameters(IGF, polyFn, params);
}
/// Emit entry point arguments for the parameters of a C function, or the
@@ -250,12 +234,8 @@ static void emitEntryPointArgumentsNativeCC(IRGenSILFunction &IGF,
static void emitEntryPointArgumentsCOrObjC(IRGenSILFunction &IGF,
SILBasicBlock *entry,
Explosion &params,
ArrayRef<SILType> inputTypes,
unsigned argOffset) {
for (SILType inputType : inputTypes) {
(void)inputType;
SILArgument *arg = entry->bbarg_begin()[argOffset++];
ArrayRef<SILArgument*> args) {
for (SILArgument *arg : args) {
TypeInfo const &argType = IGF.getFragileTypeInfo(arg->getType());
if (arg->getType().isAddress()) {
IGF.newLoweredAddress(arg,
@@ -279,39 +259,33 @@ static void emitEntryPointArgumentsCOrObjC(IRGenSILFunction &IGF,
/// Emit entry point arguments for a SILFunction with the ObjC method calling
/// convention.
static void emitEntryPointArgumentsObjCCC(IRGenSILFunction &IGF,
SILBasicBlock *entry,
Explosion &params,
SILType funcTy) {
/// convention. This convention inserts the '_cmd' objc_msgSend argument after
/// the first non-sret argument.
static void emitEntryPointArgumentsObjCMethodCC(IRGenSILFunction &IGF,
SILBasicBlock *entry,
Explosion &params,
SILType funcTy) {
SILFunctionTypeInfo *funcTI = funcTy.getFunctionTypeInfo();
// Map the indirect return if present.
emitEntryPointIndirectReturn(IGF, entry, params, funcTI, [&] {
return requiresExternalIndirectResult(IGF.IGM, funcTI->getResultType());
});
ArrayRef<SILArgument*> args
= emitEntryPointIndirectReturn(IGF, entry, params, funcTI, [&] {
return requiresExternalIndirectResult(IGF.IGM, funcTI->getResultType());
});
assert(funcTI->getUncurryLevel() == 1
&& "objc method should be at uncurry level 1");
// Map the self argument.
assert(funcTI->getInputTypesForCurryLevel(0).size() == 1
&& "should only have 'self' in first argument clause");
unsigned selfOffset = funcTI->getUncurriedInputBegins()[0];
SILArgument *selfArg = entry->bbarg_begin()[selfOffset];
// Map the self argument. This should always be an ObjC pointer type so
// should never need to be loaded from a byval.
SILArgument *selfArg = args[0];
TypeInfo const &selfType = IGF.getFragileTypeInfo(selfArg->getType());
Explosion self(IGF.CurExplosionLevel);
selfType.reexplode(IGF, params, self);
IGF.newLoweredExplosion(selfArg, self);
// Discard the _cmd argument.
// Discard the implicit _cmd argument.
params.claimNext();
ArrayRef<SILType> inputTypes = funcTI->getInputTypesForCurryLevel(1);
unsigned argOffset = funcTI->getUncurriedInputBegins()[1];
emitEntryPointArgumentsCOrObjC(IGF, entry, params,
inputTypes, argOffset);
// Map the rest of the arguments as in the C calling convention.
emitEntryPointArgumentsCOrObjC(IGF, entry, params, args.slice(1));
}
/// Emit entry point arguments for a SILFunction with the C calling
@@ -323,14 +297,11 @@ static void emitEntryPointArgumentsCCC(IRGenSILFunction &IGF,
SILFunctionTypeInfo *funcTI = funcTy.getFunctionTypeInfo();
// Map the indirect return if present.
emitEntryPointIndirectReturn(IGF, entry, params, funcTI, [&] {
return requiresExternalIndirectResult(IGF.IGM, funcTI->getResultType());
});
ArrayRef<SILType> inputTypes = funcTI->getInputTypesForCurryLevel(0);
unsigned argOffset = funcTI->getUncurriedInputBegins()[0];
emitEntryPointArgumentsCOrObjC(IGF, entry, params, inputTypes, argOffset);
ArrayRef<SILArgument*> args
= emitEntryPointIndirectReturn(IGF, entry, params, funcTI, [&] {
return requiresExternalIndirectResult(IGF.IGM, funcTI->getResultType());
});
emitEntryPointArgumentsCOrObjC(IGF, entry, params, args);
}
void IRGenSILFunction::emitSILFunction() {
@@ -366,7 +337,7 @@ void IRGenSILFunction::emitSILFunction() {
emitEntryPointArgumentsNativeCC(*this, entry->first, params, funcTy);
break;
case AbstractCC::ObjCMethod:
emitEntryPointArgumentsObjCCC(*this, entry->first, params, funcTy);
emitEntryPointArgumentsObjCMethodCC(*this, entry->first, params, funcTy);
break;
case AbstractCC::C:
emitEntryPointArgumentsCCC(*this, entry->first, params, funcTy);
@@ -755,29 +726,27 @@ void IRGenSILFunction::visitApplyInst(swift::ApplyInst *i) {
builtin.getSubstitutions());
}
SILType resultTy = i->getCallee().getType().getFunctionTypeInfo()
->getSemanticResultType();
SILType calleeTy = i->getCallee().getType();
SILType resultTy = calleeTy.getFunctionTypeInfo()->getSemanticResultType();
CallEmission emission = getCallEmissionForLoweredValue(*this,
i->getCallee().getType(),
resultTy, calleeLV);
SILFunctionTypeInfo *ti
= i->getCallee().getType().getFunctionTypeInfo();
// Lower the SIL arguments to IR arguments.
Explosion llArgs(CurExplosionLevel);
// Lower the SIL arguments to IR arguments, and pass them to the CallEmission
// one curry at a time. CallEmission will arrange the curries in the proper
// order for the callee.
unsigned arg = 0;
auto uncurriedInputEnds = ti->getUncurriedInputEnds();
// Save off the indirect return argument, if any.
OperandValueArrayRef args = i->getArgumentsWithoutIndirectReturn();
SILValue indirectReturn;
if (i->hasIndirectReturn()) {
indirectReturn = i->getIndirectReturn();
}
// ObjC message sends need special handling for the 'this' argument. It may
// need to be wrapped in an objc_super struct, and the '_cmd' argument needs
// to be passed alongside it.
if (calleeLV.kind == LoweredValue::Kind::ObjCMethod) {
assert(uncurriedInputEnds[0] == 1 &&
"more than one this argument for an objc call?!");
SILValue thisValue = i->getArguments()[0];
llvm::Value *selfArg;
// Convert a metatype 'this' argument to the ObjC Class pointer.
@@ -789,32 +758,22 @@ void IRGenSILFunction::visitApplyInst(swift::ApplyInst *i) {
selfArg = selfExplosion.claimNext();
}
addObjCMethodCallImplicitArguments(*this, emission,
addObjCMethodCallImplicitArguments(*this, llArgs,
calleeLV.getObjCMethod().getMethod(),
selfArg,
calleeLV.getObjCMethod().getSuperSearchType());
arg = 1;
uncurriedInputEnds = uncurriedInputEnds.slice(1);
args = args.slice(1);
}
AnyFunctionType *calleeTy = i->getCallee().getType().castTo<AnyFunctionType>();
interleave(uncurriedInputEnds.begin(), uncurriedInputEnds.end(),
[&](unsigned inputCount) {
Explosion curryArgs(CurExplosionLevel);
for (; arg < inputCount; ++arg) {
emitApplyArgument(*this, curryArgs, i->getArguments()[arg]);
}
emission.addSubstitutedArg(CanType(calleeTy->getInput()),
curryArgs);
},
[&] {
calleeTy = calleeTy->getResult()->castTo<AnyFunctionType>();
});
for (SILValue arg : args)
emitApplyArgument(*this, llArgs, arg);
emission.addSubstitutedArg(CanType(calleeTy.castTo<FunctionType>()->getInput()),
llArgs);
// If the function takes an indirect return argument, emit into it.
if (i->hasIndirectReturn()) {
SILValue indirectReturn = i->getIndirectReturn();
if (indirectReturn) {
Address a = getLoweredAddress(indirectReturn);
TypeInfo const &ti = getFragileTypeInfo(indirectReturn.getType());
emission.emitToMemory(a, ti);
@@ -862,29 +821,19 @@ void IRGenSILFunction::visitPartialApplyInst(swift::PartialApplyInst *i) {
// specialized
assert(i->getCallee().getType().castTo<FunctionType>()->isThin() &&
"can't closure a function that already has context");
assert(i->getCallee().getType().getUncurryLevel() >= 1 &&
"can't closure a function that isn't uncurried");
unsigned uncurryLevel = i->getCallee().getType().getUncurryLevel();
SILFunctionTypeInfo *ti
= i->getCallee().getType().getFunctionTypeInfo();
Explosion args(CurExplosionLevel);
Explosion llArgs(CurExplosionLevel);
SmallVector<SILType, 8> argTypes;
while (uncurryLevel-- != 0) {
unsigned from = ti->getUncurriedInputBegins()[uncurryLevel],
to = ti->getUncurriedInputEnds()[uncurryLevel];
for (SILValue arg : i->getArguments().slice(from, to - from)) {
emitApplyArgument(*this, args, arg);
// FIXME: Need to carry the address-ness of each argument alongside
// the object type's TypeInfo.
argTypes.push_back(arg.getType());
}
for (SILValue arg : i->getArguments()) {
emitApplyArgument(*this, llArgs, arg);
// FIXME: Need to carry the address-ness of each argument alongside
// the object type's TypeInfo.
argTypes.push_back(arg.getType());
}
// Create the thunk and function value.
Explosion function(CurExplosionLevel);
emitFunctionPartialApplication(*this, calleeFn, args, argTypes,
emitFunctionPartialApplication(*this, calleeFn, llArgs, argTypes,
i->getType(), function);
newLoweredExplosion(v, function);
}

View File

@@ -64,6 +64,8 @@ private:
SILFunctionTypeInfo *ft);
public:
OwnershipConventions() = default;
/// Derive the ownership conventions for a SILConstant.
static OwnershipConventions get(SILGenFunction &gen,
SILConstant c,

View File

@@ -585,12 +585,6 @@ public:
LValue const &dest);
ManagedValue emitMaterializedLoadFromLValue(SILLocation loc,
LValue const &src);
ManagedValue emitSpecializedPropertyFunctionRef(
SILLocation loc,
SILConstant constant,
ArrayRef<Substitution> substitutions,
Type substPropertyType);
ManagedValue emitMethodRef(SILLocation loc,
SILValue thisValue,
SILConstant methodConstant,

View File

@@ -13,6 +13,7 @@
#include "SILGen.h"
#include "OwnershipConventions.h"
#include "RValue.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Builtins.h"
#include "swift/AST/Module.h"
#include "swift/Basic/Range.h"
@@ -29,12 +30,24 @@ class CallEmission;
class Callee {
public:
enum class Kind {
/// A generic SIL value.
/// FIXME: We should use more specific kinds so we can emit curried calls
/// to methods.
GenericValue,
/// A standalone function, referenceable by a FunctionRefInst.
/// An indirect function value.
IndirectValue,
/// A direct standalone function call, referenceable by a FunctionRefInst.
StandaloneFunction,
VirtualMethod_First,
/// A method call using class method dispatch.
ClassMethod = VirtualMethod_First,
/// A method call using super method dispatch.
SuperMethod,
VirtualMethod_Last = SuperMethod,
GenericMethod_First,
/// A method call using archetype dispatch.
ArchetypeMethod = GenericMethod_First,
/// A method call using protocol dispatch.
ProtocolMethod,
GenericMethod_Last = ProtocolMethod
};
const Kind kind;
@@ -50,35 +63,136 @@ public:
Callee &operator=(const Callee &) = delete;
private:
union {
ManagedValue genericValue;
ManagedValue indirectValue;
SILConstant standaloneFunction;
struct {
SILValue thisValue;
SILConstant methodName;
} method;
struct {
SILValue thisValue;
SILConstant methodName;
CanType origType;
} genericMethod;
};
std::vector<Substitution> substitutions;
SILType specializedType;
SpecializeExpr *specializeLoc = nullptr;
OwnershipConventions ownership;
// There is an initialization order dependency between genericMethod and
// specializedType.
CanType specializedType;
SILLocation specializeLoc;
static SpecializedEmitter getSpecializedEmitterForSILBuiltin(SILConstant c);
public:
Callee(ManagedValue genericValue, OwnershipConventions &&ownership)
: kind(Kind::GenericValue), genericValue(genericValue),
specializedType(genericValue.getType()),
ownership(std::move(ownership))
Callee(ManagedValue indirectValue)
: kind(Kind::IndirectValue),
indirectValue(indirectValue),
specializedType(indirectValue.getType().getSwiftRValueType())
{}
Callee(SILGenFunction &gen, SILConstant standaloneFunction)
: kind(Kind::StandaloneFunction), standaloneFunction(standaloneFunction),
specializedType(gen.SGM.getConstantType(standaloneFunction)),
ownership(OwnershipConventions::get(gen, standaloneFunction,
specializedType))
specializedType(
gen.SGM.getConstantType(standaloneFunction.atUncurryLevel(0))
.getSwiftRValueType())
{}
Callee(Kind methodKind,
SILGenFunction &gen,
SILValue thisValue,
SILConstant methodName)
: kind(methodKind), method{thisValue, methodName},
specializedType(
gen.SGM.getConstantType(methodName.atUncurryLevel(0))
.getSwiftRValueType())
{
assert(kind >= Kind::VirtualMethod_First &&
kind <= Kind::VirtualMethod_Last &&
"this constructor is only used for class/super method callees");
}
static const enum class ForArchetype_t {} ForArchetype{};
static const enum class ForProtocol_t {} ForProtocol{};
Callee(ForArchetype_t,
SILGenFunction &gen,
SILValue archetype, SILConstant methodName, Type memberType)
: kind(Kind::ArchetypeMethod),
genericMethod{archetype, methodName,
FunctionType::get(archetype.getType().getSwiftType(),
memberType,
/*isAutoClosure*/ false,
/*isBlock*/ false,
/*isThin*/ false,
gen.SGM.getConstantCC(methodName),
memberType->getASTContext())
->getCanonicalType()},
specializedType(genericMethod.origType)
{
}
static CanType getProtocolMethodType(SILGenFunction &gen,
SILValue proto,
SILConstant methodName,
Type memberType) {
// 'this' for instance methods is projected out of the existential container
// as an OpaquePointer.
// 'this' for existential metatypes is the metatype itself.
Type thisTy = methodName.getDecl()->isInstanceMember()
? memberType->getASTContext().TheOpaquePointerType
: proto.getType().getSwiftType();
// This is a method reference. Extract the method implementation from the
// archetype and apply the "this" argument.
return FunctionType::get(thisTy,
memberType,
/*isAutoClosure*/ false,
/*isBlock*/ false,
/*isThin*/ false,
gen.SGM.getConstantCC(methodName),
memberType->getASTContext())
->getCanonicalType();
}
Callee(ForProtocol_t,
SILGenFunction &gen,
SILValue proto, SILConstant methodName, Type memberType)
: kind(Kind::ProtocolMethod),
genericMethod{proto, methodName,
getProtocolMethodType(gen, proto, methodName, memberType)},
specializedType(genericMethod.origType)
{}
public:
static Callee forIndirect(ManagedValue indirectValue) {
return Callee(indirectValue);
}
static Callee forDirect(SILGenFunction &gen, SILConstant c) {
return Callee(gen, c);
}
static Callee forClassMethod(SILGenFunction &gen, SILValue thisValue,
SILConstant name) {
return Callee(Kind::ClassMethod, gen, thisValue, name);
}
static Callee forSuperMethod(SILGenFunction &gen, SILValue thisValue,
SILConstant name) {
return Callee(Kind::SuperMethod, gen, thisValue, name);
}
static Callee forArchetype(SILGenFunction &gen, SILValue archetypeValue,
SILConstant name, Type memberType) {
return Callee(ForArchetype, gen, archetypeValue, name, memberType);
}
static Callee forProtocol(SILGenFunction &gen, SILValue proto,
SILConstant name, Type memberType) {
return Callee(ForProtocol, gen, proto, name, memberType);
}
Callee(Callee &&) = default;
Callee &operator=(Callee &&) = default;
void addSubstitutions(SILGenFunction &gen,
SpecializeExpr *e,
SILLocation loc,
ArrayRef<Substitution> newSubs,
CanType subType,
unsigned callDepth) {
// Currently generic methods of generic types are the deepest we should
// be able to stack specializations.
@@ -86,76 +200,164 @@ public:
// depth.
assert(callDepth < 2 && "specialization below 'this' or argument depth?!");
substitutions.insert(substitutions.end(),
e->getSubstitutions().begin(),
e->getSubstitutions().end());
newSubs.begin(),
newSubs.end());
// Save the type of the SpecializeExpr at the right depth in the type.
assert(specializedType.getUncurryLevel() >= callDepth
assert(getNaturalUncurryLevel() >= callDepth
&& "specializations below uncurry level?!");
AbstractCC cc = specializedType.getFunctionCC();
AbstractCC cc = cast<AnyFunctionType>(specializedType)->getCC();
if (callDepth == 0) {
specializedType = gen.getLoweredLoadableType(
getThinFunctionType(e->getType(),
cc),
specializedType.getUncurryLevel());
specializedType = getThinFunctionType(subType, cc)
->getCanonicalType();
} else {
FunctionType *ft = specializedType.castTo<FunctionType>();
FunctionType *ft = cast<FunctionType>(specializedType);
Type outerInput = ft->getInput();
Type newSpecialized = FunctionType::get(outerInput,
e->getType(),
/*isAutoClosure*/ false,
/*isBlock*/ false,
/*isThin*/ true,
cc,
outerInput->getASTContext());
specializedType = gen.getLoweredLoadableType(newSpecialized,
specializedType.getUncurryLevel());
specializedType = CanType(FunctionType::get(outerInput,
subType,
/*isAutoClosure*/ false,
/*isBlock*/ false,
/*isThin*/ true,
cc,
outerInput->getASTContext()));
}
specializeLoc = e;
specializeLoc = loc;
}
// Recalculate the ownership conventions because the substitutions may
// have changed the function signature.
// FIXME: Currently only native methods can be specialized, so always use
// default ownership semantics.
ownership = OwnershipConventions::getDefault(specializedType);
void addSubstitutions(SILGenFunction &gen,
SpecializeExpr *e,
unsigned callDepth) {
addSubstitutions(gen, e, e->getSubstitutions(),
e->getType()->getCanonicalType(), callDepth);
}
unsigned getNaturalUncurryLevel() const {
return specializedType.getUncurryLevel();
switch (kind) {
case Kind::IndirectValue:
return 0;
case Kind::StandaloneFunction:
return standaloneFunction.uncurryLevel;
case Kind::ClassMethod:
case Kind::SuperMethod:
case Kind::ArchetypeMethod:
case Kind::ProtocolMethod:
return method.methodName.uncurryLevel;
}
}
ManagedValue getAtUncurryLevel(SILGenFunction &gen, unsigned level) const {
std::pair<ManagedValue, OwnershipConventions>
getAtUncurryLevel(SILGenFunction &gen, unsigned level) const {
ManagedValue mv;
OwnershipConventions ownership;
/// Get the SILConstant for a method at an uncurry level, and store its
/// ownership conventions into the 'ownership' local variable.
auto getMethodAndSetOwnership = [&]() -> SILConstant {
assert(level >= 1
&& "currying 'this' of dynamic method dispatch not yet supported");
assert(level <= method.methodName.uncurryLevel
&& "uncurrying past natural uncurry level of method");
SILConstant c = method.methodName.atUncurryLevel(level);
ownership = OwnershipConventions::get(gen, c, gen.SGM.getConstantType(c));
return c;
};
switch (kind) {
case Kind::GenericValue:
assert(level == genericValue.getType().getUncurryLevel()
&& "currying non-standalone function not yet supported");
mv = genericValue;
case Kind::IndirectValue:
assert(level == 0 && "can't curry indirect function");
mv = indirectValue;
ownership = OwnershipConventions::getDefault(mv.getType());
break;
case Kind::StandaloneFunction: {
assert(level <= standaloneFunction.uncurryLevel
&& "currying past natural uncurry level of standalone function");
&& "uncurrying past natural uncurry level of standalone function");
SILConstant constant = standaloneFunction.atUncurryLevel(level);
SILValue ref = gen.emitGlobalFunctionRef(SILLocation(), constant);
mv = ManagedValue(ref, ManagedValue::Unmanaged);
ownership = OwnershipConventions::get(gen, constant, ref.getType());
break;
}
};
case Kind::ClassMethod: {
SILConstant constant = getMethodAndSetOwnership();
SILValue classMethod = gen.B.createClassMethod(SILLocation(),
method.thisValue,
constant,
gen.SGM.getConstantType(constant));
mv = ManagedValue(classMethod, ManagedValue::Unmanaged);
break;
}
case Kind::SuperMethod: {
SILConstant constant = getMethodAndSetOwnership();
SILValue superMethod = gen.B.createSuperMethod(SILLocation(),
method.thisValue,
constant,
gen.SGM.getConstantType(constant));
mv = ManagedValue(superMethod, ManagedValue::Unmanaged);
break;
}
case Kind::ArchetypeMethod: {
assert(level >= 1
&& "currying 'this' of dynamic method dispatch not yet supported");
assert(level <= method.methodName.uncurryLevel
&& "uncurrying past natural uncurry level of method");
SILConstant constant = genericMethod.methodName.atUncurryLevel(level);
CanType archetypeType
= genericMethod.thisValue.getType().getSwiftRValueType();
if (auto *metatype = dyn_cast<MetaTypeType>(archetypeType))
archetypeType = CanType(metatype->getInstanceType());
SILValue method = gen.B.createArchetypeMethod(SILLocation(),
gen.getLoweredType(archetypeType),
constant,
gen.getLoweredType(genericMethod.origType, level));
mv = ManagedValue(method, ManagedValue::Unmanaged);
// FIXME: We currently assume all archetype methods have native ownership
// semantics.
ownership = OwnershipConventions::getDefault(method.getType());
break;
}
case Kind::ProtocolMethod: {
assert(level >= 1
&& "currying 'this' of dynamic method dispatch not yet supported");
assert(level <= method.methodName.uncurryLevel
&& "uncurrying past natural uncurry level of method");
SILConstant constant = genericMethod.methodName.atUncurryLevel(level);
SILValue method = gen.B.createProtocolMethod(SILLocation(),
genericMethod.thisValue,
constant,
gen.getLoweredType(genericMethod.origType, level));
mv = ManagedValue(method, ManagedValue::Unmanaged);
// FIXME: We currently assume all protocol methods have native ownership
// semantics.
ownership = OwnershipConventions::getDefault(method.getType());
break;
}
}
// If the callee needs to be specialized, do so.
if (specializeLoc) {
SILType specializedUncurriedType
= gen.getLoweredLoadableType(specializedType, level);
CleanupsDepth cleanup = mv.getCleanup();
SILValue spec = gen.B.createSpecialize(specializeLoc, mv.getValue(),
substitutions, specializedType);
substitutions,
specializedUncurriedType);
mv = ManagedValue(spec, cleanup);
// Recalculate the ownership conventions because the substitutions may
// have changed the function signature.
// FIXME: Currently only native methods can be specialized, so always use
// default ownership semantics.
ownership = OwnershipConventions::getDefault(specializedUncurriedType);
}
return mv;
}
OwnershipConventions const &getOwnershipConventions() const {
// FIXME: May need to adjust ownership conventions with uncurry level?
return ownership;
return {mv, ownership};
}
ArrayRef<Substitution> getSubstitutions() const {
@@ -176,10 +378,13 @@ public:
= getSpecializedEmitterForSILBuiltin(standaloneFunction))
return e;
}
case Kind::GenericValue:
break;
case Kind::IndirectValue:
case Kind::ClassMethod:
case Kind::SuperMethod:
case Kind::ArchetypeMethod:
case Kind::ProtocolMethod:
return nullptr;
}
return nullptr;
}
};
@@ -202,18 +407,11 @@ public:
: gen(gen), sideEffect(nullptr), callDepth(0)
{}
void setCallee(ManagedValue theCallee, OwnershipConventions &&ownership) {
void setCallee(Callee &&c) {
assert((thisParam ? callDepth == 1 : callDepth == 0)
&& "setting callee at non-zero call depth?!");
assert(!callee && "already set callee!");
callee.emplace(theCallee, std::move(ownership));
}
void setCallee(SILConstant standaloneCallee) {
assert((thisParam ? callDepth == 1 : callDepth == 0)
&& "setting callee at non-zero call depth?!");
assert(!callee && "already set callee!");
callee.emplace(gen, standaloneCallee);
callee.emplace(std::move(c));
}
void setSideEffect(Expr *sideEffectExpr) {
@@ -230,7 +428,7 @@ public:
/// Fall back to an unknown, indirect callee.
void visitExpr(Expr *e) {
ManagedValue fn = gen.visit(e).getAsSingleValue(gen);
setCallee(fn, OwnershipConventions::getDefault(fn.getType()));
setCallee(Callee::forIndirect(fn));
}
/// Add a call site to the curry.
@@ -268,13 +466,9 @@ public:
SILConstant::ConstructAtNaturalUncurryLevel,
gen.SGM.requiresObjCDispatch(fd));
SILValue classMethod = gen.B.createClassMethod(thisCallSite,
thisParam.peekScalarValue(),
constant,
gen.SGM.getConstantType(constant));
setCallee(ManagedValue(classMethod, ManagedValue::Unmanaged),
OwnershipConventions::get(gen, constant,
classMethod.getType()));
setCallee(Callee::forClassMethod(gen, thisParam.peekScalarValue(),
constant));
// setThisParam bumps the callDepth, but we aren't really past the
// 'this' call depth in this case.
--callDepth;
@@ -291,15 +485,15 @@ public:
// Obtain a reference for a local closure.
if (gen.LocalConstants.count(constant)) {
ManagedValue localFn = gen.emitReferenceToDecl(e, e->getDecl());
setCallee(localFn,
OwnershipConventions::getDefault(localFn.getType()));
setCallee(Callee::forIndirect(localFn));
}
// Otherwise, stash the SILConstant.
else
setCallee(constant);
setCallee(Callee::forDirect(gen, constant));
}
void visitOtherConstructorDeclRefExpr(OtherConstructorDeclRefExpr *e) {
setCallee(SILConstant(e->getDecl(), SILConstant::Kind::Initializer));
setCallee(Callee::forDirect(gen,
SILConstant(e->getDecl(), SILConstant::Kind::Initializer)));
}
void visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *e) {
setSideEffect(e->getLHS());
@@ -323,18 +517,20 @@ public:
setThisParam(RValue(gen, existential));
}
ManagedValue protoMethod(gen.emitProtocolMethod(e, existential.getValue()),
ManagedValue::Unmanaged);
setCallee(protoMethod,
OwnershipConventions::getDefault(protoMethod.getType()));
auto *fd = dyn_cast<FuncDecl>(e->getDecl());
assert(fd && "existential properties not yet supported");
setCallee(Callee::forProtocol(gen, existential.getValue(),
SILConstant(fd), e->getType()));
}
void visitArchetypeMemberRefExpr(ArchetypeMemberRefExpr *e) {
setThisParam(gen.visit(e->getBase()));
ManagedValue archeMethod(
gen.emitArchetypeMethod(e, thisParam.peekScalarValue()),
ManagedValue::Unmanaged);
setCallee(archeMethod,
OwnershipConventions::getDefault(archeMethod.getType()));
auto *fd = dyn_cast<FuncDecl>(e->getDecl());
assert(fd && "archetype properties not yet supported");
setCallee(Callee::forArchetype(gen, thisParam.peekScalarValue(),
SILConstant(fd), e->getType()));
}
void visitFunctionConversionExpr(FunctionConversionExpr *e) {
visit(e->getSubExpr());
@@ -377,26 +573,21 @@ public:
llvm_unreachable("invalid super callee");
// Upcast 'this' parameter to the super type.
SILType constantTy = gen.SGM.getConstantType(constant);
SILType constantThisTy
= gen.getLoweredLoadableType(constantTy.castTo<FunctionType>()->getInput());
SILType superTy
= gen.getLoweredLoadableType(apply->getArg()->getType()->getRValueType());
SILValue superUpcast = gen.B.createUpcast(apply->getArg(), super.getValue(),
constantThisTy);
superTy);
setThisParam(RValue(gen, ManagedValue(superUpcast, super.getCleanup())));
SILValue superMethod;
if (constant.isObjC) {
// ObjC super calls require dynamic dispatch.
superMethod = gen.B.createSuperMethod(apply, super.getValue(),
constant, constantTy);
setCallee(Callee::forSuperMethod(gen, super.getValue(), constant));
} else {
// Native Swift super calls are direct.
superMethod = gen.emitGlobalFunctionRef(apply, constant);
setCallee(Callee::forDirect(gen, constant));
}
setCallee(ManagedValue(superMethod, ManagedValue::Unmanaged),
OwnershipConventions::get(gen, constant,
superMethod.getType()));
}
Callee getCallee() {
@@ -422,56 +613,58 @@ ManagedValue SILGenFunction::emitApply(SILLocation Loc,
// Get the result type.
Type resultTy = Fn.getType().getFunctionResultType();
const TypeLoweringInfo &resultTI = getTypeLoweringInfo(resultTy);
SILType instructionTy = resultTI.getLoweredType();
// Get the callee value.
SILValue fnValue = Ownership.isCalleeConsumed()
? Fn.forward(*this)
: Fn.getValue();
// Gather the arguments.
SmallVector<SILValue, 4> argValues;
// Prepare a buffer for an indirect return if needed.
SILValue indirectReturn;
if (resultTI.isAddressOnly(F.getModule())) {
indirectReturn = getBufferForExprResult(Loc, resultTI.getLoweredType(), C);
instructionTy = SGM.Types.getEmptyTupleType();
argValues.push_back(indirectReturn);
}
// Gather the arguments.
for (size_t i = 0; i < Args.size(); ++i)
argValues.push_back(
forwardIfConsumed(Args[i], Ownership.isArgumentConsumed(i)));
if (resultTI.isAddressOnly(F.getModule())) {
// Allocate a temporary to house the indirect return, and pass it to the
// function as an implicit argument.
SILValue buffer = getBufferForExprResult(Loc, resultTI.getLoweredType(), C);
argValues.push_back(buffer);
B.createApply(Loc, fnValue, SGM.Types.getEmptyTupleType(),
argValues);
SILValue result = B.createApply(Loc, fnValue, instructionTy, argValues);
if (indirectReturn) {
/// FIXME: Can ObjC/C functions return types SIL considers address-only?
/// Do we need to copy here if the return value is Unretained?
return emitManagedRValueWithCleanup(buffer);
} else {
// Receive the result by value.
SILValue result = B.createApply(Loc, fnValue,
resultTI.getLoweredType(),
argValues);
// Take ownership of the return value, if necessary.
switch (Ownership.getReturn()) {
case OwnershipConventions::Return::Retained:
// Already retained.
break;
case OwnershipConventions::Return::Autoreleased:
// Autoreleased. Retain using retain_autoreleased.
B.createRetainAutoreleased(Loc, result);
break;
case OwnershipConventions::Return::Unretained:
// Unretained. Retain the value.
emitRetainRValue(Loc, result);
break;
}
return resultTy->is<LValueType>()
? ManagedValue(result, ManagedValue::LValue)
: emitManagedRValueWithCleanup(result);
assert(Ownership.getReturn() == OwnershipConventions::Return::Retained
&& "address-only result with non-Retained ownership not implemented");
return emitManagedRValueWithCleanup(indirectReturn);
}
// Take ownership of the return value, if necessary.
switch (Ownership.getReturn()) {
case OwnershipConventions::Return::Retained:
// Already retained.
break;
case OwnershipConventions::Return::Autoreleased:
// Autoreleased. Retain using retain_autoreleased.
B.createRetainAutoreleased(Loc, result);
break;
case OwnershipConventions::Return::Unretained:
// Unretained. Retain the value.
emitRetainRValue(Loc, result);
break;
}
return resultTy->is<LValueType>()
? ManagedValue(result, ManagedValue::LValue)
: emitManagedRValueWithCleanup(result);
}
namespace {
@@ -585,17 +778,38 @@ namespace {
= callee.getSpecializedEmitter(uncurryLevel);
ManagedValue calleeValue;
if (!specializedEmitter)
calleeValue = callee.getAtUncurryLevel(gen, uncurryLevel);
OwnershipConventions ownership;
auto cc = AbstractCC::Freestanding;
if (!specializedEmitter) {
std::tie(calleeValue, ownership)
= callee.getAtUncurryLevel(gen, uncurryLevel);
cc = calleeValue.getType().getFunctionCC();
}
// Collect the arguments to the uncurried call.
SmallVector<ManagedValue, 4> args;
SmallVector<SmallVector<ManagedValue, 4>, 2> args;
SILLocation uncurriedLoc;
for (auto &site : uncurriedSites) {
uncurriedLoc = site.loc;
std::move(site).emit(gen, args);
args.push_back({});
std::move(site).emit(gen, args.back());
}
// Uncurry the arguments in calling convention order.
SmallVector<ManagedValue, 4> uncurriedArgs;
UncurryDirection direction = gen.SGM.Types.getUncurryDirection(cc);
switch (direction) {
case UncurryDirection::LeftToRight:
for (auto &argSet : args)
uncurriedArgs.append(argSet.begin(), argSet.end());
break;
case UncurryDirection::RightToLeft:
for (auto &argSet : reversed(args))
uncurriedArgs.append(argSet.begin(), argSet.end());
break;
}
args = {};
// We use the context emit-into initialization only for the outermost
// call.
SGFContext uncurriedContext = extraSites.empty() ? C : SGFContext();
@@ -607,22 +821,19 @@ namespace {
result = specializedEmitter(gen,
uncurriedLoc,
callee.getSubstitutions(),
args,
uncurriedArgs,
uncurriedContext);
else
result = gen.emitApply(uncurriedLoc, calleeValue, args,
callee.getOwnershipConventions(),
uncurriedContext);
result = gen.emitApply(uncurriedLoc, calleeValue, uncurriedArgs,
ownership, uncurriedContext);
// If there are remaining call sites, apply them to the result function.
for (unsigned i = 0, size = extraSites.size(); i < size; ++i) {
args.clear();
uncurriedArgs.clear();
SILLocation loc = extraSites[i].loc;
std::move(extraSites[i]).emit(gen, args);
std::move(extraSites[i]).emit(gen, uncurriedArgs);
SGFContext context = i == size - 1 ? C : SGFContext();
result = gen.emitApply(loc, result, args,
callee.getOwnershipConventions(),
context);
result = gen.emitApply(loc, result, uncurriedArgs, ownership, context);
}
return result;
@@ -969,7 +1180,7 @@ ManagedValue SILGenFunction::emitArrayInjectionCall(ManagedValue ObjectPtr,
return emission.apply();
}
ManagedValue SILGenFunction::emitSpecializedPropertyFunctionRef(
Callee emitSpecializedPropertyFunctionRef(SILGenFunction &gen,
SILLocation loc,
SILConstant constant,
ArrayRef<Substitution> substitutions,
@@ -977,33 +1188,28 @@ ManagedValue SILGenFunction::emitSpecializedPropertyFunctionRef(
{
// If the accessor is a local constant, use it.
// FIXME: Can local properties ever be generic?
if (LocalConstants.count(constant)) {
SILValue v = LocalConstants[constant];
emitRetainRValue(loc, v);
return emitManagedRValueWithCleanup(v);
if (gen.LocalConstants.count(constant)) {
SILValue v = gen.LocalConstants[constant];
gen.emitRetainRValue(loc, v);
return Callee::forIndirect(gen.emitManagedRValueWithCleanup(v));
}
// Get the accessor function. The type will be a polymorphic function if
// the This type is generic.
SILValue method = emitGlobalFunctionRef(loc, constant);
// FIXME: Dynamic dispatch for class/arch/proto methods.
Callee callee = Callee::forDirect(gen, constant);
// If there are substitutions, specialize the generic getter.
// If there are substitutions, specialize the generic accessor.
// FIXME: Generic subscript operator could add another layer of
// substitutions.
if (!substitutions.empty()) {
assert(method.getType().is<PolymorphicFunctionType>() &&
"generic getter is not of a poly function type");
substPropertyType = getThinFunctionType(substPropertyType,
SGM.getConstantCC(constant));
SILType loweredPropertyType = getLoweredLoadableType(substPropertyType,
constant.uncurryLevel);
gen.SGM.getConstantCC(constant));
method = B.createSpecialize(loc, method, substitutions,
loweredPropertyType);
callee.addSubstitutions(gen, loc, substitutions,
substPropertyType->getCanonicalType(), 0);
}
assert(method.getType().is<FunctionType>() &&
"getter is not of a concrete function type");
return ManagedValue(method, ManagedValue::Unmanaged);
return callee;
}
/// Emit a call to a getter and materialize its result.
@@ -1026,13 +1232,10 @@ Materialize SILGenFunction::emitGetProperty(SILLocation loc,
propType = tc.getMethodTypeInContext(thisValue.getType()->getRValueType(),
propType);
ManagedValue getter = emitSpecializedPropertyFunctionRef(loc, get,
substitutions,
propType);
Callee getter = emitSpecializedPropertyFunctionRef(*this, loc, get,
substitutions, propType);
CallEmission emission(*this, Callee(getter,
OwnershipConventions::get(*this, get,
getter.getType())));
CallEmission emission(*this, std::move(getter));
// This ->
if (thisValue)
emission.addCallSite(loc, std::move(thisValue));
@@ -1066,13 +1269,10 @@ void SILGenFunction::emitSetProperty(SILLocation loc,
propType = tc.getMethodTypeInContext(thisValue.getType()->getRValueType(),
propType);
ManagedValue setter = emitSpecializedPropertyFunctionRef(loc, set,
substitutions,
propType);
Callee setter = emitSpecializedPropertyFunctionRef(*this, loc, set,
substitutions, propType);
CallEmission emission(*this, Callee(setter,
OwnershipConventions::get(*this, set,
setter.getType())));
CallEmission emission(*this, std::move(setter));
// This ->
if (thisValue)
emission.addCallSite(loc, std::move(thisValue));

View File

@@ -571,33 +571,46 @@ static void makeCaptureSILArguments(SILGenFunction &gen, ValueDecl *capture) {
void SILGenFunction::emitProlog(CapturingExpr *ce,
ArrayRef<Pattern*> paramPatterns,
Type resultType) {
// Emit the capture argument variables. These are placed first because they
emitProlog(paramPatterns, resultType);
// Emit the capture argument variables. These are placed last because they
// become the first curry level of the SIL function.
for (auto capture : ce->getCaptures()) {
makeCaptureSILArguments(*this, capture);
}
emitProlog(paramPatterns, resultType);
}
void SILGenFunction::emitProlog(ArrayRef<Pattern *> paramPatterns,
Type resultType) {
// Emit the argument variables.
for (size_t i = 0; i < paramPatterns.size(); ++i) {
// Allocate the local mutable argument storage and set up an Initialization.
InitializationPtr argInit
= InitializationForPattern(*this, InitializationForPattern::Argument)
.visit(paramPatterns[i]);
// Add the SILArguments and use them to initialize the local argument
// values.
ArgumentInitVisitor(*this, F).visit(paramPatterns[i], argInit.get());
}
// If the return type is address-only, emit the indirect return argument.
const TypeLoweringInfo &returnTI = getTypeLoweringInfo(resultType);
if (returnTI.isAddressOnly(SGM.M)) {
IndirectReturnAddress = new (SGM.M) SILArgument(returnTI.getLoweredType(),
F.begin());
F.begin());
}
auto emitPattern = [&](Pattern *p) {
// Allocate the local mutable argument storage and set up an Initialization.
InitializationPtr argInit
= InitializationForPattern(*this, InitializationForPattern::Argument)
.visit(p);
// Add the SILArguments and use them to initialize the local argument
// values.
ArgumentInitVisitor(*this, F).visit(p, argInit.get());
};
// Emit the argument variables in calling convention order.
UncurryDirection direction = SGM.Types.getUncurryDirection(F.getAbstractCC());
switch (direction) {
case UncurryDirection::LeftToRight:
for (Pattern *p : paramPatterns)
emitPattern(p);
break;
case UncurryDirection::RightToLeft:
for (Pattern *p : reversed(paramPatterns))
emitPattern(p);
break;
}
}
@@ -1018,8 +1031,12 @@ void SILGenFunction::emitObjCMethodThunk(SILConstant thunk) {
auto ownership = OwnershipConventions::get(*this, thunk, thunkTy);
SmallVector<SILValue, 4> args;
SILFunctionTypeInfo *info = thunkTy.getFunctionTypeInfo();
if (info->hasIndirectReturn()) {
args.push_back(new(F.getModule()) SILArgument(info->getIndirectReturnType(),
F.begin()));
}
ArrayRef<SILType> inputs
= info->getInputTypesWithoutIndirectReturnType();
for (unsigned i = 0, e = inputs.size(); i < e; ++i) {
@@ -1031,10 +1048,11 @@ void SILGenFunction::emitObjCMethodThunk(SILConstant thunk) {
args.push_back(arg);
}
if (info->hasIndirectReturn()) {
args.push_back(new (F.getModule()) SILArgument(info->getIndirectReturnType(),
F.begin()));
}
// Reorder the 'this' argument for the Swift calling convention.
size_t thisIndex = info->hasIndirectReturn() ? 1 : 0;
SILValue thisArg = args[thisIndex];
args.erase(args.begin() + thisIndex);
args.push_back(thisArg);
// Call the native entry point.
SILValue nativeFn = emitGlobalFunctionRef(thunk.getDecl(),
@@ -1051,17 +1069,17 @@ void SILGenFunction::emitObjCPropertyGetter(SILConstant getter) {
auto ownership = OwnershipConventions::get(*this, getter, thunkTy);
SILFunctionTypeInfo *info = thunkTy.getFunctionTypeInfo();
SILValue thisValue
= new (F.getModule()) SILArgument(info->getInputTypes()[0], F.begin());
SILValue indirectReturn;
SILType resultType;
if (info->hasIndirectReturn()) {
indirectReturn = new (F.getModule()) SILArgument(info->getIndirectReturnType(),
F.begin());
indirectReturn
= new(F.getModule()) SILArgument(info->getIndirectReturnType(),F.begin());
resultType = indirectReturn.getType();
} else {
resultType = info->getResultType();
}
SILValue thisValue
= new (F.getModule()) SILArgument(info->getInputTypes()[0], F.begin());
auto *var = cast<VarDecl>(getter.getDecl());
if (var->isProperty()) {
@@ -1069,9 +1087,9 @@ void SILGenFunction::emitObjCPropertyGetter(SILConstant getter) {
if (!ownership.isArgumentConsumed(0))
emitObjCUnconsumedArgument(*this, var, thisValue);
SmallVector<SILValue, 2> args;
args.push_back(thisValue);
if (indirectReturn)
args.push_back(indirectReturn);
args.push_back(thisValue);
SILValue nativeFn = emitGlobalFunctionRef(var, getter.asObjC(false));
SILValue result = B.createApply(var, nativeFn, info->getResultType(), args);
emitObjCReturnValue(*this, var, result, ownership);
@@ -1123,8 +1141,8 @@ void SILGenFunction::emitObjCPropertySetter(SILConstant setter) {
if (!ownership.isArgumentConsumed(1))
emitObjCUnconsumedArgument(*this, var, setValue);
SmallVector<SILValue, 2> args;
args.push_back(thisValue);
args.push_back(setValue);
args.push_back(thisValue);
SILValue nativeFn = emitGlobalFunctionRef(var, setter.asObjC(false));
SILValue result = B.createApply(var, nativeFn, info->getResultType(), args);
// Result should always be void.
@@ -1150,4 +1168,3 @@ void SILGenFunction::emitObjCPropertySetter(SILConstant setter) {
B.createReturn(var, emitEmptyTuple(var));
}

View File

@@ -664,9 +664,9 @@ ManagedValue SILGenFunction::emitMethodRef(SILLocation loc,
// FIXME: Emit dynamic dispatch instruction (class_method, super_method, etc.)
// if needed.
SILType methodType = SGM.getConstantType(methodConstant);
SILValue methodValue = B.createFunctionRef(loc,
SGM.getFunction(methodConstant));
SILType methodType = SGM.getConstantType(methodConstant.atUncurryLevel(0));
/// If the 'this' type is a bound generic, specialize the method ref with
/// its substitutions.
@@ -717,7 +717,7 @@ ManagedValue SILGenFunction::emitMethodRef(SILLocation loc,
}
SILType specType = getLoweredLoadableType(outerMethodTy,
methodValue.getType().getUncurryLevel());
methodConstant.uncurryLevel);
methodValue = B.createSpecialize(loc, methodValue, allSubs, specType);
}
@@ -1119,7 +1119,6 @@ ManagedValue SILGenFunction::emitClosureForCapturingExpr(SILLocation loc,
auto captures = body->getCaptures();
if (!captures.empty()) {
llvm::SmallVector<SILValue, 4> capturedArgs;
for (ValueDecl *capture : captures) {
switch (getDeclCaptureKind(capture)) {
@@ -1168,9 +1167,7 @@ ManagedValue SILGenFunction::emitClosureForCapturingExpr(SILLocation loc,
}
SILValue functionRef = emitGlobalFunctionRef(loc, constant);
Type closureSwiftTy
= functionRef.getType().getAs<AnyFunctionType>()->getResult();
SILType closureTy = getLoweredLoadableType(closureSwiftTy);
SILType closureTy = getLoweredLoadableType(body->getType());
return emitManagedRValueWithCleanup(
B.createPartialApply(loc, functionRef, capturedArgs,
closureTy));
@@ -1390,7 +1387,10 @@ static void emitImplicitValueConstructor(SILGenFunction &gen,
return emitImplicitValueDefaultConstructor(gen, ctor);
}
emitConstructorMetatypeArg(gen, ctor);
// Emit the indirect return argument, if any.
SILValue resultSlot;
if (thisTy.isAddressOnly(gen.SGM.M))
resultSlot = new (gen.F.getModule()) SILArgument(thisTy, gen.F.begin());
// Emit the elementwise arguments.
SmallVector<RValue, 4> elements;
@@ -1401,12 +1401,11 @@ static void emitImplicitValueConstructor(SILGenFunction &gen,
emitImplicitValueConstructorArg(gen, ctor, P->getType()));
}
emitConstructorMetatypeArg(gen, ctor);
// If we have an indirect return slot, initialize it in-place in the implicit
// return slot.
if (thisTy.isAddressOnly(gen.SGM.M)) {
SILValue resultSlot
= new (gen.F.getModule()) SILArgument(thisTy, gen.F.begin());
if (resultSlot) {
auto *decl = cast<StructDecl>(thisTy.getSwiftRValueType()
->getNominalOrBoundGenericNominal());
unsigned memberIndex = 0;
@@ -1459,8 +1458,8 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
return emitImplicitValueConstructor(*this, ctor);
// Emit the prolog.
emitConstructorMetatypeArg(*this, ctor);
emitProlog(ctor->getArguments(), ctor->getImplicitThisDecl()->getType());
emitConstructorMetatypeArg(*this, ctor);
// Get the 'this' decl and type.
VarDecl *thisDecl = ctor->getImplicitThisDecl();
@@ -1592,10 +1591,14 @@ namespace {
void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) {
// Emit the prolog. Since we're just going to forward our args directly
// to the initializer, don't allocate local variables for them.
emitConstructorMetatypeArg(*this, ctor);
SmallVector<SILValue, 8> args;
// Forward the constructor arguments.
ArgumentForwardVisitor(*this, args).visit(ctor->getArguments());
emitConstructorMetatypeArg(*this, ctor);
// Allocate the "this" value.
VarDecl *thisDecl = ctor->getImplicitThisDecl();
SILType thisTy = getLoweredType(thisDecl->getType());
@@ -1616,9 +1619,6 @@ void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) {
}
args.push_back(thisValue);
// Forward the constructor arguments.
ArgumentForwardVisitor(*this, args).visit(ctor->getArguments());
// Call the initializer.
SILConstant initConstant = SILConstant(ctor, SILConstant::Kind::Initializer);
ManagedValue initVal = emitMethodRef(ctor, thisValue, initConstant,
@@ -1653,6 +1653,9 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
if (!ctor->getBody())
return emitClassImplicitConstructorInitializer(*this, ctor);
// Emit the prolog for the non-this arguments.
emitProlog(ctor->getArguments(), TupleType::getEmpty(F.getASTContext()));
// Emit the 'this' argument and make an lvalue for it.
VarDecl *thisDecl = ctor->getImplicitThisDecl();
SILType thisTy = getLoweredLoadableType(thisDecl->getType());
@@ -1666,9 +1669,6 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
SILValue thisLV = VarLocs[thisDecl].address;
emitStore(ctor, ManagedValue(thisArg, ManagedValue::Unmanaged), thisLV);
// Emit the prolog for the non-this arguments.
emitProlog(ctor->getArguments(), TupleType::getEmpty(F.getASTContext()));
// Create a basic block to jump to for the implicit 'this' return.
// We won't emit the block until after we've emitted the body.
epilogBB = new (SGM.M) SILBasicBlock(&F);
@@ -1747,17 +1747,35 @@ void SILGenFunction::emitCurryThunk(FuncExpr *fe,
unsigned paramCount = from.uncurryLevel + 1;
// If the function has implicit closure context arguments, forward them.
if (!fe->getCaptures().empty()) {
for (auto capture : fe->getCaptures())
forwardCaptureArgs(*this, curriedArgs, capture);
/// Forward implicit closure context arguments.
bool hasCaptures = !fe->getCaptures().empty();
if (hasCaptures)
--paramCount;
}
auto forwardCaptures = [&] {
if (hasCaptures)
for (auto capture : fe->getCaptures())
forwardCaptureArgs(*this, curriedArgs, capture);
};
// Forward the curried formal arguments.
auto forwardedPatterns = fe->getBodyParamPatterns().slice(0, paramCount);
ArgumentForwardVisitor forwarder(*this, curriedArgs);
for (auto *paramPattern : fe->getBodyParamPatterns().slice(0, paramCount))
forwarder.visit(paramPattern);
UncurryDirection direction
= SGM.Types.getUncurryDirection(F.getAbstractCC());
switch (direction) {
case UncurryDirection::LeftToRight:
forwardCaptures();
for (auto *paramPattern : forwardedPatterns)
forwarder.visit(paramPattern);
break;
case UncurryDirection::RightToLeft:
for (auto *paramPattern : reversed(forwardedPatterns))
forwarder.visit(paramPattern);
forwardCaptures();
break;
}
// FIXME: Forward archetypes and specialize if the function is generic.
@@ -1870,8 +1888,6 @@ RValue SILGenFunction::visitDefaultValueExpr(DefaultValueExpr *E, SGFContext C)
}
SILValue SILGenFunction::emitGeneralizedValue(SILLocation loc, SILValue v) {
assert(v.getType().getUncurryLevel() == 0 &&
"uncurried functions shouldn't be used as swift values");
// Thicken thin functions.
if (v.getType().is<AnyFunctionType>() &&
v.getType().castTo<AnyFunctionType>()->isThin()) {

View File

@@ -120,12 +120,6 @@ void SILType::print(raw_ostream &OS) const {
if (is<AnyFunctionType>()) {
auto info = getFunctionTypeInfo();
if (info->getUncurryLevel()) {
if (!Attributes.empty()) Attributes += ", ";
Attributes += "sil_uncurry=";
Attributes += llvm::utostr(info->getUncurryLevel());
}
if (info->hasIndirectReturn()) {
if (!Attributes.empty()) Attributes += ", ";
Attributes += "sil_sret";
@@ -677,15 +671,6 @@ void SILFunction::dump() const {
/// Pretty-print the SILFunction to the designated stream.
void SILFunction::print(llvm::raw_ostream &OS) const {
// FIXME: Temporary testing comment until we actually use uncurried function
// types during SILGen.
OS << "// uncurried type: ";
getModule().Types.uncurryFunctionType(
cast<AnyFunctionType>(getLoweredType().getSwiftRValueType()),
getLoweredType().getUncurryLevel())
->print(OS);
OS << '\n';
OS << "sil ";
switch (getLinkage()) {
case SILLinkage::Internal:

View File

@@ -79,32 +79,20 @@ bool SILType::isAddressOnly(CanType Ty, SILModule &M) {
SILFunctionTypeInfo *SILFunctionTypeInfo::create(CanType swiftType,
ArrayRef<SILType> inputTypes,
SILType resultType,
ArrayRef<unsigned> uncurriedInputCounts,
bool hasIndirectReturn,
SILModule &M) {
// We allocate room for an extra unsigned in the uncurriedInputCounts array,
// so that we can stuff a leading zero in there and be able to efficiently
// return both the begins and ends of each uncurried argument group.
void *buffer = M.allocate(sizeof(SILFunctionTypeInfo)
+ sizeof(SILType)*inputTypes.size()
+ sizeof(unsigned)*(1+uncurriedInputCounts.size()),
alignof(SILFunctionTypeInfo));
+ sizeof(SILType)*inputTypes.size(),
alignof(SILFunctionTypeInfo));
SILFunctionTypeInfo *fi = ::new (buffer) SILFunctionTypeInfo(
swiftType,
inputTypes.size(),
resultType,
uncurriedInputCounts.size(),
hasIndirectReturn);
memcpy(fi->getInputTypeBuffer(), inputTypes.data(),
sizeof(SILType) * inputTypes.size());
fi->getUncurryBuffer()[0] = 0;
memcpy(fi->getUncurryBuffer()+1, uncurriedInputCounts.data(),
sizeof(unsigned) * uncurriedInputCounts.size());
return fi;
}
unsigned SILType::getUncurryLevel() const {
if (auto *finfo = value.getPointer().dyn_cast<SILFunctionTypeInfo*>())
return finfo->getUncurryLevel();
return 0;
}

View File

@@ -24,7 +24,19 @@
using namespace swift;
using namespace Lowering;
AnyFunctionType *TypeConverter::uncurryFunctionType(AnyFunctionType *t,
UncurryDirection TypeConverter::getUncurryDirection(AbstractCC cc) {
switch (cc) {
case AbstractCC::C:
case AbstractCC::ObjCMethod:
return UncurryDirection::LeftToRight;
case AbstractCC::Freestanding:
case AbstractCC::Method:
return UncurryDirection::RightToLeft;
}
}
AnyFunctionType *TypeConverter::getUncurriedFunctionType(AnyFunctionType *t,
unsigned uncurryLevel) {
if (uncurryLevel == 0)
return t;
@@ -73,17 +85,10 @@ AnyFunctionType *TypeConverter::uncurryFunctionType(AnyFunctionType *t,
}
// Put the inputs in the order expected by the calling convention.
switch (outerCC) {
case AbstractCC::C:
case AbstractCC::ObjCMethod:
// C/ObjC functions are curried left-to-right.
// They shouldn't be generic though.
assert(!isPolymorphic && "c/objc function shouldn't be generic");
switch (getUncurryDirection(outerCC)) {
case UncurryDirection::LeftToRight:
break;
case AbstractCC::Freestanding:
case AbstractCC::Method:
// Swift functions uncurry right-to-left.
case UncurryDirection::RightToLeft:
std::reverse(inputs.begin(), inputs.end());
break;
}
@@ -274,21 +279,9 @@ namespace {
};
} // end anonymous namespace
SILFunctionTypeInfo *TypeConverter::makeInfoForFunctionType(AnyFunctionType *ft,
unsigned uncurries)
SILFunctionTypeInfo *TypeConverter::makeInfoForFunctionType(AnyFunctionType *ft)
{
CanType topType(ft);
SmallVector<SILType, 8> inputTypes;
SmallVector<unsigned, 3> uncurriedInputCounts;
// Destructure the uncurried input tuple types.
for (;;) {
LoweredFunctionInputTypeVisitor(*this, inputTypes)
.visit(ft->getInput()->getCanonicalType());
uncurriedInputCounts.push_back(inputTypes.size());
if (uncurries-- == 0)
break;
ft = ft->getResult()->castTo<AnyFunctionType>();
}
// If the result type lowers to an address-only type, add it as an indirect
// return argument.
@@ -299,9 +292,12 @@ SILFunctionTypeInfo *TypeConverter::makeInfoForFunctionType(AnyFunctionType *ft,
resultType = getEmptyTupleType();
}
return SILFunctionTypeInfo::create(topType, inputTypes, resultType,
uncurriedInputCounts, hasIndirectReturn,
M);
// Destructure the input tuple type.
LoweredFunctionInputTypeVisitor(*this, inputTypes)
.visit(ft->getInput()->getCanonicalType());
return SILFunctionTypeInfo::create(CanType(ft), inputTypes, resultType,
hasIndirectReturn, M);
}
const TypeLoweringInfo &
@@ -329,12 +325,16 @@ TypeConverter::makeTypeLoweringInfo(CanType t, unsigned uncurryLevel) {
}
// Make a SILFunctionTypeInfo for function types.
if (AnyFunctionType *ft = t->getAs<AnyFunctionType>())
theInfo->loweredType = SILType(makeInfoForFunctionType(ft, uncurryLevel),
if (AnyFunctionType *ft = t->getAs<AnyFunctionType>()) {
auto *uncurried = getUncurriedFunctionType(ft, uncurryLevel);
theInfo->loweredType = SILType(makeInfoForFunctionType(uncurried),
/*address=*/ addressOnly);
// Otherwise, create a SILType from just the Swift type.
else
} else {
// Otherwise, create a SILType from just the Swift type.
assert(uncurryLevel == 0 &&
"non-function type cannot have an uncurry level");
theInfo->loweredType = SILType(t, /*address=*/ addressOnly);
}
return *theInfo;
}

View File

@@ -11,12 +11,14 @@
//===----------------------------------------------------------------------===//
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILVisitor.h"
#include "swift/SIL/Dominance.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Module.h"
#include "swift/AST/Types.h"
#include "swift/SIL/TypeLowering.h"
#include "swift/Basic/Range.h"
#include "llvm/Support/Debug.h"
@@ -197,8 +199,6 @@ public:
require(!calleeTy.isAddress(), "callee of closure cannot be an address");
require(calleeTy.is<FunctionType>(),
"callee of closure must have concrete function type");
require(calleeTy.castTo<FunctionType>()->isThin(),
"callee of closure must have a thin function type");
SILType appliedTy = PAI->getType();
require(!appliedTy.isAddress(), "result of closure cannot be an address");
require(appliedTy.is<FunctionType>(),
@@ -207,33 +207,35 @@ public:
require(!appliedTy.castTo<FunctionType>()->isThin(),
"result of closure cannot have a thin function type");
SILFunctionTypeInfo *ti = calleeTy.getFunctionTypeInfo();
SILFunctionTypeInfo *info = calleeTy.getFunctionTypeInfo();
SILFunctionTypeInfo *resultInfo = appliedTy.getFunctionTypeInfo();
// Check that the arguments match the curry levels.
require(PAI->getArguments().size() == ti->getCurryInputTypes().size(),
"closure doesn't have right number of curry arguments for function");
for (size_t i = 0, size = PAI->getArguments().size(); i < size; ++i) {
DEBUG(llvm::dbgs() << " argument type ";
PAI->getArguments()[i].getType().print(llvm::dbgs());
llvm::dbgs() << " for input type ";
ti->getCurryInputTypes()[i].print(llvm::dbgs());
llvm::dbgs() << '\n');
require(PAI->getArguments()[i].getType() == ti->getCurryInputTypes()[i],
"input types to closure don't match function input types");
// The arguments must match the suffix of the original function's input
// types.
require(PAI->getArguments().size() + resultInfo->getInputTypes().size()
== info->getInputTypes().size(),
"result of partial_apply should take as many inputs as were not "
"applied by the instruction");
unsigned offset = info->getInputTypes().size() - PAI->getArguments().size();
for (unsigned i = 0; i < PAI->getArguments().size(); ++i) {
require(PAI->getArguments()[i].getType()
== info->getInputTypes()[i + offset],
"applied argument types do not match suffix of function type's "
"inputs");
}
DEBUG(llvm::dbgs() << "result type ";
PAI->getType().print(llvm::dbgs());
llvm::dbgs() << '\n');
// The result type should match the uncurried type.
FunctionType *ft = calleeTy.castTo<FunctionType>();
for (unsigned i = 0; i < calleeTy.getUncurryLevel(); ++i)
ft = ft->getResult()->castTo<FunctionType>();
require(PAI->getType().getSwiftType()->isEqual(ft)
&& PAI->getType().getUncurryLevel() == 0,
"type of apply instruction doesn't match function result type");
// The arguments to the result function type must match the prefix of the
// original function's input types.
for (unsigned i = 0; i < resultInfo->getInputTypes().size(); ++i) {
require(resultInfo->getInputTypes()[i] == info->getInputTypes()[i],
"inputs to result function type do not match unapplied inputs "
"of original function");
}
require(resultInfo->getResultType() == info->getResultType(),
"result type of result function type does not match original "
"function");
}
void checkBuiltinFunctionRefInst(BuiltinFunctionRefInst *BFI) {
@@ -310,9 +312,6 @@ public:
"Specialize source should have a polymorphic function type");
require(operandTy.castTo<AnyFunctionType>()->isThin(),
"Specialize source should have a thin function type");
require(SI->getType().getUncurryLevel()
== SI->getOperand().getType().getUncurryLevel(),
"Specialize source and dest uncurry levels must match");
}
void checkStructInst(StructInst *SI) {
@@ -520,11 +519,25 @@ public:
// generic types.
}
CanType getMethodThisType(AnyFunctionType *ft) {
Lowering::UncurryDirection direction
= F.getModule().Types.getUncurryDirection(ft->getCC());
auto *inputTuple = ft->getInput()->getAs<TupleType>();
if (!inputTuple)
return ft->getInput()->getCanonicalType();
switch (direction) {
case Lowering::UncurryDirection::LeftToRight:
return inputTuple->getFields()[0].getType()->getCanonicalType();
case Lowering::UncurryDirection::RightToLeft:
return inputTuple->getFields().back().getType()->getCanonicalType();
}
}
void checkArchetypeMethodInst(ArchetypeMethodInst *AMI) {
DEBUG(llvm::dbgs() << "verifying";
AMI->print(llvm::dbgs()));
require(AMI->getType(0).getUncurryLevel() == AMI->getMember().uncurryLevel,
"result method must be at natural uncurry level of method");
FunctionType *methodType = AMI->getType(0).getAs<FunctionType>();
DEBUG(llvm::dbgs() << "method type ";
methodType->print(llvm::dbgs());
@@ -539,11 +552,10 @@ public:
llvm::dbgs() << "\n");
require(operandType.is<ArchetypeType>(),
"operand type must be an archetype");
require(methodType->getResult()->is<FunctionType>(),
"result must be a method");
require(methodType->getInput()->isEqual(operandType.getSwiftType())
|| methodType->getInput()->isEqual(
CanType thisType = getMethodThisType(methodType);
require(thisType == operandType.getSwiftType()
|| thisType->isEqual(
MetaTypeType::get(operandType.getSwiftRValueType(),
operandType.getASTContext())),
"result must be method of operand type");
@@ -558,10 +570,6 @@ public:
}
void checkProtocolMethodInst(ProtocolMethodInst *EMI) {
require(EMI->getType(0).getUncurryLevel() == EMI->getMember().uncurryLevel,
"result method must be at natural uncurry level of method");
require(EMI->getType(0).getUncurryLevel() == 1,
"protocol method result must be at uncurry level 1");
FunctionType *methodType = EMI->getType(0).getAs<FunctionType>();
require(methodType,
"result method must be of a concrete function type");
@@ -570,11 +578,9 @@ public:
SILType operandType = EMI->getOperand().getType();
if (EMI->getMember().getDecl()->isInstanceMember()) {
require(methodType->getInput()->isEqual(
operandType.getASTContext().TheOpaquePointerType),
require(getMethodThisType(methodType)->isEqual(
operandType.getASTContext().TheOpaquePointerType),
"result must be a method of opaque pointer");
require(methodType->getResult()->is<FunctionType>(),
"result must be a method");
require(operandType.isAddress(),
"instance protocol_method must apply to an existential address");
require(operandType.isExistentialType(),
@@ -587,10 +593,8 @@ public:
require(operandType.castTo<MetaTypeType>()
->getInstanceType()->isExistentialType(),
"static protocol_method must apply to an existential metatype");
require(methodType->getResult()->is<FunctionType>(),
"result must be a method");
require(methodType->getInput()->isEqual(
EMI->getOperand().getType().getSwiftType()),
require(getMethodThisType(methodType) ==
EMI->getOperand().getType().getSwiftType(),
"result must be a method of the existential metatype");
}
}
@@ -604,8 +608,6 @@ public:
}
void checkClassMethodInst(ClassMethodInst *CMI) {
require(CMI->getType(0).getUncurryLevel() == CMI->getMember().uncurryLevel,
"result method must be at natural uncurry level of method");
auto *methodType = CMI->getType(0).getAs<AnyFunctionType>();
require(methodType,
"result method must be of a function type");
@@ -614,15 +616,11 @@ public:
SILType operandType = CMI->getOperand().getType();
require(isClassOrClassMetatype(operandType.getSwiftType()),
"operand must be of a class type");
require(isClassOrClassMetatype(methodType->getInput()),
require(isClassOrClassMetatype(getMethodThisType(methodType)),
"result must be a method of a class");
require(methodType->getResult()->is<AnyFunctionType>(),
"result must be a method");
}
void checkSuperMethodInst(SuperMethodInst *CMI) {
require(CMI->getType(0).getUncurryLevel() == CMI->getMember().uncurryLevel,
"result method must be at natural uncurry level of method");
auto *methodType = CMI->getType(0).getAs<AnyFunctionType>();
require(methodType,
"result method must be of a function type");
@@ -631,10 +629,8 @@ public:
SILType operandType = CMI->getOperand().getType();
require(isClassOrClassMetatype(operandType.getSwiftType()),
"operand must be of a class type");
require(isClassOrClassMetatype(methodType->getInput()),
require(isClassOrClassMetatype(getMethodThisType(methodType)),
"result must be a method of a class");
require(methodType->getResult()->is<AnyFunctionType>(),
"result must be a method");
}
void checkProjectExistentialInst(ProjectExistentialInst *PEI) {
@@ -698,10 +694,6 @@ public:
"bridge_to_block operand must be a function type");
require(resultTy.is<FunctionType>(),
"bridge_to_block result must be a function type");
require(operandTy.getUncurryLevel() == 0,
"bridge_to_block operand cannot be uncurried");
require(resultTy.getUncurryLevel() == 0,
"bridge_to_block result cannot be uncurried");
auto *operandFTy = BBI->getOperand().getType().castTo<FunctionType>();
auto *resultFTy = BBI->getType().castTo<FunctionType>();
@@ -732,10 +724,6 @@ public:
"thin_to_thick_function operand must be a function");
require(TTFI->getType().is<AnyFunctionType>(),
"thin_to_thick_function result must be a function");
require(TTFI->getType().getUncurryLevel()
== TTFI->getOperand().getType().getUncurryLevel(),
"thin_to_thick_function operand and result type must have same "
"uncurry level");
if (auto *opFTy = dyn_cast<FunctionType>(
TTFI->getOperand().getType().getSwiftType())) {
auto *resFTy = dyn_cast<FunctionType>(TTFI->getType().getSwiftType());
@@ -777,10 +765,6 @@ public:
"convert_cc operand must be a function");
require(CCI->getType().is<AnyFunctionType>(),
"convert_cc result must be a function");
require(CCI->getType().getUncurryLevel()
== CCI->getOperand().getType().getUncurryLevel(),
"convert_cc operand and result type must have same "
"uncurry level");
if (auto *opFTy = dyn_cast<FunctionType>(
CCI->getOperand().getType().getSwiftType())) {
auto *resFTy = dyn_cast<FunctionType>(CCI->getType().getSwiftType());

View File

@@ -1,49 +0,0 @@
// RUN: %swift -emit-sil -sdk=%S/Inputs %s | FileCheck %s
// FIXME: This shouldn't need to be a separate test when SILTypes actually use
// uncurried Swift types directly.
// CHECK: uncurried type: [thin] (x : Int64) -> Int64
// CHECK-NEXT: sil @_T10uncurrying3fooFT1xSi_Si
func foo(x:Int) -> Int {}
// CHECK: uncurried type: [thin] ((y : Int64), (x : Int64)) -> Int64
// CHECK-NEXT: sil @_T10uncurrying3barfT1xSi_FT1ySi_Si
func bar(x:Int)(y:Int) -> Int {}
// CHECK: uncurried type: [thin] <T, U> ((y : U), (x : T)) -> Int64
// CHECK-NEXT: sil @_T10uncurrying3zimU___fT1xQ__FT1yQ0__Si
func zim<T, U>(x:T)(y:U) -> Int {}
// CHECK: uncurried type: [thin] ((z : Int64), (y : Int64), (x : Int64)) -> Int64
// CHECK-NEXT: sil @_T10uncurrying4zangfT1xSi_fT1ySi_FT1zSi_Si
func zang(x:Int)(y:Int)(z:Int) -> Int {}
struct Hoozit {
// CHECK: uncurried type: [cc(method), thin] ((x : Int64), [byref] Hoozit) -> ()
// CHECK-NEXT: sil @_TV10uncurrying6Hoozit3foofRS0_FT1xSi_T_
func foo(x:Int) { }
// CHECK: uncurried type: [cc(method), thin] <U> ((x : U), [byref] Hoozit) -> ()
// CHECK-NEXT: sil @_TV10uncurrying6Hoozit3barfRS0_U__FT1xQ__T_
func bar<U>(x:U) { }
}
struct Wotsit<T> {
struct Thingamabob {
// CHECK: uncurried type: [cc(method), thin] <T> ((x : T), [byref] Wotsit<T>.Thingamabob) -> ()
// CHECK-NEXT: sil @_TVV10uncurrying6Wotsit11Thingamabob3fooU__fRS1_FT1xQ__T_
func foo(x:T) { }
// CHECK: uncurried type: [cc(method), thin] <T, U> ((x : U), [byref] Wotsit<T>.Thingamabob) -> ()
// CHECK-NEXT: sil @_TVV10uncurrying6Wotsit11Thingamabob3barU__fRS1_U__FT1xQ__T_
func bar<U>(x:U) { }
}
}
// ObjC method types uncurry left-to-right.
class [objc] Knicknack {
// CHECK: uncurried type: [cc(objc_method), thin] (Knicknack, (x : Int64)) -> ()
// CHECK-NEXT: sil @_TToCSo9Knicknack3foofS_FT1xSi_T_
func foo(x:Int) { }
}