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:
@@ -102,6 +102,8 @@ public:
|
|||||||
bbarg_iterator bbarg_end() { return BBArgList.end(); }
|
bbarg_iterator bbarg_end() { return BBArgList.end(); }
|
||||||
const_bbarg_iterator bbarg_begin() const { return BBArgList.begin(); }
|
const_bbarg_iterator bbarg_begin() const { return BBArgList.begin(); }
|
||||||
const_bbarg_iterator bbarg_end() const { return BBArgList.end(); }
|
const_bbarg_iterator bbarg_end() const { return BBArgList.end(); }
|
||||||
|
|
||||||
|
ArrayRef<SILArgument*> getBBArgs() const { return BBArgList; }
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
// Predecessors and Successors
|
// Predecessors and Successors
|
||||||
|
|||||||
@@ -73,11 +73,6 @@ public:
|
|||||||
return LoweredType.getFunctionTypeInfo();
|
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.
|
/// Returns the calling convention used by this entry point.
|
||||||
AbstractCC getAbstractCC() const {
|
AbstractCC getAbstractCC() const {
|
||||||
return getLoweredType().getFunctionCC();
|
return getLoweredType().getFunctionCC();
|
||||||
|
|||||||
@@ -327,7 +327,13 @@ public:
|
|||||||
|
|
||||||
SILValue getIndirectReturn() const {
|
SILValue getIndirectReturn() const {
|
||||||
assert(hasIndirectReturn() && "apply inst does not have indirect return!");
|
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) {
|
static bool classof(const ValueBase *V) {
|
||||||
|
|||||||
@@ -143,18 +143,10 @@ public:
|
|||||||
return value.getPointer().get<SILFunctionTypeInfo*>();
|
return value.getPointer().get<SILFunctionTypeInfo*>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the uncurry level of the type. Returns zero for non-function
|
/// Returns the Swift return type of a function type.
|
||||||
/// types.
|
|
||||||
unsigned getUncurryLevel() const;
|
|
||||||
|
|
||||||
/// Returns the Swift return type of a function type at the right uncurry
|
|
||||||
/// level.
|
|
||||||
/// The SILType must refer to a function type.
|
/// The SILType must refer to a function type.
|
||||||
CanType getFunctionResultType() const {
|
CanType getFunctionResultType() const {
|
||||||
auto *fty = castTo<AnyFunctionType>();
|
auto *fty = castTo<AnyFunctionType>();
|
||||||
for (unsigned uncurry = 0; uncurry < getUncurryLevel(); ++uncurry) {
|
|
||||||
fty = fty->getResult()->castTo<AnyFunctionType>();
|
|
||||||
}
|
|
||||||
return CanType(fty->getResult());
|
return CanType(fty->getResult());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,8 +258,7 @@ class alignas(8) SILFunctionTypeInfo {
|
|||||||
// for SILType.
|
// for SILType.
|
||||||
CanType swiftType;
|
CanType swiftType;
|
||||||
SILType resultType;
|
SILType resultType;
|
||||||
unsigned inputTypeCount;
|
unsigned inputTypeCount : 31;
|
||||||
unsigned uncurryCount : 31;
|
|
||||||
unsigned indirectReturn : 1;
|
unsigned indirectReturn : 1;
|
||||||
|
|
||||||
SILType *getInputTypeBuffer() {
|
SILType *getInputTypeBuffer() {
|
||||||
@@ -277,33 +268,20 @@ class alignas(8) SILFunctionTypeInfo {
|
|||||||
return reinterpret_cast<SILType const *>(this+1);
|
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,
|
SILFunctionTypeInfo(CanType swiftType,
|
||||||
unsigned inputTypeCount,
|
unsigned inputTypeCount,
|
||||||
SILType resultType,
|
SILType resultType,
|
||||||
unsigned uncurryCount,
|
|
||||||
bool hasIndirectReturn)
|
bool hasIndirectReturn)
|
||||||
: swiftType(swiftType),
|
: swiftType(swiftType),
|
||||||
resultType(resultType),
|
resultType(resultType),
|
||||||
inputTypeCount(inputTypeCount),
|
inputTypeCount(inputTypeCount),
|
||||||
uncurryCount(uncurryCount),
|
|
||||||
indirectReturn(hasIndirectReturn)
|
indirectReturn(hasIndirectReturn)
|
||||||
{
|
{}
|
||||||
assert(uncurryCount >= 1 && "negative uncurry level?!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static SILFunctionTypeInfo *create(CanType swiftType,
|
static SILFunctionTypeInfo *create(CanType swiftType,
|
||||||
ArrayRef<SILType> inputTypes,
|
ArrayRef<SILType> inputTypes,
|
||||||
SILType resultType,
|
SILType resultType,
|
||||||
ArrayRef<unsigned> uncurriedInputCounts,
|
|
||||||
bool hasIndirectReturn,
|
bool hasIndirectReturn,
|
||||||
SILModule &M);
|
SILModule &M);
|
||||||
|
|
||||||
@@ -329,66 +307,21 @@ public:
|
|||||||
/// Get the indirect return argument type. Always an address.
|
/// Get the indirect return argument type. Always an address.
|
||||||
SILType getIndirectReturnType() const {
|
SILType getIndirectReturnType() const {
|
||||||
assert(hasIndirectReturn() && "type doesn't have an indirect return?!");
|
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,
|
/// Returns the list of input types, excluding the indirect return argument,
|
||||||
/// if any.
|
/// if any.
|
||||||
ArrayRef<SILType> getInputTypesWithoutIndirectReturnType() const {
|
ArrayRef<SILType> getInputTypesWithoutIndirectReturnType() const {
|
||||||
auto inputs = getInputTypes();
|
auto inputs = getInputTypes();
|
||||||
return hasIndirectReturn()
|
return hasIndirectReturn() ? inputs.slice(1) : inputs;
|
||||||
? inputs.slice(0, inputs.size() - 1)
|
|
||||||
: inputs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the type of the return type or the indirect return slot if
|
/// Returns the type of the return type or the indirect return slot if
|
||||||
/// present.
|
/// present.
|
||||||
SILType getSemanticResultType() const {
|
SILType getSemanticResultType() const {
|
||||||
return hasIndirectReturn() ? getIndirectReturnType() : getResultType();
|
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 {
|
inline CanType SILType::getSwiftRValueType() const {
|
||||||
|
|||||||
@@ -255,6 +255,9 @@ public:
|
|||||||
OperandValueArrayRef slice(unsigned begin, unsigned length) const {
|
OperandValueArrayRef slice(unsigned begin, unsigned length) const {
|
||||||
return OperandValueArrayRef(Operands.slice(begin, length));
|
return OperandValueArrayRef(Operands.slice(begin, length));
|
||||||
}
|
}
|
||||||
|
OperandValueArrayRef slice(unsigned begin) const {
|
||||||
|
return OperandValueArrayRef(Operands.slice(begin));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An iterator over all uses of a ValueBase.
|
/// An iterator over all uses of a ValueBase.
|
||||||
|
|||||||
@@ -168,6 +168,12 @@ public:
|
|||||||
return loweredType;
|
return loweredType;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Argument order of uncurried functions.
|
||||||
|
enum class UncurryDirection {
|
||||||
|
LeftToRight,
|
||||||
|
RightToLeft
|
||||||
|
};
|
||||||
|
|
||||||
/// TypeConverter - helper class for creating and managing TypeLoweringInfos.
|
/// TypeConverter - helper class for creating and managing TypeLoweringInfos.
|
||||||
class TypeConverter {
|
class TypeConverter {
|
||||||
@@ -183,8 +189,7 @@ class TypeConverter {
|
|||||||
|
|
||||||
const TypeLoweringInfo &makeTypeLoweringInfo(CanType t,
|
const TypeLoweringInfo &makeTypeLoweringInfo(CanType t,
|
||||||
unsigned uncurryLevel);
|
unsigned uncurryLevel);
|
||||||
SILFunctionTypeInfo *makeInfoForFunctionType(AnyFunctionType *ft,
|
SILFunctionTypeInfo *makeInfoForFunctionType(AnyFunctionType *ft);
|
||||||
unsigned uncurryLevel);
|
|
||||||
|
|
||||||
Type makeConstantType(SILConstant constant);
|
Type makeConstantType(SILConstant constant);
|
||||||
|
|
||||||
@@ -238,8 +243,11 @@ public:
|
|||||||
GenericParamList *genericParams = nullptr) const;
|
GenericParamList *genericParams = nullptr) const;
|
||||||
|
|
||||||
/// Convert a nested function type into an uncurried representation.
|
/// Convert a nested function type into an uncurried representation.
|
||||||
static AnyFunctionType *uncurryFunctionType(AnyFunctionType *t,
|
static AnyFunctionType *getUncurriedFunctionType(AnyFunctionType *t,
|
||||||
unsigned uncurryLevel);
|
unsigned uncurryLevel);
|
||||||
|
|
||||||
|
/// Get the uncurried argument order for a calling convention.
|
||||||
|
static UncurryDirection getUncurryDirection(AbstractCC cc);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Lowering
|
} // namespace Lowering
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ private:
|
|||||||
void externalizeArgument(Explosion &out, Explosion &in,
|
void externalizeArgument(Explosion &out, Explosion &in,
|
||||||
SmallVectorImpl<std::pair<unsigned, Alignment>> &newByvals,
|
SmallVectorImpl<std::pair<unsigned, Alignment>> &newByvals,
|
||||||
CanType ty);
|
CanType ty);
|
||||||
void externalizeArguments(Explosion &arg,
|
void externalizeArguments(Explosion &out, Explosion &in,
|
||||||
SmallVectorImpl<std::pair<unsigned, Alignment>> &newByvals,
|
SmallVectorImpl<std::pair<unsigned, Alignment>> &newByvals,
|
||||||
CanType inputsTy);
|
CanType inputsTy);
|
||||||
llvm::CallSite emitInvoke(llvm::CallingConv::ID cc, llvm::Value *fn,
|
llvm::CallSite emitInvoke(llvm::CallingConv::ID cc, llvm::Value *fn,
|
||||||
|
|||||||
@@ -158,13 +158,12 @@ namespace irgen {
|
|||||||
ArrayRef<Substitution> subs,
|
ArrayRef<Substitution> subs,
|
||||||
llvm::Value *fn, llvm::Value *data,
|
llvm::Value *fn, llvm::Value *data,
|
||||||
ExplosionKind explosionLevel) {
|
ExplosionKind explosionLevel) {
|
||||||
SILFunctionTypeInfo *info = origSILType.getFunctionTypeInfo();
|
|
||||||
return forKnownFunction(origSILType.getFunctionCC(),
|
return forKnownFunction(origSILType.getFunctionCC(),
|
||||||
origSILType.getSwiftType(),
|
origSILType.getSwiftType(),
|
||||||
substResultType.getSwiftRValueType(),
|
substResultType.getSwiftRValueType(),
|
||||||
subs,
|
subs,
|
||||||
fn, data, explosionLevel,
|
fn, data, explosionLevel,
|
||||||
info->getUncurryLevel());
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare a callee for a known function with a known data pointer.
|
/// 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<llvm::Type*> &argTypes,
|
||||||
SmallVectorImpl<std::pair<unsigned, Alignment>> &byvals,
|
SmallVectorImpl<std::pair<unsigned, Alignment>> &byvals,
|
||||||
llvm::AttributeSet &attrs) {
|
llvm::AttributeSet &attrs) {
|
||||||
|
// Ask SIL's TypeLowering to uncurry the function type.
|
||||||
|
type = CanType(Lowering::getThinFunctionType(type, cc));
|
||||||
auto fn = cast<AnyFunctionType>(type);
|
auto fn = cast<AnyFunctionType>(type);
|
||||||
|
fn = Lowering::TypeConverter::getUncurriedFunctionType(fn, uncurryLevel);
|
||||||
|
|
||||||
// Save up the formal parameter types.
|
// Explode the argument.
|
||||||
llvm::SmallVector<AnyFunctionType*, 8> formalFnTypes;
|
auto decomposeTopLevelArg = [&](CanType inputTy) {
|
||||||
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());
|
|
||||||
if (TupleType *tupleTy = inputTy->getAs<TupleType>()) {
|
if (TupleType *tupleTy = inputTy->getAs<TupleType>()) {
|
||||||
for (auto &field : tupleTy->getFields()) {
|
for (auto &field : tupleTy->getFields()) {
|
||||||
decomposeFunctionArg(IGM, CanType(field.getType()), cc, explosionKind,
|
decomposeFunctionArg(IGM, CanType(field.getType()), cc, explosionKind,
|
||||||
@@ -578,10 +545,29 @@ static CanType decomposeFunctionType(IRGenModule &IGM, CanType type,
|
|||||||
decomposeFunctionArg(IGM, inputTy, cc, explosionKind,
|
decomposeFunctionArg(IGM, inputTy, cc, explosionKind,
|
||||||
argTypes, byvals, attrs);
|
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());
|
return CanType(fn->getResult());
|
||||||
}
|
}
|
||||||
@@ -683,9 +669,8 @@ IRGenModule::getFunctionType(SILType type, ExplosionKind explosionKind,
|
|||||||
llvm::AttributeSet &attrs) {
|
llvm::AttributeSet &attrs) {
|
||||||
assert(!type.isAddress());
|
assert(!type.isAddress());
|
||||||
assert(type.is<AnyFunctionType>());
|
assert(type.is<AnyFunctionType>());
|
||||||
SILFunctionTypeInfo *info = type.getFunctionTypeInfo();
|
|
||||||
return getFunctionType(type.getFunctionCC(), type.getSwiftType(),
|
return getFunctionType(type.getFunctionCC(), type.getSwiftType(),
|
||||||
explosionKind, info->getUncurryLevel(),
|
explosionKind, 0,
|
||||||
extraData, attrs);
|
extraData, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1393,24 +1378,17 @@ void CallEmission::externalizeArgument(Explosion &out, Explosion &in,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convert exploded Swift arguments into C-compatible arguments.
|
/// 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,
|
SmallVectorImpl<std::pair<unsigned, Alignment>> &newByvals,
|
||||||
CanType inputsTy) {
|
CanType inputsTy) {
|
||||||
Explosion externalized(arg.getKind());
|
|
||||||
|
|
||||||
if (TupleType *tupleTy = inputsTy->getAs<TupleType>()) {
|
if (TupleType *tupleTy = inputsTy->getAs<TupleType>()) {
|
||||||
for (auto &elt : tupleTy->getFields()) {
|
for (auto &elt : tupleTy->getFields()) {
|
||||||
externalizeArgument(externalized, arg, newByvals,
|
externalizeArgument(out, arg, newByvals,
|
||||||
elt.getType()->getCanonicalType());
|
elt.getType()->getCanonicalType());
|
||||||
}
|
}
|
||||||
} else {
|
} 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.
|
/// 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
|
// Convert arguments to a representation appropriate to the calling
|
||||||
// convention.
|
// convention.
|
||||||
switch (CurCallee.getConvention()) {
|
AbstractCC cc = CurCallee.getConvention();
|
||||||
case AbstractCC::C:
|
switch (cc) {
|
||||||
case AbstractCC::ObjCMethod:
|
case AbstractCC::C: {
|
||||||
externalizeArguments(arg, newByvals,
|
Explosion externalized(arg.getKind());
|
||||||
CanType(CurOrigType->castTo<AnyFunctionType>()->getInput()));
|
externalizeArguments(externalized, arg, newByvals,
|
||||||
|
CanType(CurOrigType->castTo<AnyFunctionType>()->getInput()));
|
||||||
|
arg = std::move(externalized);
|
||||||
break;
|
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::Freestanding:
|
||||||
case AbstractCC::Method:
|
case AbstractCC::Method:
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
@@ -1776,18 +1774,6 @@ llvm::Function *irgen::emitFunctionSpecialization(IRGenModule &IGM,
|
|||||||
|
|
||||||
IRGenFunction subIGF(IGM, explosionLevel, spec);
|
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();
|
Explosion params = subIGF.collectParameters();
|
||||||
|
|
||||||
// Collect the indirect return address, if present.
|
// Collect the indirect return address, if present.
|
||||||
@@ -1799,17 +1785,6 @@ llvm::Function *irgen::emitFunctionSpecialization(IRGenModule &IGM,
|
|||||||
if (schema.requiresIndirectResult())
|
if (schema.requiresIndirectResult())
|
||||||
indirectReturn = retTI.getAddressForPointer(params.claimNext());
|
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.
|
// Apply the arguments in a call to the generic function.
|
||||||
Callee callee = Callee::forKnownFunction(genericType,
|
Callee callee = Callee::forKnownFunction(genericType,
|
||||||
retTy,
|
retTy,
|
||||||
@@ -1818,12 +1793,9 @@ llvm::Function *irgen::emitFunctionSpecialization(IRGenModule &IGM,
|
|||||||
nullptr,
|
nullptr,
|
||||||
explosionLevel);
|
explosionLevel);
|
||||||
CallEmission emission(subIGF, callee);
|
CallEmission emission(subIGF, callee);
|
||||||
|
FunctionType *ft = substType.castTo<FunctionType>();
|
||||||
for (size_t i = 0; i < paramLevels.size(); ++i) {
|
emission.addSubstitutedArg(CanType(ft->getInput()), params);
|
||||||
Explosion ¶mLevel = paramLevels.rbegin()[i];
|
assert(params.empty() && "did not claim all parameters?!");
|
||||||
FunctionType *uncurriedType = uncurriedTypes[i];
|
|
||||||
emission.addSubstitutedArg(CanType(uncurriedType->getInput()), paramLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the result of the call.
|
// Return the result of the call.
|
||||||
if (indirectReturn.isValid()) {
|
if (indirectReturn.isValid()) {
|
||||||
|
|||||||
@@ -427,7 +427,7 @@ CallEmission irgen::prepareObjCMethodRootCall(IRGenFunction &IGF,
|
|||||||
auto fnTy = IGF.IGM.getFunctionType(AbstractCC::ObjCMethod,
|
auto fnTy = IGF.IGM.getFunctionType(AbstractCC::ObjCMethod,
|
||||||
origType.getSwiftRValueType(),
|
origType.getSwiftRValueType(),
|
||||||
ExplosionKind::Minimal,
|
ExplosionKind::Minimal,
|
||||||
/*uncurryLevel*/ 1,
|
0,
|
||||||
ExtraData::None,
|
ExtraData::None,
|
||||||
attrs);
|
attrs);
|
||||||
bool indirectResult = requiresExternalIndirectResult(IGF.IGM,
|
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.
|
/// Emit the 'self'/'super' and '_cmd' arguments for an ObjC method dispatch.
|
||||||
void irgen::addObjCMethodCallImplicitArguments(IRGenFunction &IGF,
|
void irgen::addObjCMethodCallImplicitArguments(IRGenFunction &IGF,
|
||||||
CallEmission &emission,
|
Explosion &args,
|
||||||
SILConstant method,
|
SILConstant method,
|
||||||
llvm::Value *self,
|
llvm::Value *self,
|
||||||
SILType searchType) {
|
SILType searchType) {
|
||||||
// Compute the selector.
|
// Compute the selector.
|
||||||
Selector selector(method.getDecl());
|
Selector selector(method.getDecl());
|
||||||
|
|
||||||
Explosion args(ExplosionKind::Minimal);
|
|
||||||
|
|
||||||
// super.constructor references an instance method (even though the
|
// super.constructor references an instance method (even though the
|
||||||
// decl is really a 'static' member).
|
// decl is really a 'static' member).
|
||||||
bool isInstanceMethod
|
bool isInstanceMethod
|
||||||
@@ -505,9 +503,6 @@ void irgen::addObjCMethodCallImplicitArguments(IRGenFunction &IGF,
|
|||||||
IGF.IGM.getPointerAlignment()));
|
IGF.IGM.getPointerAlignment()));
|
||||||
}
|
}
|
||||||
args.add(selectorV);
|
args.add(selectorV);
|
||||||
|
|
||||||
// Add that to the emission.
|
|
||||||
emission.addArg(args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create the LLVM function declaration for a thunk that acts like
|
/// Create the LLVM function declaration for a thunk that acts like
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace irgen {
|
|||||||
bool isSuper);
|
bool isSuper);
|
||||||
|
|
||||||
void addObjCMethodCallImplicitArguments(IRGenFunction &IGF,
|
void addObjCMethodCallImplicitArguments(IRGenFunction &IGF,
|
||||||
CallEmission &emission,
|
Explosion &emission,
|
||||||
SILConstant method,
|
SILConstant method,
|
||||||
llvm::Value *self,
|
llvm::Value *self,
|
||||||
SILType searchType);
|
SILType searchType);
|
||||||
|
|||||||
@@ -1759,11 +1759,12 @@ static llvm::Constant *getValueWitness(IRGenModule &IGM,
|
|||||||
return asOpaquePtr(IGM, fn);
|
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) {
|
static CanType stripLabel(CanType input) {
|
||||||
if (auto tuple = dyn_cast<TupleType>(input))
|
if (auto tuple = dyn_cast<TupleType>(input))
|
||||||
if (tuple->getFields().size() == 1)
|
if (tuple->getFields().size() > 0)
|
||||||
return stripLabel(CanType(tuple->getFields()[0].getType()));
|
return stripLabel(CanType(tuple->getFields().back().getType()));
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -164,25 +164,30 @@ emitPHINodesForBBArgs(IRGenSILFunction &IGF,
|
|||||||
return phis;
|
return phis;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emitEntryPointIndirectReturn(IRGenSILFunction &IGF,
|
static ArrayRef<SILArgument*> emitEntryPointIndirectReturn(
|
||||||
|
IRGenSILFunction &IGF,
|
||||||
SILBasicBlock *entry,
|
SILBasicBlock *entry,
|
||||||
Explosion ¶ms,
|
Explosion ¶ms,
|
||||||
SILFunctionTypeInfo *funcTI,
|
SILFunctionTypeInfo *funcTI,
|
||||||
std::function<bool()> requiresIndirectResult) {
|
std::function<bool()> requiresIndirectResult) {
|
||||||
// Map the indirect return if present.
|
// Map the indirect return if present.
|
||||||
if (funcTI->hasIndirectReturn()) {
|
if (funcTI->hasIndirectReturn()) {
|
||||||
SILArgument *ret = entry->bbarg_end()[-1];
|
SILArgument *ret = entry->bbarg_begin()[0];
|
||||||
SILValue retv(ret, 0);
|
SILValue retv(ret, 0);
|
||||||
TypeInfo const &retType = IGF.IGM.getFragileTypeInfo(ret->getType());
|
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 {
|
} else {
|
||||||
// Map an indirect return for a type SIL considers loadable but still
|
// Map an indirect return for a type SIL considers loadable but still
|
||||||
// requires an indirect return at the IR level.
|
// requires an indirect return at the IR level.
|
||||||
if (requiresIndirectResult()) {
|
if (requiresIndirectResult()) {
|
||||||
TypeInfo const &retType = IGF.IGM.getFragileTypeInfo(funcTI->getResultType());
|
TypeInfo const &retType
|
||||||
|
= IGF.IGM.getFragileTypeInfo(funcTI->getResultType());
|
||||||
IGF.IndirectReturn = retType.getAddressForPointer(params.claimNext());
|
IGF.IndirectReturn = retType.getAddressForPointer(params.claimNext());
|
||||||
}
|
}
|
||||||
|
return entry->getBBArgs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,54 +200,33 @@ static void emitEntryPointArgumentsNativeCC(IRGenSILFunction &IGF,
|
|||||||
SILFunctionTypeInfo *funcTI = funcTy.getFunctionTypeInfo();
|
SILFunctionTypeInfo *funcTI = funcTy.getFunctionTypeInfo();
|
||||||
|
|
||||||
// Map the indirect return if present.
|
// Map the indirect return if present.
|
||||||
emitEntryPointIndirectReturn(IGF, entry, params, funcTI,
|
ArrayRef<SILArgument*> args
|
||||||
[&]() -> bool {
|
= emitEntryPointIndirectReturn(IGF, entry, params, funcTI,
|
||||||
TypeInfo const &retType = IGF.IGM.getFragileTypeInfo(funcTI->getResultType());
|
[&]() -> bool {
|
||||||
ExplosionSchema schema = retType.getSchema(IGF.CurExplosionLevel);
|
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.
|
// Map the remaining SIL argument to LLVM arguments.
|
||||||
unsigned level = funcTI->getUncurryLevel();
|
for (SILArgument *arg : args) {
|
||||||
llvm::SmallVector<AnyFunctionType*, 4> uncurriedTypes;
|
SILValue argv(arg, 0);
|
||||||
AnyFunctionType *uncurriedType = funcTy.castTo<AnyFunctionType>();
|
TypeInfo const &argType = IGF.getFragileTypeInfo(arg->getType());
|
||||||
for (;;) {
|
if (arg->getType().isAddress()) {
|
||||||
uncurriedTypes.push_back(uncurriedType);
|
IGF.newLoweredAddress(argv,
|
||||||
if (level-- != 0)
|
argType.getAddressForPointer(params.claimNext()));
|
||||||
uncurriedType = uncurriedType->getResult()->castTo<AnyFunctionType>();
|
continue;
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
Explosion explosion(IGF.CurExplosionLevel);
|
||||||
// Bind polymorphic arguments for this uncurry level.
|
argType.reexplode(IGF, params, explosion);
|
||||||
auto fn = uncurriedTypes.back();
|
IGF.newLoweredExplosion(arg, explosion);
|
||||||
uncurriedTypes.pop_back();
|
}
|
||||||
if (auto polyFn = dyn_cast<PolymorphicFunctionType>(fn))
|
|
||||||
emitPolymorphicParameters(IGF, polyFn, params);
|
// Bind polymorphic arguments.
|
||||||
} while (level-- != 0);
|
if (auto polyFn = funcTy.getAs<PolymorphicFunctionType>())
|
||||||
|
emitPolymorphicParameters(IGF, polyFn, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit entry point arguments for the parameters of a C function, or the
|
/// 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,
|
static void emitEntryPointArgumentsCOrObjC(IRGenSILFunction &IGF,
|
||||||
SILBasicBlock *entry,
|
SILBasicBlock *entry,
|
||||||
Explosion ¶ms,
|
Explosion ¶ms,
|
||||||
ArrayRef<SILType> inputTypes,
|
ArrayRef<SILArgument*> args) {
|
||||||
unsigned argOffset) {
|
for (SILArgument *arg : args) {
|
||||||
for (SILType inputType : inputTypes) {
|
|
||||||
(void)inputType;
|
|
||||||
|
|
||||||
SILArgument *arg = entry->bbarg_begin()[argOffset++];
|
|
||||||
TypeInfo const &argType = IGF.getFragileTypeInfo(arg->getType());
|
TypeInfo const &argType = IGF.getFragileTypeInfo(arg->getType());
|
||||||
if (arg->getType().isAddress()) {
|
if (arg->getType().isAddress()) {
|
||||||
IGF.newLoweredAddress(arg,
|
IGF.newLoweredAddress(arg,
|
||||||
@@ -279,39 +259,33 @@ static void emitEntryPointArgumentsCOrObjC(IRGenSILFunction &IGF,
|
|||||||
|
|
||||||
|
|
||||||
/// Emit entry point arguments for a SILFunction with the ObjC method calling
|
/// Emit entry point arguments for a SILFunction with the ObjC method calling
|
||||||
/// convention.
|
/// convention. This convention inserts the '_cmd' objc_msgSend argument after
|
||||||
static void emitEntryPointArgumentsObjCCC(IRGenSILFunction &IGF,
|
/// the first non-sret argument.
|
||||||
SILBasicBlock *entry,
|
static void emitEntryPointArgumentsObjCMethodCC(IRGenSILFunction &IGF,
|
||||||
Explosion ¶ms,
|
SILBasicBlock *entry,
|
||||||
SILType funcTy) {
|
Explosion ¶ms,
|
||||||
|
SILType funcTy) {
|
||||||
SILFunctionTypeInfo *funcTI = funcTy.getFunctionTypeInfo();
|
SILFunctionTypeInfo *funcTI = funcTy.getFunctionTypeInfo();
|
||||||
|
|
||||||
// Map the indirect return if present.
|
// Map the indirect return if present.
|
||||||
emitEntryPointIndirectReturn(IGF, entry, params, funcTI, [&] {
|
ArrayRef<SILArgument*> args
|
||||||
return requiresExternalIndirectResult(IGF.IGM, funcTI->getResultType());
|
= emitEntryPointIndirectReturn(IGF, entry, params, funcTI, [&] {
|
||||||
});
|
return requiresExternalIndirectResult(IGF.IGM, funcTI->getResultType());
|
||||||
|
});
|
||||||
|
|
||||||
assert(funcTI->getUncurryLevel() == 1
|
// Map the self argument. This should always be an ObjC pointer type so
|
||||||
&& "objc method should be at uncurry level 1");
|
// should never need to be loaded from a byval.
|
||||||
|
SILArgument *selfArg = args[0];
|
||||||
// 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];
|
|
||||||
TypeInfo const &selfType = IGF.getFragileTypeInfo(selfArg->getType());
|
TypeInfo const &selfType = IGF.getFragileTypeInfo(selfArg->getType());
|
||||||
Explosion self(IGF.CurExplosionLevel);
|
Explosion self(IGF.CurExplosionLevel);
|
||||||
selfType.reexplode(IGF, params, self);
|
selfType.reexplode(IGF, params, self);
|
||||||
IGF.newLoweredExplosion(selfArg, self);
|
IGF.newLoweredExplosion(selfArg, self);
|
||||||
|
|
||||||
// Discard the _cmd argument.
|
// Discard the implicit _cmd argument.
|
||||||
params.claimNext();
|
params.claimNext();
|
||||||
|
|
||||||
ArrayRef<SILType> inputTypes = funcTI->getInputTypesForCurryLevel(1);
|
// Map the rest of the arguments as in the C calling convention.
|
||||||
unsigned argOffset = funcTI->getUncurriedInputBegins()[1];
|
emitEntryPointArgumentsCOrObjC(IGF, entry, params, args.slice(1));
|
||||||
|
|
||||||
emitEntryPointArgumentsCOrObjC(IGF, entry, params,
|
|
||||||
inputTypes, argOffset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit entry point arguments for a SILFunction with the C calling
|
/// Emit entry point arguments for a SILFunction with the C calling
|
||||||
@@ -323,14 +297,11 @@ static void emitEntryPointArgumentsCCC(IRGenSILFunction &IGF,
|
|||||||
SILFunctionTypeInfo *funcTI = funcTy.getFunctionTypeInfo();
|
SILFunctionTypeInfo *funcTI = funcTy.getFunctionTypeInfo();
|
||||||
|
|
||||||
// Map the indirect return if present.
|
// Map the indirect return if present.
|
||||||
emitEntryPointIndirectReturn(IGF, entry, params, funcTI, [&] {
|
ArrayRef<SILArgument*> args
|
||||||
return requiresExternalIndirectResult(IGF.IGM, funcTI->getResultType());
|
= emitEntryPointIndirectReturn(IGF, entry, params, funcTI, [&] {
|
||||||
});
|
return requiresExternalIndirectResult(IGF.IGM, funcTI->getResultType());
|
||||||
|
});
|
||||||
ArrayRef<SILType> inputTypes = funcTI->getInputTypesForCurryLevel(0);
|
emitEntryPointArgumentsCOrObjC(IGF, entry, params, args);
|
||||||
unsigned argOffset = funcTI->getUncurriedInputBegins()[0];
|
|
||||||
|
|
||||||
emitEntryPointArgumentsCOrObjC(IGF, entry, params, inputTypes, argOffset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRGenSILFunction::emitSILFunction() {
|
void IRGenSILFunction::emitSILFunction() {
|
||||||
@@ -366,7 +337,7 @@ void IRGenSILFunction::emitSILFunction() {
|
|||||||
emitEntryPointArgumentsNativeCC(*this, entry->first, params, funcTy);
|
emitEntryPointArgumentsNativeCC(*this, entry->first, params, funcTy);
|
||||||
break;
|
break;
|
||||||
case AbstractCC::ObjCMethod:
|
case AbstractCC::ObjCMethod:
|
||||||
emitEntryPointArgumentsObjCCC(*this, entry->first, params, funcTy);
|
emitEntryPointArgumentsObjCMethodCC(*this, entry->first, params, funcTy);
|
||||||
break;
|
break;
|
||||||
case AbstractCC::C:
|
case AbstractCC::C:
|
||||||
emitEntryPointArgumentsCCC(*this, entry->first, params, funcTy);
|
emitEntryPointArgumentsCCC(*this, entry->first, params, funcTy);
|
||||||
@@ -755,29 +726,27 @@ void IRGenSILFunction::visitApplyInst(swift::ApplyInst *i) {
|
|||||||
builtin.getSubstitutions());
|
builtin.getSubstitutions());
|
||||||
}
|
}
|
||||||
|
|
||||||
SILType resultTy = i->getCallee().getType().getFunctionTypeInfo()
|
SILType calleeTy = i->getCallee().getType();
|
||||||
->getSemanticResultType();
|
SILType resultTy = calleeTy.getFunctionTypeInfo()->getSemanticResultType();
|
||||||
|
|
||||||
CallEmission emission = getCallEmissionForLoweredValue(*this,
|
CallEmission emission = getCallEmissionForLoweredValue(*this,
|
||||||
i->getCallee().getType(),
|
i->getCallee().getType(),
|
||||||
resultTy, calleeLV);
|
resultTy, calleeLV);
|
||||||
|
|
||||||
SILFunctionTypeInfo *ti
|
// Lower the SIL arguments to IR arguments.
|
||||||
= i->getCallee().getType().getFunctionTypeInfo();
|
Explosion llArgs(CurExplosionLevel);
|
||||||
|
|
||||||
// Lower the SIL arguments to IR arguments, and pass them to the CallEmission
|
// Save off the indirect return argument, if any.
|
||||||
// one curry at a time. CallEmission will arrange the curries in the proper
|
OperandValueArrayRef args = i->getArgumentsWithoutIndirectReturn();
|
||||||
// order for the callee.
|
SILValue indirectReturn;
|
||||||
|
if (i->hasIndirectReturn()) {
|
||||||
unsigned arg = 0;
|
indirectReturn = i->getIndirectReturn();
|
||||||
auto uncurriedInputEnds = ti->getUncurriedInputEnds();
|
}
|
||||||
|
|
||||||
// ObjC message sends need special handling for the 'this' argument. It may
|
// 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
|
// need to be wrapped in an objc_super struct, and the '_cmd' argument needs
|
||||||
// to be passed alongside it.
|
// to be passed alongside it.
|
||||||
if (calleeLV.kind == LoweredValue::Kind::ObjCMethod) {
|
if (calleeLV.kind == LoweredValue::Kind::ObjCMethod) {
|
||||||
assert(uncurriedInputEnds[0] == 1 &&
|
|
||||||
"more than one this argument for an objc call?!");
|
|
||||||
SILValue thisValue = i->getArguments()[0];
|
SILValue thisValue = i->getArguments()[0];
|
||||||
llvm::Value *selfArg;
|
llvm::Value *selfArg;
|
||||||
// Convert a metatype 'this' argument to the ObjC Class pointer.
|
// Convert a metatype 'this' argument to the ObjC Class pointer.
|
||||||
@@ -789,32 +758,22 @@ void IRGenSILFunction::visitApplyInst(swift::ApplyInst *i) {
|
|||||||
selfArg = selfExplosion.claimNext();
|
selfArg = selfExplosion.claimNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
addObjCMethodCallImplicitArguments(*this, emission,
|
addObjCMethodCallImplicitArguments(*this, llArgs,
|
||||||
calleeLV.getObjCMethod().getMethod(),
|
calleeLV.getObjCMethod().getMethod(),
|
||||||
selfArg,
|
selfArg,
|
||||||
calleeLV.getObjCMethod().getSuperSearchType());
|
calleeLV.getObjCMethod().getSuperSearchType());
|
||||||
|
|
||||||
arg = 1;
|
args = args.slice(1);
|
||||||
uncurriedInputEnds = uncurriedInputEnds.slice(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (SILValue arg : args)
|
||||||
|
emitApplyArgument(*this, llArgs, arg);
|
||||||
|
|
||||||
AnyFunctionType *calleeTy = i->getCallee().getType().castTo<AnyFunctionType>();
|
emission.addSubstitutedArg(CanType(calleeTy.castTo<FunctionType>()->getInput()),
|
||||||
interleave(uncurriedInputEnds.begin(), uncurriedInputEnds.end(),
|
llArgs);
|
||||||
[&](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>();
|
|
||||||
});
|
|
||||||
|
|
||||||
// If the function takes an indirect return argument, emit into it.
|
// If the function takes an indirect return argument, emit into it.
|
||||||
if (i->hasIndirectReturn()) {
|
if (indirectReturn) {
|
||||||
SILValue indirectReturn = i->getIndirectReturn();
|
|
||||||
Address a = getLoweredAddress(indirectReturn);
|
Address a = getLoweredAddress(indirectReturn);
|
||||||
TypeInfo const &ti = getFragileTypeInfo(indirectReturn.getType());
|
TypeInfo const &ti = getFragileTypeInfo(indirectReturn.getType());
|
||||||
emission.emitToMemory(a, ti);
|
emission.emitToMemory(a, ti);
|
||||||
@@ -862,29 +821,19 @@ void IRGenSILFunction::visitPartialApplyInst(swift::PartialApplyInst *i) {
|
|||||||
// specialized
|
// specialized
|
||||||
assert(i->getCallee().getType().castTo<FunctionType>()->isThin() &&
|
assert(i->getCallee().getType().castTo<FunctionType>()->isThin() &&
|
||||||
"can't closure a function that already has context");
|
"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();
|
Explosion llArgs(CurExplosionLevel);
|
||||||
SILFunctionTypeInfo *ti
|
|
||||||
= i->getCallee().getType().getFunctionTypeInfo();
|
|
||||||
|
|
||||||
Explosion args(CurExplosionLevel);
|
|
||||||
SmallVector<SILType, 8> argTypes;
|
SmallVector<SILType, 8> argTypes;
|
||||||
while (uncurryLevel-- != 0) {
|
for (SILValue arg : i->getArguments()) {
|
||||||
unsigned from = ti->getUncurriedInputBegins()[uncurryLevel],
|
emitApplyArgument(*this, llArgs, arg);
|
||||||
to = ti->getUncurriedInputEnds()[uncurryLevel];
|
// FIXME: Need to carry the address-ness of each argument alongside
|
||||||
for (SILValue arg : i->getArguments().slice(from, to - from)) {
|
// the object type's TypeInfo.
|
||||||
emitApplyArgument(*this, args, arg);
|
argTypes.push_back(arg.getType());
|
||||||
// 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.
|
// Create the thunk and function value.
|
||||||
Explosion function(CurExplosionLevel);
|
Explosion function(CurExplosionLevel);
|
||||||
emitFunctionPartialApplication(*this, calleeFn, args, argTypes,
|
emitFunctionPartialApplication(*this, calleeFn, llArgs, argTypes,
|
||||||
i->getType(), function);
|
i->getType(), function);
|
||||||
newLoweredExplosion(v, function);
|
newLoweredExplosion(v, function);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,8 @@ private:
|
|||||||
SILFunctionTypeInfo *ft);
|
SILFunctionTypeInfo *ft);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
OwnershipConventions() = default;
|
||||||
|
|
||||||
/// Derive the ownership conventions for a SILConstant.
|
/// Derive the ownership conventions for a SILConstant.
|
||||||
static OwnershipConventions get(SILGenFunction &gen,
|
static OwnershipConventions get(SILGenFunction &gen,
|
||||||
SILConstant c,
|
SILConstant c,
|
||||||
|
|||||||
@@ -585,12 +585,6 @@ public:
|
|||||||
LValue const &dest);
|
LValue const &dest);
|
||||||
ManagedValue emitMaterializedLoadFromLValue(SILLocation loc,
|
ManagedValue emitMaterializedLoadFromLValue(SILLocation loc,
|
||||||
LValue const &src);
|
LValue const &src);
|
||||||
ManagedValue emitSpecializedPropertyFunctionRef(
|
|
||||||
SILLocation loc,
|
|
||||||
SILConstant constant,
|
|
||||||
ArrayRef<Substitution> substitutions,
|
|
||||||
Type substPropertyType);
|
|
||||||
|
|
||||||
ManagedValue emitMethodRef(SILLocation loc,
|
ManagedValue emitMethodRef(SILLocation loc,
|
||||||
SILValue thisValue,
|
SILValue thisValue,
|
||||||
SILConstant methodConstant,
|
SILConstant methodConstant,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "SILGen.h"
|
#include "SILGen.h"
|
||||||
#include "OwnershipConventions.h"
|
#include "OwnershipConventions.h"
|
||||||
#include "RValue.h"
|
#include "RValue.h"
|
||||||
|
#include "swift/AST/ASTContext.h"
|
||||||
#include "swift/AST/Builtins.h"
|
#include "swift/AST/Builtins.h"
|
||||||
#include "swift/AST/Module.h"
|
#include "swift/AST/Module.h"
|
||||||
#include "swift/Basic/Range.h"
|
#include "swift/Basic/Range.h"
|
||||||
@@ -29,56 +30,169 @@ class CallEmission;
|
|||||||
class Callee {
|
class Callee {
|
||||||
public:
|
public:
|
||||||
enum class Kind {
|
enum class Kind {
|
||||||
/// A generic SIL value.
|
/// An indirect function value.
|
||||||
/// FIXME: We should use more specific kinds so we can emit curried calls
|
IndirectValue,
|
||||||
/// to methods.
|
/// A direct standalone function call, referenceable by a FunctionRefInst.
|
||||||
GenericValue,
|
|
||||||
/// A standalone function, referenceable by a FunctionRefInst.
|
|
||||||
StandaloneFunction,
|
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;
|
const Kind kind;
|
||||||
|
|
||||||
using SpecializedEmitter = ManagedValue (*)(SILGenFunction &,
|
using SpecializedEmitter = ManagedValue (*)(SILGenFunction &,
|
||||||
SILLocation,
|
SILLocation,
|
||||||
ArrayRef<Substitution>,
|
ArrayRef<Substitution>,
|
||||||
ArrayRef<ManagedValue>,
|
ArrayRef<ManagedValue>,
|
||||||
SGFContext);
|
SGFContext);
|
||||||
|
|
||||||
// Move, don't copy.
|
// Move, don't copy.
|
||||||
Callee(const Callee &) = delete;
|
Callee(const Callee &) = delete;
|
||||||
Callee &operator=(const Callee &) = delete;
|
Callee &operator=(const Callee &) = delete;
|
||||||
private:
|
private:
|
||||||
union {
|
union {
|
||||||
ManagedValue genericValue;
|
ManagedValue indirectValue;
|
||||||
SILConstant standaloneFunction;
|
SILConstant standaloneFunction;
|
||||||
|
struct {
|
||||||
|
SILValue thisValue;
|
||||||
|
SILConstant methodName;
|
||||||
|
} method;
|
||||||
|
struct {
|
||||||
|
SILValue thisValue;
|
||||||
|
SILConstant methodName;
|
||||||
|
CanType origType;
|
||||||
|
} genericMethod;
|
||||||
};
|
};
|
||||||
std::vector<Substitution> substitutions;
|
std::vector<Substitution> substitutions;
|
||||||
SILType specializedType;
|
// There is an initialization order dependency between genericMethod and
|
||||||
SpecializeExpr *specializeLoc = nullptr;
|
// specializedType.
|
||||||
OwnershipConventions ownership;
|
CanType specializedType;
|
||||||
|
SILLocation specializeLoc;
|
||||||
|
|
||||||
static SpecializedEmitter getSpecializedEmitterForSILBuiltin(SILConstant c);
|
static SpecializedEmitter getSpecializedEmitterForSILBuiltin(SILConstant c);
|
||||||
|
|
||||||
public:
|
Callee(ManagedValue indirectValue)
|
||||||
Callee(ManagedValue genericValue, OwnershipConventions &&ownership)
|
: kind(Kind::IndirectValue),
|
||||||
: kind(Kind::GenericValue), genericValue(genericValue),
|
indirectValue(indirectValue),
|
||||||
specializedType(genericValue.getType()),
|
specializedType(indirectValue.getType().getSwiftRValueType())
|
||||||
ownership(std::move(ownership))
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Callee(SILGenFunction &gen, SILConstant standaloneFunction)
|
Callee(SILGenFunction &gen, SILConstant standaloneFunction)
|
||||||
: kind(Kind::StandaloneFunction), standaloneFunction(standaloneFunction),
|
: kind(Kind::StandaloneFunction), standaloneFunction(standaloneFunction),
|
||||||
specializedType(gen.SGM.getConstantType(standaloneFunction)),
|
specializedType(
|
||||||
ownership(OwnershipConventions::get(gen, standaloneFunction,
|
gen.SGM.getConstantType(standaloneFunction.atUncurryLevel(0))
|
||||||
specializedType))
|
.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(Callee &&) = default;
|
||||||
Callee &operator=(Callee &&) = default;
|
Callee &operator=(Callee &&) = default;
|
||||||
|
|
||||||
void addSubstitutions(SILGenFunction &gen,
|
void addSubstitutions(SILGenFunction &gen,
|
||||||
SpecializeExpr *e,
|
SILLocation loc,
|
||||||
|
ArrayRef<Substitution> newSubs,
|
||||||
|
CanType subType,
|
||||||
unsigned callDepth) {
|
unsigned callDepth) {
|
||||||
// Currently generic methods of generic types are the deepest we should
|
// Currently generic methods of generic types are the deepest we should
|
||||||
// be able to stack specializations.
|
// be able to stack specializations.
|
||||||
@@ -86,76 +200,164 @@ public:
|
|||||||
// depth.
|
// depth.
|
||||||
assert(callDepth < 2 && "specialization below 'this' or argument depth?!");
|
assert(callDepth < 2 && "specialization below 'this' or argument depth?!");
|
||||||
substitutions.insert(substitutions.end(),
|
substitutions.insert(substitutions.end(),
|
||||||
e->getSubstitutions().begin(),
|
newSubs.begin(),
|
||||||
e->getSubstitutions().end());
|
newSubs.end());
|
||||||
// Save the type of the SpecializeExpr at the right depth in the type.
|
// Save the type of the SpecializeExpr at the right depth in the type.
|
||||||
assert(specializedType.getUncurryLevel() >= callDepth
|
assert(getNaturalUncurryLevel() >= callDepth
|
||||||
&& "specializations below uncurry level?!");
|
&& "specializations below uncurry level?!");
|
||||||
AbstractCC cc = specializedType.getFunctionCC();
|
AbstractCC cc = cast<AnyFunctionType>(specializedType)->getCC();
|
||||||
if (callDepth == 0) {
|
if (callDepth == 0) {
|
||||||
specializedType = gen.getLoweredLoadableType(
|
specializedType = getThinFunctionType(subType, cc)
|
||||||
getThinFunctionType(e->getType(),
|
->getCanonicalType();
|
||||||
cc),
|
|
||||||
specializedType.getUncurryLevel());
|
|
||||||
} else {
|
} else {
|
||||||
FunctionType *ft = specializedType.castTo<FunctionType>();
|
FunctionType *ft = cast<FunctionType>(specializedType);
|
||||||
Type outerInput = ft->getInput();
|
Type outerInput = ft->getInput();
|
||||||
Type newSpecialized = FunctionType::get(outerInput,
|
specializedType = CanType(FunctionType::get(outerInput,
|
||||||
e->getType(),
|
subType,
|
||||||
/*isAutoClosure*/ false,
|
/*isAutoClosure*/ false,
|
||||||
/*isBlock*/ false,
|
/*isBlock*/ false,
|
||||||
/*isThin*/ true,
|
/*isThin*/ true,
|
||||||
cc,
|
cc,
|
||||||
outerInput->getASTContext());
|
outerInput->getASTContext()));
|
||||||
specializedType = gen.getLoweredLoadableType(newSpecialized,
|
|
||||||
specializedType.getUncurryLevel());
|
|
||||||
}
|
}
|
||||||
specializeLoc = e;
|
specializeLoc = loc;
|
||||||
|
}
|
||||||
// Recalculate the ownership conventions because the substitutions may
|
|
||||||
// have changed the function signature.
|
void addSubstitutions(SILGenFunction &gen,
|
||||||
// FIXME: Currently only native methods can be specialized, so always use
|
SpecializeExpr *e,
|
||||||
// default ownership semantics.
|
unsigned callDepth) {
|
||||||
ownership = OwnershipConventions::getDefault(specializedType);
|
addSubstitutions(gen, e, e->getSubstitutions(),
|
||||||
|
e->getType()->getCanonicalType(), callDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned getNaturalUncurryLevel() const {
|
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;
|
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) {
|
switch (kind) {
|
||||||
case Kind::GenericValue:
|
case Kind::IndirectValue:
|
||||||
assert(level == genericValue.getType().getUncurryLevel()
|
assert(level == 0 && "can't curry indirect function");
|
||||||
&& "currying non-standalone function not yet supported");
|
mv = indirectValue;
|
||||||
mv = genericValue;
|
ownership = OwnershipConventions::getDefault(mv.getType());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Kind::StandaloneFunction: {
|
case Kind::StandaloneFunction: {
|
||||||
assert(level <= standaloneFunction.uncurryLevel
|
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);
|
SILConstant constant = standaloneFunction.atUncurryLevel(level);
|
||||||
SILValue ref = gen.emitGlobalFunctionRef(SILLocation(), constant);
|
SILValue ref = gen.emitGlobalFunctionRef(SILLocation(), constant);
|
||||||
mv = ManagedValue(ref, ManagedValue::Unmanaged);
|
mv = ManagedValue(ref, ManagedValue::Unmanaged);
|
||||||
|
ownership = OwnershipConventions::get(gen, constant, ref.getType());
|
||||||
break;
|
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 the callee needs to be specialized, do so.
|
||||||
if (specializeLoc) {
|
if (specializeLoc) {
|
||||||
|
SILType specializedUncurriedType
|
||||||
|
= gen.getLoweredLoadableType(specializedType, level);
|
||||||
|
|
||||||
CleanupsDepth cleanup = mv.getCleanup();
|
CleanupsDepth cleanup = mv.getCleanup();
|
||||||
SILValue spec = gen.B.createSpecialize(specializeLoc, mv.getValue(),
|
SILValue spec = gen.B.createSpecialize(specializeLoc, mv.getValue(),
|
||||||
substitutions, specializedType);
|
substitutions,
|
||||||
|
specializedUncurriedType);
|
||||||
mv = ManagedValue(spec, cleanup);
|
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;
|
return {mv, ownership};
|
||||||
}
|
|
||||||
|
|
||||||
OwnershipConventions const &getOwnershipConventions() const {
|
|
||||||
// FIXME: May need to adjust ownership conventions with uncurry level?
|
|
||||||
return ownership;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayRef<Substitution> getSubstitutions() const {
|
ArrayRef<Substitution> getSubstitutions() const {
|
||||||
@@ -176,10 +378,13 @@ public:
|
|||||||
= getSpecializedEmitterForSILBuiltin(standaloneFunction))
|
= getSpecializedEmitterForSILBuiltin(standaloneFunction))
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
case Kind::GenericValue:
|
case Kind::IndirectValue:
|
||||||
break;
|
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)
|
: gen(gen), sideEffect(nullptr), callDepth(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void setCallee(ManagedValue theCallee, OwnershipConventions &&ownership) {
|
void setCallee(Callee &&c) {
|
||||||
assert((thisParam ? callDepth == 1 : callDepth == 0)
|
assert((thisParam ? callDepth == 1 : callDepth == 0)
|
||||||
&& "setting callee at non-zero call depth?!");
|
&& "setting callee at non-zero call depth?!");
|
||||||
assert(!callee && "already set callee!");
|
assert(!callee && "already set callee!");
|
||||||
callee.emplace(theCallee, std::move(ownership));
|
callee.emplace(std::move(c));
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSideEffect(Expr *sideEffectExpr) {
|
void setSideEffect(Expr *sideEffectExpr) {
|
||||||
@@ -230,7 +428,7 @@ public:
|
|||||||
/// Fall back to an unknown, indirect callee.
|
/// Fall back to an unknown, indirect callee.
|
||||||
void visitExpr(Expr *e) {
|
void visitExpr(Expr *e) {
|
||||||
ManagedValue fn = gen.visit(e).getAsSingleValue(gen);
|
ManagedValue fn = gen.visit(e).getAsSingleValue(gen);
|
||||||
setCallee(fn, OwnershipConventions::getDefault(fn.getType()));
|
setCallee(Callee::forIndirect(fn));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a call site to the curry.
|
/// Add a call site to the curry.
|
||||||
@@ -268,13 +466,9 @@ public:
|
|||||||
SILConstant::ConstructAtNaturalUncurryLevel,
|
SILConstant::ConstructAtNaturalUncurryLevel,
|
||||||
gen.SGM.requiresObjCDispatch(fd));
|
gen.SGM.requiresObjCDispatch(fd));
|
||||||
|
|
||||||
SILValue classMethod = gen.B.createClassMethod(thisCallSite,
|
setCallee(Callee::forClassMethod(gen, thisParam.peekScalarValue(),
|
||||||
thisParam.peekScalarValue(),
|
constant));
|
||||||
constant,
|
|
||||||
gen.SGM.getConstantType(constant));
|
|
||||||
setCallee(ManagedValue(classMethod, ManagedValue::Unmanaged),
|
|
||||||
OwnershipConventions::get(gen, constant,
|
|
||||||
classMethod.getType()));
|
|
||||||
// setThisParam bumps the callDepth, but we aren't really past the
|
// setThisParam bumps the callDepth, but we aren't really past the
|
||||||
// 'this' call depth in this case.
|
// 'this' call depth in this case.
|
||||||
--callDepth;
|
--callDepth;
|
||||||
@@ -291,15 +485,15 @@ public:
|
|||||||
// Obtain a reference for a local closure.
|
// Obtain a reference for a local closure.
|
||||||
if (gen.LocalConstants.count(constant)) {
|
if (gen.LocalConstants.count(constant)) {
|
||||||
ManagedValue localFn = gen.emitReferenceToDecl(e, e->getDecl());
|
ManagedValue localFn = gen.emitReferenceToDecl(e, e->getDecl());
|
||||||
setCallee(localFn,
|
setCallee(Callee::forIndirect(localFn));
|
||||||
OwnershipConventions::getDefault(localFn.getType()));
|
|
||||||
}
|
}
|
||||||
// Otherwise, stash the SILConstant.
|
// Otherwise, stash the SILConstant.
|
||||||
else
|
else
|
||||||
setCallee(constant);
|
setCallee(Callee::forDirect(gen, constant));
|
||||||
}
|
}
|
||||||
void visitOtherConstructorDeclRefExpr(OtherConstructorDeclRefExpr *e) {
|
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) {
|
void visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *e) {
|
||||||
setSideEffect(e->getLHS());
|
setSideEffect(e->getLHS());
|
||||||
@@ -323,18 +517,20 @@ public:
|
|||||||
setThisParam(RValue(gen, existential));
|
setThisParam(RValue(gen, existential));
|
||||||
}
|
}
|
||||||
|
|
||||||
ManagedValue protoMethod(gen.emitProtocolMethod(e, existential.getValue()),
|
auto *fd = dyn_cast<FuncDecl>(e->getDecl());
|
||||||
ManagedValue::Unmanaged);
|
assert(fd && "existential properties not yet supported");
|
||||||
setCallee(protoMethod,
|
|
||||||
OwnershipConventions::getDefault(protoMethod.getType()));
|
setCallee(Callee::forProtocol(gen, existential.getValue(),
|
||||||
|
SILConstant(fd), e->getType()));
|
||||||
}
|
}
|
||||||
void visitArchetypeMemberRefExpr(ArchetypeMemberRefExpr *e) {
|
void visitArchetypeMemberRefExpr(ArchetypeMemberRefExpr *e) {
|
||||||
setThisParam(gen.visit(e->getBase()));
|
setThisParam(gen.visit(e->getBase()));
|
||||||
ManagedValue archeMethod(
|
|
||||||
gen.emitArchetypeMethod(e, thisParam.peekScalarValue()),
|
auto *fd = dyn_cast<FuncDecl>(e->getDecl());
|
||||||
ManagedValue::Unmanaged);
|
assert(fd && "archetype properties not yet supported");
|
||||||
setCallee(archeMethod,
|
|
||||||
OwnershipConventions::getDefault(archeMethod.getType()));
|
setCallee(Callee::forArchetype(gen, thisParam.peekScalarValue(),
|
||||||
|
SILConstant(fd), e->getType()));
|
||||||
}
|
}
|
||||||
void visitFunctionConversionExpr(FunctionConversionExpr *e) {
|
void visitFunctionConversionExpr(FunctionConversionExpr *e) {
|
||||||
visit(e->getSubExpr());
|
visit(e->getSubExpr());
|
||||||
@@ -377,26 +573,21 @@ public:
|
|||||||
llvm_unreachable("invalid super callee");
|
llvm_unreachable("invalid super callee");
|
||||||
|
|
||||||
// Upcast 'this' parameter to the super type.
|
// Upcast 'this' parameter to the super type.
|
||||||
SILType constantTy = gen.SGM.getConstantType(constant);
|
SILType superTy
|
||||||
SILType constantThisTy
|
= gen.getLoweredLoadableType(apply->getArg()->getType()->getRValueType());
|
||||||
= gen.getLoweredLoadableType(constantTy.castTo<FunctionType>()->getInput());
|
|
||||||
SILValue superUpcast = gen.B.createUpcast(apply->getArg(), super.getValue(),
|
SILValue superUpcast = gen.B.createUpcast(apply->getArg(), super.getValue(),
|
||||||
constantThisTy);
|
superTy);
|
||||||
|
|
||||||
setThisParam(RValue(gen, ManagedValue(superUpcast, super.getCleanup())));
|
setThisParam(RValue(gen, ManagedValue(superUpcast, super.getCleanup())));
|
||||||
|
|
||||||
SILValue superMethod;
|
SILValue superMethod;
|
||||||
if (constant.isObjC) {
|
if (constant.isObjC) {
|
||||||
// ObjC super calls require dynamic dispatch.
|
// ObjC super calls require dynamic dispatch.
|
||||||
superMethod = gen.B.createSuperMethod(apply, super.getValue(),
|
setCallee(Callee::forSuperMethod(gen, super.getValue(), constant));
|
||||||
constant, constantTy);
|
|
||||||
} else {
|
} else {
|
||||||
// Native Swift super calls are direct.
|
// 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() {
|
Callee getCallee() {
|
||||||
@@ -422,56 +613,58 @@ ManagedValue SILGenFunction::emitApply(SILLocation Loc,
|
|||||||
// Get the result type.
|
// Get the result type.
|
||||||
Type resultTy = Fn.getType().getFunctionResultType();
|
Type resultTy = Fn.getType().getFunctionResultType();
|
||||||
const TypeLoweringInfo &resultTI = getTypeLoweringInfo(resultTy);
|
const TypeLoweringInfo &resultTI = getTypeLoweringInfo(resultTy);
|
||||||
|
SILType instructionTy = resultTI.getLoweredType();
|
||||||
|
|
||||||
// Get the callee value.
|
// Get the callee value.
|
||||||
SILValue fnValue = Ownership.isCalleeConsumed()
|
SILValue fnValue = Ownership.isCalleeConsumed()
|
||||||
? Fn.forward(*this)
|
? Fn.forward(*this)
|
||||||
: Fn.getValue();
|
: Fn.getValue();
|
||||||
|
|
||||||
|
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.
|
// Gather the arguments.
|
||||||
SmallVector<SILValue, 4> argValues;
|
|
||||||
for (size_t i = 0; i < Args.size(); ++i)
|
for (size_t i = 0; i < Args.size(); ++i)
|
||||||
argValues.push_back(
|
argValues.push_back(
|
||||||
forwardIfConsumed(Args[i], Ownership.isArgumentConsumed(i)));
|
forwardIfConsumed(Args[i], Ownership.isArgumentConsumed(i)));
|
||||||
|
|
||||||
if (resultTI.isAddressOnly(F.getModule())) {
|
SILValue result = B.createApply(Loc, fnValue, instructionTy, argValues);
|
||||||
// Allocate a temporary to house the indirect return, and pass it to the
|
|
||||||
// function as an implicit argument.
|
if (indirectReturn) {
|
||||||
SILValue buffer = getBufferForExprResult(Loc, resultTI.getLoweredType(), C);
|
|
||||||
argValues.push_back(buffer);
|
|
||||||
B.createApply(Loc, fnValue, SGM.Types.getEmptyTupleType(),
|
|
||||||
argValues);
|
|
||||||
|
|
||||||
/// FIXME: Can ObjC/C functions return types SIL considers address-only?
|
/// FIXME: Can ObjC/C functions return types SIL considers address-only?
|
||||||
/// Do we need to copy here if the return value is Unretained?
|
/// Do we need to copy here if the return value is Unretained?
|
||||||
return emitManagedRValueWithCleanup(buffer);
|
assert(Ownership.getReturn() == OwnershipConventions::Return::Retained
|
||||||
} else {
|
&& "address-only result with non-Retained ownership not implemented");
|
||||||
// Receive the result by value.
|
return emitManagedRValueWithCleanup(indirectReturn);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 {
|
namespace {
|
||||||
@@ -585,17 +778,38 @@ namespace {
|
|||||||
= callee.getSpecializedEmitter(uncurryLevel);
|
= callee.getSpecializedEmitter(uncurryLevel);
|
||||||
|
|
||||||
ManagedValue calleeValue;
|
ManagedValue calleeValue;
|
||||||
if (!specializedEmitter)
|
OwnershipConventions ownership;
|
||||||
calleeValue = callee.getAtUncurryLevel(gen, uncurryLevel);
|
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.
|
// Collect the arguments to the uncurried call.
|
||||||
SmallVector<ManagedValue, 4> args;
|
SmallVector<SmallVector<ManagedValue, 4>, 2> args;
|
||||||
SILLocation uncurriedLoc;
|
SILLocation uncurriedLoc;
|
||||||
for (auto &site : uncurriedSites) {
|
for (auto &site : uncurriedSites) {
|
||||||
uncurriedLoc = site.loc;
|
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
|
// We use the context emit-into initialization only for the outermost
|
||||||
// call.
|
// call.
|
||||||
SGFContext uncurriedContext = extraSites.empty() ? C : SGFContext();
|
SGFContext uncurriedContext = extraSites.empty() ? C : SGFContext();
|
||||||
@@ -607,22 +821,19 @@ namespace {
|
|||||||
result = specializedEmitter(gen,
|
result = specializedEmitter(gen,
|
||||||
uncurriedLoc,
|
uncurriedLoc,
|
||||||
callee.getSubstitutions(),
|
callee.getSubstitutions(),
|
||||||
args,
|
uncurriedArgs,
|
||||||
uncurriedContext);
|
uncurriedContext);
|
||||||
else
|
else
|
||||||
result = gen.emitApply(uncurriedLoc, calleeValue, args,
|
result = gen.emitApply(uncurriedLoc, calleeValue, uncurriedArgs,
|
||||||
callee.getOwnershipConventions(),
|
ownership, uncurriedContext);
|
||||||
uncurriedContext);
|
|
||||||
|
|
||||||
// If there are remaining call sites, apply them to the result function.
|
// If there are remaining call sites, apply them to the result function.
|
||||||
for (unsigned i = 0, size = extraSites.size(); i < size; ++i) {
|
for (unsigned i = 0, size = extraSites.size(); i < size; ++i) {
|
||||||
args.clear();
|
uncurriedArgs.clear();
|
||||||
SILLocation loc = extraSites[i].loc;
|
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();
|
SGFContext context = i == size - 1 ? C : SGFContext();
|
||||||
result = gen.emitApply(loc, result, args,
|
result = gen.emitApply(loc, result, uncurriedArgs, ownership, context);
|
||||||
callee.getOwnershipConventions(),
|
|
||||||
context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -969,7 +1180,7 @@ ManagedValue SILGenFunction::emitArrayInjectionCall(ManagedValue ObjectPtr,
|
|||||||
return emission.apply();
|
return emission.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
ManagedValue SILGenFunction::emitSpecializedPropertyFunctionRef(
|
Callee emitSpecializedPropertyFunctionRef(SILGenFunction &gen,
|
||||||
SILLocation loc,
|
SILLocation loc,
|
||||||
SILConstant constant,
|
SILConstant constant,
|
||||||
ArrayRef<Substitution> substitutions,
|
ArrayRef<Substitution> substitutions,
|
||||||
@@ -977,33 +1188,28 @@ ManagedValue SILGenFunction::emitSpecializedPropertyFunctionRef(
|
|||||||
{
|
{
|
||||||
// If the accessor is a local constant, use it.
|
// If the accessor is a local constant, use it.
|
||||||
// FIXME: Can local properties ever be generic?
|
// FIXME: Can local properties ever be generic?
|
||||||
if (LocalConstants.count(constant)) {
|
if (gen.LocalConstants.count(constant)) {
|
||||||
SILValue v = LocalConstants[constant];
|
SILValue v = gen.LocalConstants[constant];
|
||||||
emitRetainRValue(loc, v);
|
gen.emitRetainRValue(loc, v);
|
||||||
return emitManagedRValueWithCleanup(v);
|
return Callee::forIndirect(gen.emitManagedRValueWithCleanup(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the accessor function. The type will be a polymorphic function if
|
// Get the accessor function. The type will be a polymorphic function if
|
||||||
// the This type is generic.
|
// 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
|
// FIXME: Generic subscript operator could add another layer of
|
||||||
// substitutions.
|
// substitutions.
|
||||||
if (!substitutions.empty()) {
|
if (!substitutions.empty()) {
|
||||||
assert(method.getType().is<PolymorphicFunctionType>() &&
|
|
||||||
"generic getter is not of a poly function type");
|
|
||||||
substPropertyType = getThinFunctionType(substPropertyType,
|
substPropertyType = getThinFunctionType(substPropertyType,
|
||||||
SGM.getConstantCC(constant));
|
gen.SGM.getConstantCC(constant));
|
||||||
SILType loweredPropertyType = getLoweredLoadableType(substPropertyType,
|
|
||||||
constant.uncurryLevel);
|
|
||||||
|
|
||||||
method = B.createSpecialize(loc, method, substitutions,
|
callee.addSubstitutions(gen, loc, substitutions,
|
||||||
loweredPropertyType);
|
substPropertyType->getCanonicalType(), 0);
|
||||||
}
|
}
|
||||||
assert(method.getType().is<FunctionType>() &&
|
return callee;
|
||||||
"getter is not of a concrete function type");
|
|
||||||
return ManagedValue(method, ManagedValue::Unmanaged);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit a call to a getter and materialize its result.
|
/// 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 = tc.getMethodTypeInContext(thisValue.getType()->getRValueType(),
|
||||||
propType);
|
propType);
|
||||||
|
|
||||||
ManagedValue getter = emitSpecializedPropertyFunctionRef(loc, get,
|
Callee getter = emitSpecializedPropertyFunctionRef(*this, loc, get,
|
||||||
substitutions,
|
substitutions, propType);
|
||||||
propType);
|
|
||||||
|
|
||||||
CallEmission emission(*this, Callee(getter,
|
CallEmission emission(*this, std::move(getter));
|
||||||
OwnershipConventions::get(*this, get,
|
|
||||||
getter.getType())));
|
|
||||||
// This ->
|
// This ->
|
||||||
if (thisValue)
|
if (thisValue)
|
||||||
emission.addCallSite(loc, std::move(thisValue));
|
emission.addCallSite(loc, std::move(thisValue));
|
||||||
@@ -1066,13 +1269,10 @@ void SILGenFunction::emitSetProperty(SILLocation loc,
|
|||||||
propType = tc.getMethodTypeInContext(thisValue.getType()->getRValueType(),
|
propType = tc.getMethodTypeInContext(thisValue.getType()->getRValueType(),
|
||||||
propType);
|
propType);
|
||||||
|
|
||||||
ManagedValue setter = emitSpecializedPropertyFunctionRef(loc, set,
|
Callee setter = emitSpecializedPropertyFunctionRef(*this, loc, set,
|
||||||
substitutions,
|
substitutions, propType);
|
||||||
propType);
|
|
||||||
|
|
||||||
CallEmission emission(*this, Callee(setter,
|
CallEmission emission(*this, std::move(setter));
|
||||||
OwnershipConventions::get(*this, set,
|
|
||||||
setter.getType())));
|
|
||||||
// This ->
|
// This ->
|
||||||
if (thisValue)
|
if (thisValue)
|
||||||
emission.addCallSite(loc, std::move(thisValue));
|
emission.addCallSite(loc, std::move(thisValue));
|
||||||
@@ -1083,4 +1283,4 @@ void SILGenFunction::emitSetProperty(SILLocation loc,
|
|||||||
emission.addCallSite(loc, std::move(setValue));
|
emission.addCallSite(loc, std::move(setValue));
|
||||||
// ()
|
// ()
|
||||||
emission.apply();
|
emission.apply();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -571,33 +571,46 @@ static void makeCaptureSILArguments(SILGenFunction &gen, ValueDecl *capture) {
|
|||||||
void SILGenFunction::emitProlog(CapturingExpr *ce,
|
void SILGenFunction::emitProlog(CapturingExpr *ce,
|
||||||
ArrayRef<Pattern*> paramPatterns,
|
ArrayRef<Pattern*> paramPatterns,
|
||||||
Type resultType) {
|
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.
|
// become the first curry level of the SIL function.
|
||||||
for (auto capture : ce->getCaptures()) {
|
for (auto capture : ce->getCaptures()) {
|
||||||
makeCaptureSILArguments(*this, capture);
|
makeCaptureSILArguments(*this, capture);
|
||||||
}
|
}
|
||||||
|
|
||||||
emitProlog(paramPatterns, resultType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SILGenFunction::emitProlog(ArrayRef<Pattern *> paramPatterns,
|
void SILGenFunction::emitProlog(ArrayRef<Pattern *> paramPatterns,
|
||||||
Type resultType) {
|
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.
|
// If the return type is address-only, emit the indirect return argument.
|
||||||
const TypeLoweringInfo &returnTI = getTypeLoweringInfo(resultType);
|
const TypeLoweringInfo &returnTI = getTypeLoweringInfo(resultType);
|
||||||
if (returnTI.isAddressOnly(SGM.M)) {
|
if (returnTI.isAddressOnly(SGM.M)) {
|
||||||
IndirectReturnAddress = new (SGM.M) SILArgument(returnTI.getLoweredType(),
|
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);
|
auto ownership = OwnershipConventions::get(*this, thunk, thunkTy);
|
||||||
|
|
||||||
SmallVector<SILValue, 4> args;
|
SmallVector<SILValue, 4> args;
|
||||||
|
|
||||||
SILFunctionTypeInfo *info = thunkTy.getFunctionTypeInfo();
|
SILFunctionTypeInfo *info = thunkTy.getFunctionTypeInfo();
|
||||||
|
if (info->hasIndirectReturn()) {
|
||||||
|
args.push_back(new(F.getModule()) SILArgument(info->getIndirectReturnType(),
|
||||||
|
F.begin()));
|
||||||
|
}
|
||||||
|
|
||||||
ArrayRef<SILType> inputs
|
ArrayRef<SILType> inputs
|
||||||
= info->getInputTypesWithoutIndirectReturnType();
|
= info->getInputTypesWithoutIndirectReturnType();
|
||||||
for (unsigned i = 0, e = inputs.size(); i < e; ++i) {
|
for (unsigned i = 0, e = inputs.size(); i < e; ++i) {
|
||||||
@@ -1031,10 +1048,11 @@ void SILGenFunction::emitObjCMethodThunk(SILConstant thunk) {
|
|||||||
args.push_back(arg);
|
args.push_back(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->hasIndirectReturn()) {
|
// Reorder the 'this' argument for the Swift calling convention.
|
||||||
args.push_back(new (F.getModule()) SILArgument(info->getIndirectReturnType(),
|
size_t thisIndex = info->hasIndirectReturn() ? 1 : 0;
|
||||||
F.begin()));
|
SILValue thisArg = args[thisIndex];
|
||||||
}
|
args.erase(args.begin() + thisIndex);
|
||||||
|
args.push_back(thisArg);
|
||||||
|
|
||||||
// Call the native entry point.
|
// Call the native entry point.
|
||||||
SILValue nativeFn = emitGlobalFunctionRef(thunk.getDecl(),
|
SILValue nativeFn = emitGlobalFunctionRef(thunk.getDecl(),
|
||||||
@@ -1051,17 +1069,17 @@ void SILGenFunction::emitObjCPropertyGetter(SILConstant getter) {
|
|||||||
auto ownership = OwnershipConventions::get(*this, getter, thunkTy);
|
auto ownership = OwnershipConventions::get(*this, getter, thunkTy);
|
||||||
SILFunctionTypeInfo *info = thunkTy.getFunctionTypeInfo();
|
SILFunctionTypeInfo *info = thunkTy.getFunctionTypeInfo();
|
||||||
|
|
||||||
SILValue thisValue
|
|
||||||
= new (F.getModule()) SILArgument(info->getInputTypes()[0], F.begin());
|
|
||||||
SILValue indirectReturn;
|
SILValue indirectReturn;
|
||||||
SILType resultType;
|
SILType resultType;
|
||||||
if (info->hasIndirectReturn()) {
|
if (info->hasIndirectReturn()) {
|
||||||
indirectReturn = new (F.getModule()) SILArgument(info->getIndirectReturnType(),
|
indirectReturn
|
||||||
F.begin());
|
= new(F.getModule()) SILArgument(info->getIndirectReturnType(),F.begin());
|
||||||
resultType = indirectReturn.getType();
|
resultType = indirectReturn.getType();
|
||||||
} else {
|
} else {
|
||||||
resultType = info->getResultType();
|
resultType = info->getResultType();
|
||||||
}
|
}
|
||||||
|
SILValue thisValue
|
||||||
|
= new (F.getModule()) SILArgument(info->getInputTypes()[0], F.begin());
|
||||||
|
|
||||||
auto *var = cast<VarDecl>(getter.getDecl());
|
auto *var = cast<VarDecl>(getter.getDecl());
|
||||||
if (var->isProperty()) {
|
if (var->isProperty()) {
|
||||||
@@ -1069,9 +1087,9 @@ void SILGenFunction::emitObjCPropertyGetter(SILConstant getter) {
|
|||||||
if (!ownership.isArgumentConsumed(0))
|
if (!ownership.isArgumentConsumed(0))
|
||||||
emitObjCUnconsumedArgument(*this, var, thisValue);
|
emitObjCUnconsumedArgument(*this, var, thisValue);
|
||||||
SmallVector<SILValue, 2> args;
|
SmallVector<SILValue, 2> args;
|
||||||
args.push_back(thisValue);
|
|
||||||
if (indirectReturn)
|
if (indirectReturn)
|
||||||
args.push_back(indirectReturn);
|
args.push_back(indirectReturn);
|
||||||
|
args.push_back(thisValue);
|
||||||
SILValue nativeFn = emitGlobalFunctionRef(var, getter.asObjC(false));
|
SILValue nativeFn = emitGlobalFunctionRef(var, getter.asObjC(false));
|
||||||
SILValue result = B.createApply(var, nativeFn, info->getResultType(), args);
|
SILValue result = B.createApply(var, nativeFn, info->getResultType(), args);
|
||||||
emitObjCReturnValue(*this, var, result, ownership);
|
emitObjCReturnValue(*this, var, result, ownership);
|
||||||
@@ -1123,8 +1141,8 @@ void SILGenFunction::emitObjCPropertySetter(SILConstant setter) {
|
|||||||
if (!ownership.isArgumentConsumed(1))
|
if (!ownership.isArgumentConsumed(1))
|
||||||
emitObjCUnconsumedArgument(*this, var, setValue);
|
emitObjCUnconsumedArgument(*this, var, setValue);
|
||||||
SmallVector<SILValue, 2> args;
|
SmallVector<SILValue, 2> args;
|
||||||
args.push_back(thisValue);
|
|
||||||
args.push_back(setValue);
|
args.push_back(setValue);
|
||||||
|
args.push_back(thisValue);
|
||||||
SILValue nativeFn = emitGlobalFunctionRef(var, setter.asObjC(false));
|
SILValue nativeFn = emitGlobalFunctionRef(var, setter.asObjC(false));
|
||||||
SILValue result = B.createApply(var, nativeFn, info->getResultType(), args);
|
SILValue result = B.createApply(var, nativeFn, info->getResultType(), args);
|
||||||
// Result should always be void.
|
// Result should always be void.
|
||||||
@@ -1149,5 +1167,4 @@ void SILGenFunction::emitObjCPropertySetter(SILConstant setter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
B.createReturn(var, emitEmptyTuple(var));
|
B.createReturn(var, emitEmptyTuple(var));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -664,9 +664,9 @@ ManagedValue SILGenFunction::emitMethodRef(SILLocation loc,
|
|||||||
// FIXME: Emit dynamic dispatch instruction (class_method, super_method, etc.)
|
// FIXME: Emit dynamic dispatch instruction (class_method, super_method, etc.)
|
||||||
// if needed.
|
// if needed.
|
||||||
|
|
||||||
SILType methodType = SGM.getConstantType(methodConstant);
|
|
||||||
SILValue methodValue = B.createFunctionRef(loc,
|
SILValue methodValue = B.createFunctionRef(loc,
|
||||||
SGM.getFunction(methodConstant));
|
SGM.getFunction(methodConstant));
|
||||||
|
SILType methodType = SGM.getConstantType(methodConstant.atUncurryLevel(0));
|
||||||
|
|
||||||
/// If the 'this' type is a bound generic, specialize the method ref with
|
/// If the 'this' type is a bound generic, specialize the method ref with
|
||||||
/// its substitutions.
|
/// its substitutions.
|
||||||
@@ -717,7 +717,7 @@ ManagedValue SILGenFunction::emitMethodRef(SILLocation loc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
SILType specType = getLoweredLoadableType(outerMethodTy,
|
SILType specType = getLoweredLoadableType(outerMethodTy,
|
||||||
methodValue.getType().getUncurryLevel());
|
methodConstant.uncurryLevel);
|
||||||
|
|
||||||
methodValue = B.createSpecialize(loc, methodValue, allSubs, specType);
|
methodValue = B.createSpecialize(loc, methodValue, allSubs, specType);
|
||||||
}
|
}
|
||||||
@@ -1118,8 +1118,7 @@ ManagedValue SILGenFunction::emitClosureForCapturingExpr(SILLocation loc,
|
|||||||
&& "curried local functions not yet supported");
|
&& "curried local functions not yet supported");
|
||||||
|
|
||||||
auto captures = body->getCaptures();
|
auto captures = body->getCaptures();
|
||||||
if (!captures.empty()) {
|
if (!captures.empty()) {
|
||||||
|
|
||||||
llvm::SmallVector<SILValue, 4> capturedArgs;
|
llvm::SmallVector<SILValue, 4> capturedArgs;
|
||||||
for (ValueDecl *capture : captures) {
|
for (ValueDecl *capture : captures) {
|
||||||
switch (getDeclCaptureKind(capture)) {
|
switch (getDeclCaptureKind(capture)) {
|
||||||
@@ -1168,9 +1167,7 @@ ManagedValue SILGenFunction::emitClosureForCapturingExpr(SILLocation loc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
SILValue functionRef = emitGlobalFunctionRef(loc, constant);
|
SILValue functionRef = emitGlobalFunctionRef(loc, constant);
|
||||||
Type closureSwiftTy
|
SILType closureTy = getLoweredLoadableType(body->getType());
|
||||||
= functionRef.getType().getAs<AnyFunctionType>()->getResult();
|
|
||||||
SILType closureTy = getLoweredLoadableType(closureSwiftTy);
|
|
||||||
return emitManagedRValueWithCleanup(
|
return emitManagedRValueWithCleanup(
|
||||||
B.createPartialApply(loc, functionRef, capturedArgs,
|
B.createPartialApply(loc, functionRef, capturedArgs,
|
||||||
closureTy));
|
closureTy));
|
||||||
@@ -1390,8 +1387,11 @@ static void emitImplicitValueConstructor(SILGenFunction &gen,
|
|||||||
return emitImplicitValueDefaultConstructor(gen, ctor);
|
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.
|
// Emit the elementwise arguments.
|
||||||
SmallVector<RValue, 4> elements;
|
SmallVector<RValue, 4> elements;
|
||||||
for (size_t i = 0; i < TP->getFields().size(); ++i) {
|
for (size_t i = 0; i < TP->getFields().size(); ++i) {
|
||||||
@@ -1400,13 +1400,12 @@ static void emitImplicitValueConstructor(SILGenFunction &gen,
|
|||||||
elements.push_back(
|
elements.push_back(
|
||||||
emitImplicitValueConstructorArg(gen, ctor, P->getType()));
|
emitImplicitValueConstructorArg(gen, ctor, P->getType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emitConstructorMetatypeArg(gen, ctor);
|
||||||
|
|
||||||
// If we have an indirect return slot, initialize it in-place in the implicit
|
// If we have an indirect return slot, initialize it in-place in the implicit
|
||||||
// return slot.
|
// return slot.
|
||||||
if (thisTy.isAddressOnly(gen.SGM.M)) {
|
if (resultSlot) {
|
||||||
SILValue resultSlot
|
|
||||||
= new (gen.F.getModule()) SILArgument(thisTy, gen.F.begin());
|
|
||||||
|
|
||||||
auto *decl = cast<StructDecl>(thisTy.getSwiftRValueType()
|
auto *decl = cast<StructDecl>(thisTy.getSwiftRValueType()
|
||||||
->getNominalOrBoundGenericNominal());
|
->getNominalOrBoundGenericNominal());
|
||||||
unsigned memberIndex = 0;
|
unsigned memberIndex = 0;
|
||||||
@@ -1459,8 +1458,8 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
|
|||||||
return emitImplicitValueConstructor(*this, ctor);
|
return emitImplicitValueConstructor(*this, ctor);
|
||||||
|
|
||||||
// Emit the prolog.
|
// Emit the prolog.
|
||||||
emitConstructorMetatypeArg(*this, ctor);
|
|
||||||
emitProlog(ctor->getArguments(), ctor->getImplicitThisDecl()->getType());
|
emitProlog(ctor->getArguments(), ctor->getImplicitThisDecl()->getType());
|
||||||
|
emitConstructorMetatypeArg(*this, ctor);
|
||||||
|
|
||||||
// Get the 'this' decl and type.
|
// Get the 'this' decl and type.
|
||||||
VarDecl *thisDecl = ctor->getImplicitThisDecl();
|
VarDecl *thisDecl = ctor->getImplicitThisDecl();
|
||||||
@@ -1592,10 +1591,14 @@ namespace {
|
|||||||
void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) {
|
void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) {
|
||||||
// Emit the prolog. Since we're just going to forward our args directly
|
// Emit the prolog. Since we're just going to forward our args directly
|
||||||
// to the initializer, don't allocate local variables for them.
|
// to the initializer, don't allocate local variables for them.
|
||||||
emitConstructorMetatypeArg(*this, ctor);
|
|
||||||
|
|
||||||
SmallVector<SILValue, 8> args;
|
SmallVector<SILValue, 8> args;
|
||||||
|
|
||||||
|
// Forward the constructor arguments.
|
||||||
|
ArgumentForwardVisitor(*this, args).visit(ctor->getArguments());
|
||||||
|
|
||||||
|
emitConstructorMetatypeArg(*this, ctor);
|
||||||
|
|
||||||
// Allocate the "this" value.
|
// Allocate the "this" value.
|
||||||
VarDecl *thisDecl = ctor->getImplicitThisDecl();
|
VarDecl *thisDecl = ctor->getImplicitThisDecl();
|
||||||
SILType thisTy = getLoweredType(thisDecl->getType());
|
SILType thisTy = getLoweredType(thisDecl->getType());
|
||||||
@@ -1616,9 +1619,6 @@ void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) {
|
|||||||
}
|
}
|
||||||
args.push_back(thisValue);
|
args.push_back(thisValue);
|
||||||
|
|
||||||
// Forward the constructor arguments.
|
|
||||||
ArgumentForwardVisitor(*this, args).visit(ctor->getArguments());
|
|
||||||
|
|
||||||
// Call the initializer.
|
// Call the initializer.
|
||||||
SILConstant initConstant = SILConstant(ctor, SILConstant::Kind::Initializer);
|
SILConstant initConstant = SILConstant(ctor, SILConstant::Kind::Initializer);
|
||||||
ManagedValue initVal = emitMethodRef(ctor, thisValue, initConstant,
|
ManagedValue initVal = emitMethodRef(ctor, thisValue, initConstant,
|
||||||
@@ -1653,6 +1653,9 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
|
|||||||
if (!ctor->getBody())
|
if (!ctor->getBody())
|
||||||
return emitClassImplicitConstructorInitializer(*this, ctor);
|
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.
|
// Emit the 'this' argument and make an lvalue for it.
|
||||||
VarDecl *thisDecl = ctor->getImplicitThisDecl();
|
VarDecl *thisDecl = ctor->getImplicitThisDecl();
|
||||||
SILType thisTy = getLoweredLoadableType(thisDecl->getType());
|
SILType thisTy = getLoweredLoadableType(thisDecl->getType());
|
||||||
@@ -1666,9 +1669,6 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
|
|||||||
SILValue thisLV = VarLocs[thisDecl].address;
|
SILValue thisLV = VarLocs[thisDecl].address;
|
||||||
emitStore(ctor, ManagedValue(thisArg, ManagedValue::Unmanaged), thisLV);
|
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.
|
// 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.
|
// We won't emit the block until after we've emitted the body.
|
||||||
epilogBB = new (SGM.M) SILBasicBlock(&F);
|
epilogBB = new (SGM.M) SILBasicBlock(&F);
|
||||||
@@ -1747,17 +1747,35 @@ void SILGenFunction::emitCurryThunk(FuncExpr *fe,
|
|||||||
|
|
||||||
unsigned paramCount = from.uncurryLevel + 1;
|
unsigned paramCount = from.uncurryLevel + 1;
|
||||||
|
|
||||||
// If the function has implicit closure context arguments, forward them.
|
/// Forward implicit closure context arguments.
|
||||||
if (!fe->getCaptures().empty()) {
|
bool hasCaptures = !fe->getCaptures().empty();
|
||||||
for (auto capture : fe->getCaptures())
|
if (hasCaptures)
|
||||||
forwardCaptureArgs(*this, curriedArgs, capture);
|
|
||||||
--paramCount;
|
--paramCount;
|
||||||
}
|
|
||||||
|
auto forwardCaptures = [&] {
|
||||||
|
if (hasCaptures)
|
||||||
|
for (auto capture : fe->getCaptures())
|
||||||
|
forwardCaptureArgs(*this, curriedArgs, capture);
|
||||||
|
};
|
||||||
|
|
||||||
// Forward the curried formal arguments.
|
// Forward the curried formal arguments.
|
||||||
|
auto forwardedPatterns = fe->getBodyParamPatterns().slice(0, paramCount);
|
||||||
ArgumentForwardVisitor forwarder(*this, curriedArgs);
|
ArgumentForwardVisitor forwarder(*this, curriedArgs);
|
||||||
for (auto *paramPattern : fe->getBodyParamPatterns().slice(0, paramCount))
|
UncurryDirection direction
|
||||||
forwarder.visit(paramPattern);
|
= 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.
|
// 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) {
|
SILValue SILGenFunction::emitGeneralizedValue(SILLocation loc, SILValue v) {
|
||||||
assert(v.getType().getUncurryLevel() == 0 &&
|
|
||||||
"uncurried functions shouldn't be used as swift values");
|
|
||||||
// Thicken thin functions.
|
// Thicken thin functions.
|
||||||
if (v.getType().is<AnyFunctionType>() &&
|
if (v.getType().is<AnyFunctionType>() &&
|
||||||
v.getType().castTo<AnyFunctionType>()->isThin()) {
|
v.getType().castTo<AnyFunctionType>()->isThin()) {
|
||||||
|
|||||||
@@ -120,12 +120,6 @@ void SILType::print(raw_ostream &OS) const {
|
|||||||
if (is<AnyFunctionType>()) {
|
if (is<AnyFunctionType>()) {
|
||||||
auto info = getFunctionTypeInfo();
|
auto info = getFunctionTypeInfo();
|
||||||
|
|
||||||
if (info->getUncurryLevel()) {
|
|
||||||
if (!Attributes.empty()) Attributes += ", ";
|
|
||||||
Attributes += "sil_uncurry=";
|
|
||||||
Attributes += llvm::utostr(info->getUncurryLevel());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info->hasIndirectReturn()) {
|
if (info->hasIndirectReturn()) {
|
||||||
if (!Attributes.empty()) Attributes += ", ";
|
if (!Attributes.empty()) Attributes += ", ";
|
||||||
Attributes += "sil_sret";
|
Attributes += "sil_sret";
|
||||||
@@ -677,15 +671,6 @@ void SILFunction::dump() const {
|
|||||||
|
|
||||||
/// Pretty-print the SILFunction to the designated stream.
|
/// Pretty-print the SILFunction to the designated stream.
|
||||||
void SILFunction::print(llvm::raw_ostream &OS) const {
|
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 ";
|
OS << "sil ";
|
||||||
switch (getLinkage()) {
|
switch (getLinkage()) {
|
||||||
case SILLinkage::Internal:
|
case SILLinkage::Internal:
|
||||||
|
|||||||
@@ -79,32 +79,20 @@ bool SILType::isAddressOnly(CanType Ty, SILModule &M) {
|
|||||||
SILFunctionTypeInfo *SILFunctionTypeInfo::create(CanType swiftType,
|
SILFunctionTypeInfo *SILFunctionTypeInfo::create(CanType swiftType,
|
||||||
ArrayRef<SILType> inputTypes,
|
ArrayRef<SILType> inputTypes,
|
||||||
SILType resultType,
|
SILType resultType,
|
||||||
ArrayRef<unsigned> uncurriedInputCounts,
|
|
||||||
bool hasIndirectReturn,
|
bool hasIndirectReturn,
|
||||||
SILModule &M) {
|
SILModule &M) {
|
||||||
// We allocate room for an extra unsigned in the uncurriedInputCounts array,
|
// 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
|
// 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.
|
// return both the begins and ends of each uncurried argument group.
|
||||||
void *buffer = M.allocate(sizeof(SILFunctionTypeInfo)
|
void *buffer = M.allocate(sizeof(SILFunctionTypeInfo)
|
||||||
+ sizeof(SILType)*inputTypes.size()
|
+ sizeof(SILType)*inputTypes.size(),
|
||||||
+ sizeof(unsigned)*(1+uncurriedInputCounts.size()),
|
alignof(SILFunctionTypeInfo));
|
||||||
alignof(SILFunctionTypeInfo));
|
|
||||||
SILFunctionTypeInfo *fi = ::new (buffer) SILFunctionTypeInfo(
|
SILFunctionTypeInfo *fi = ::new (buffer) SILFunctionTypeInfo(
|
||||||
swiftType,
|
swiftType,
|
||||||
inputTypes.size(),
|
inputTypes.size(),
|
||||||
resultType,
|
resultType,
|
||||||
uncurriedInputCounts.size(),
|
|
||||||
hasIndirectReturn);
|
hasIndirectReturn);
|
||||||
memcpy(fi->getInputTypeBuffer(), inputTypes.data(),
|
memcpy(fi->getInputTypeBuffer(), inputTypes.data(),
|
||||||
sizeof(SILType) * inputTypes.size());
|
sizeof(SILType) * inputTypes.size());
|
||||||
fi->getUncurryBuffer()[0] = 0;
|
|
||||||
memcpy(fi->getUncurryBuffer()+1, uncurriedInputCounts.data(),
|
|
||||||
sizeof(unsigned) * uncurriedInputCounts.size());
|
|
||||||
return fi;
|
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 swift;
|
||||||
using namespace Lowering;
|
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) {
|
unsigned uncurryLevel) {
|
||||||
if (uncurryLevel == 0)
|
if (uncurryLevel == 0)
|
||||||
return t;
|
return t;
|
||||||
@@ -73,17 +85,10 @@ AnyFunctionType *TypeConverter::uncurryFunctionType(AnyFunctionType *t,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Put the inputs in the order expected by the calling convention.
|
// Put the inputs in the order expected by the calling convention.
|
||||||
switch (outerCC) {
|
switch (getUncurryDirection(outerCC)) {
|
||||||
case AbstractCC::C:
|
case UncurryDirection::LeftToRight:
|
||||||
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");
|
|
||||||
break;
|
break;
|
||||||
|
case UncurryDirection::RightToLeft:
|
||||||
case AbstractCC::Freestanding:
|
|
||||||
case AbstractCC::Method:
|
|
||||||
// Swift functions uncurry right-to-left.
|
|
||||||
std::reverse(inputs.begin(), inputs.end());
|
std::reverse(inputs.begin(), inputs.end());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -274,22 +279,10 @@ namespace {
|
|||||||
};
|
};
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
||||||
SILFunctionTypeInfo *TypeConverter::makeInfoForFunctionType(AnyFunctionType *ft,
|
SILFunctionTypeInfo *TypeConverter::makeInfoForFunctionType(AnyFunctionType *ft)
|
||||||
unsigned uncurries)
|
|
||||||
{
|
{
|
||||||
CanType topType(ft);
|
|
||||||
SmallVector<SILType, 8> inputTypes;
|
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
|
// If the result type lowers to an address-only type, add it as an indirect
|
||||||
// return argument.
|
// return argument.
|
||||||
SILType resultType = getLoweredType(ft->getResult());
|
SILType resultType = getLoweredType(ft->getResult());
|
||||||
@@ -298,10 +291,13 @@ SILFunctionTypeInfo *TypeConverter::makeInfoForFunctionType(AnyFunctionType *ft,
|
|||||||
inputTypes.push_back(resultType);
|
inputTypes.push_back(resultType);
|
||||||
resultType = getEmptyTupleType();
|
resultType = getEmptyTupleType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Destructure the input tuple type.
|
||||||
|
LoweredFunctionInputTypeVisitor(*this, inputTypes)
|
||||||
|
.visit(ft->getInput()->getCanonicalType());
|
||||||
|
|
||||||
return SILFunctionTypeInfo::create(topType, inputTypes, resultType,
|
return SILFunctionTypeInfo::create(CanType(ft), inputTypes, resultType,
|
||||||
uncurriedInputCounts, hasIndirectReturn,
|
hasIndirectReturn, M);
|
||||||
M);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const TypeLoweringInfo &
|
const TypeLoweringInfo &
|
||||||
@@ -329,12 +325,16 @@ TypeConverter::makeTypeLoweringInfo(CanType t, unsigned uncurryLevel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make a SILFunctionTypeInfo for function types.
|
// Make a SILFunctionTypeInfo for function types.
|
||||||
if (AnyFunctionType *ft = t->getAs<AnyFunctionType>())
|
if (AnyFunctionType *ft = t->getAs<AnyFunctionType>()) {
|
||||||
theInfo->loweredType = SILType(makeInfoForFunctionType(ft, uncurryLevel),
|
auto *uncurried = getUncurriedFunctionType(ft, uncurryLevel);
|
||||||
|
theInfo->loweredType = SILType(makeInfoForFunctionType(uncurried),
|
||||||
/*address=*/ addressOnly);
|
/*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);
|
theInfo->loweredType = SILType(t, /*address=*/ addressOnly);
|
||||||
|
}
|
||||||
|
|
||||||
return *theInfo;
|
return *theInfo;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,12 +11,14 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "swift/SIL/SILFunction.h"
|
#include "swift/SIL/SILFunction.h"
|
||||||
|
#include "swift/SIL/SILModule.h"
|
||||||
#include "swift/SIL/SILVisitor.h"
|
#include "swift/SIL/SILVisitor.h"
|
||||||
#include "swift/SIL/Dominance.h"
|
#include "swift/SIL/Dominance.h"
|
||||||
#include "swift/AST/ASTContext.h"
|
#include "swift/AST/ASTContext.h"
|
||||||
#include "swift/AST/Decl.h"
|
#include "swift/AST/Decl.h"
|
||||||
#include "swift/AST/Module.h"
|
#include "swift/AST/Module.h"
|
||||||
#include "swift/AST/Types.h"
|
#include "swift/AST/Types.h"
|
||||||
|
#include "swift/SIL/TypeLowering.h"
|
||||||
#include "swift/Basic/Range.h"
|
#include "swift/Basic/Range.h"
|
||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
|
|
||||||
@@ -197,8 +199,6 @@ public:
|
|||||||
require(!calleeTy.isAddress(), "callee of closure cannot be an address");
|
require(!calleeTy.isAddress(), "callee of closure cannot be an address");
|
||||||
require(calleeTy.is<FunctionType>(),
|
require(calleeTy.is<FunctionType>(),
|
||||||
"callee of closure must have concrete function type");
|
"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();
|
SILType appliedTy = PAI->getType();
|
||||||
require(!appliedTy.isAddress(), "result of closure cannot be an address");
|
require(!appliedTy.isAddress(), "result of closure cannot be an address");
|
||||||
require(appliedTy.is<FunctionType>(),
|
require(appliedTy.is<FunctionType>(),
|
||||||
@@ -207,33 +207,35 @@ public:
|
|||||||
require(!appliedTy.castTo<FunctionType>()->isThin(),
|
require(!appliedTy.castTo<FunctionType>()->isThin(),
|
||||||
"result of closure cannot have a thin function type");
|
"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.
|
// The arguments must match the suffix of the original function's input
|
||||||
require(PAI->getArguments().size() == ti->getCurryInputTypes().size(),
|
// types.
|
||||||
"closure doesn't have right number of curry arguments for function");
|
require(PAI->getArguments().size() + resultInfo->getInputTypes().size()
|
||||||
for (size_t i = 0, size = PAI->getArguments().size(); i < size; ++i) {
|
== info->getInputTypes().size(),
|
||||||
DEBUG(llvm::dbgs() << " argument type ";
|
"result of partial_apply should take as many inputs as were not "
|
||||||
PAI->getArguments()[i].getType().print(llvm::dbgs());
|
"applied by the instruction");
|
||||||
llvm::dbgs() << " for input type ";
|
|
||||||
ti->getCurryInputTypes()[i].print(llvm::dbgs());
|
unsigned offset = info->getInputTypes().size() - PAI->getArguments().size();
|
||||||
llvm::dbgs() << '\n');
|
|
||||||
require(PAI->getArguments()[i].getType() == ti->getCurryInputTypes()[i],
|
for (unsigned i = 0; i < PAI->getArguments().size(); ++i) {
|
||||||
"input types to closure don't match function input types");
|
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) {
|
void checkBuiltinFunctionRefInst(BuiltinFunctionRefInst *BFI) {
|
||||||
@@ -310,9 +312,6 @@ public:
|
|||||||
"Specialize source should have a polymorphic function type");
|
"Specialize source should have a polymorphic function type");
|
||||||
require(operandTy.castTo<AnyFunctionType>()->isThin(),
|
require(operandTy.castTo<AnyFunctionType>()->isThin(),
|
||||||
"Specialize source should have a thin function type");
|
"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) {
|
void checkStructInst(StructInst *SI) {
|
||||||
@@ -520,11 +519,25 @@ public:
|
|||||||
// generic types.
|
// 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) {
|
void checkArchetypeMethodInst(ArchetypeMethodInst *AMI) {
|
||||||
DEBUG(llvm::dbgs() << "verifying";
|
DEBUG(llvm::dbgs() << "verifying";
|
||||||
AMI->print(llvm::dbgs()));
|
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>();
|
FunctionType *methodType = AMI->getType(0).getAs<FunctionType>();
|
||||||
DEBUG(llvm::dbgs() << "method type ";
|
DEBUG(llvm::dbgs() << "method type ";
|
||||||
methodType->print(llvm::dbgs());
|
methodType->print(llvm::dbgs());
|
||||||
@@ -539,11 +552,10 @@ public:
|
|||||||
llvm::dbgs() << "\n");
|
llvm::dbgs() << "\n");
|
||||||
require(operandType.is<ArchetypeType>(),
|
require(operandType.is<ArchetypeType>(),
|
||||||
"operand type must be an archetype");
|
"operand type must be an archetype");
|
||||||
require(methodType->getResult()->is<FunctionType>(),
|
|
||||||
"result must be a method");
|
CanType thisType = getMethodThisType(methodType);
|
||||||
|
require(thisType == operandType.getSwiftType()
|
||||||
require(methodType->getInput()->isEqual(operandType.getSwiftType())
|
|| thisType->isEqual(
|
||||||
|| methodType->getInput()->isEqual(
|
|
||||||
MetaTypeType::get(operandType.getSwiftRValueType(),
|
MetaTypeType::get(operandType.getSwiftRValueType(),
|
||||||
operandType.getASTContext())),
|
operandType.getASTContext())),
|
||||||
"result must be method of operand type");
|
"result must be method of operand type");
|
||||||
@@ -558,10 +570,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void checkProtocolMethodInst(ProtocolMethodInst *EMI) {
|
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>();
|
FunctionType *methodType = EMI->getType(0).getAs<FunctionType>();
|
||||||
require(methodType,
|
require(methodType,
|
||||||
"result method must be of a concrete function type");
|
"result method must be of a concrete function type");
|
||||||
@@ -570,11 +578,9 @@ public:
|
|||||||
SILType operandType = EMI->getOperand().getType();
|
SILType operandType = EMI->getOperand().getType();
|
||||||
|
|
||||||
if (EMI->getMember().getDecl()->isInstanceMember()) {
|
if (EMI->getMember().getDecl()->isInstanceMember()) {
|
||||||
require(methodType->getInput()->isEqual(
|
require(getMethodThisType(methodType)->isEqual(
|
||||||
operandType.getASTContext().TheOpaquePointerType),
|
operandType.getASTContext().TheOpaquePointerType),
|
||||||
"result must be a method of opaque pointer");
|
"result must be a method of opaque pointer");
|
||||||
require(methodType->getResult()->is<FunctionType>(),
|
|
||||||
"result must be a method");
|
|
||||||
require(operandType.isAddress(),
|
require(operandType.isAddress(),
|
||||||
"instance protocol_method must apply to an existential address");
|
"instance protocol_method must apply to an existential address");
|
||||||
require(operandType.isExistentialType(),
|
require(operandType.isExistentialType(),
|
||||||
@@ -587,10 +593,8 @@ public:
|
|||||||
require(operandType.castTo<MetaTypeType>()
|
require(operandType.castTo<MetaTypeType>()
|
||||||
->getInstanceType()->isExistentialType(),
|
->getInstanceType()->isExistentialType(),
|
||||||
"static protocol_method must apply to an existential metatype");
|
"static protocol_method must apply to an existential metatype");
|
||||||
require(methodType->getResult()->is<FunctionType>(),
|
require(getMethodThisType(methodType) ==
|
||||||
"result must be a method");
|
EMI->getOperand().getType().getSwiftType(),
|
||||||
require(methodType->getInput()->isEqual(
|
|
||||||
EMI->getOperand().getType().getSwiftType()),
|
|
||||||
"result must be a method of the existential metatype");
|
"result must be a method of the existential metatype");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -604,8 +608,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void checkClassMethodInst(ClassMethodInst *CMI) {
|
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>();
|
auto *methodType = CMI->getType(0).getAs<AnyFunctionType>();
|
||||||
require(methodType,
|
require(methodType,
|
||||||
"result method must be of a function type");
|
"result method must be of a function type");
|
||||||
@@ -614,15 +616,11 @@ public:
|
|||||||
SILType operandType = CMI->getOperand().getType();
|
SILType operandType = CMI->getOperand().getType();
|
||||||
require(isClassOrClassMetatype(operandType.getSwiftType()),
|
require(isClassOrClassMetatype(operandType.getSwiftType()),
|
||||||
"operand must be of a class type");
|
"operand must be of a class type");
|
||||||
require(isClassOrClassMetatype(methodType->getInput()),
|
require(isClassOrClassMetatype(getMethodThisType(methodType)),
|
||||||
"result must be a method of a class");
|
"result must be a method of a class");
|
||||||
require(methodType->getResult()->is<AnyFunctionType>(),
|
|
||||||
"result must be a method");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkSuperMethodInst(SuperMethodInst *CMI) {
|
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>();
|
auto *methodType = CMI->getType(0).getAs<AnyFunctionType>();
|
||||||
require(methodType,
|
require(methodType,
|
||||||
"result method must be of a function type");
|
"result method must be of a function type");
|
||||||
@@ -631,10 +629,8 @@ public:
|
|||||||
SILType operandType = CMI->getOperand().getType();
|
SILType operandType = CMI->getOperand().getType();
|
||||||
require(isClassOrClassMetatype(operandType.getSwiftType()),
|
require(isClassOrClassMetatype(operandType.getSwiftType()),
|
||||||
"operand must be of a class type");
|
"operand must be of a class type");
|
||||||
require(isClassOrClassMetatype(methodType->getInput()),
|
require(isClassOrClassMetatype(getMethodThisType(methodType)),
|
||||||
"result must be a method of a class");
|
"result must be a method of a class");
|
||||||
require(methodType->getResult()->is<AnyFunctionType>(),
|
|
||||||
"result must be a method");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkProjectExistentialInst(ProjectExistentialInst *PEI) {
|
void checkProjectExistentialInst(ProjectExistentialInst *PEI) {
|
||||||
@@ -698,10 +694,6 @@ public:
|
|||||||
"bridge_to_block operand must be a function type");
|
"bridge_to_block operand must be a function type");
|
||||||
require(resultTy.is<FunctionType>(),
|
require(resultTy.is<FunctionType>(),
|
||||||
"bridge_to_block result must be a function type");
|
"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 *operandFTy = BBI->getOperand().getType().castTo<FunctionType>();
|
||||||
auto *resultFTy = BBI->getType().castTo<FunctionType>();
|
auto *resultFTy = BBI->getType().castTo<FunctionType>();
|
||||||
@@ -732,10 +724,6 @@ public:
|
|||||||
"thin_to_thick_function operand must be a function");
|
"thin_to_thick_function operand must be a function");
|
||||||
require(TTFI->getType().is<AnyFunctionType>(),
|
require(TTFI->getType().is<AnyFunctionType>(),
|
||||||
"thin_to_thick_function result must be a function");
|
"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>(
|
if (auto *opFTy = dyn_cast<FunctionType>(
|
||||||
TTFI->getOperand().getType().getSwiftType())) {
|
TTFI->getOperand().getType().getSwiftType())) {
|
||||||
auto *resFTy = dyn_cast<FunctionType>(TTFI->getType().getSwiftType());
|
auto *resFTy = dyn_cast<FunctionType>(TTFI->getType().getSwiftType());
|
||||||
@@ -777,10 +765,6 @@ public:
|
|||||||
"convert_cc operand must be a function");
|
"convert_cc operand must be a function");
|
||||||
require(CCI->getType().is<AnyFunctionType>(),
|
require(CCI->getType().is<AnyFunctionType>(),
|
||||||
"convert_cc result must be a function");
|
"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>(
|
if (auto *opFTy = dyn_cast<FunctionType>(
|
||||||
CCI->getOperand().getType().getSwiftType())) {
|
CCI->getOperand().getType().getSwiftType())) {
|
||||||
auto *resFTy = dyn_cast<FunctionType>(CCI->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