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