mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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:
@@ -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
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 ¶mLevel = 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()) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace irgen {
|
||||
bool isSuper);
|
||||
|
||||
void addObjCMethodCallImplicitArguments(IRGenFunction &IGF,
|
||||
CallEmission &emission,
|
||||
Explosion &emission,
|
||||
SILConstant method,
|
||||
llvm::Value *self,
|
||||
SILType searchType);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -164,25 +164,30 @@ emitPHINodesForBBArgs(IRGenSILFunction &IGF,
|
||||
return phis;
|
||||
}
|
||||
|
||||
static void emitEntryPointIndirectReturn(IRGenSILFunction &IGF,
|
||||
static ArrayRef<SILArgument*> emitEntryPointIndirectReturn(
|
||||
IRGenSILFunction &IGF,
|
||||
SILBasicBlock *entry,
|
||||
Explosion ¶ms,
|
||||
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 ¶ms,
|
||||
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 ¶ms,
|
||||
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 ¶ms,
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -64,6 +64,8 @@ private:
|
||||
SILFunctionTypeInfo *ft);
|
||||
|
||||
public:
|
||||
OwnershipConventions() = default;
|
||||
|
||||
/// Derive the ownership conventions for a SILConstant.
|
||||
static OwnershipConventions get(SILGenFunction &gen,
|
||||
SILConstant c,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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) { }
|
||||
}
|
||||
Reference in New Issue
Block a user