| //===--- SILGenApply.cpp - Constructs call sites for SILGen ---------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "ArgumentScope.h" |
| #include "ArgumentSource.h" |
| #include "Callee.h" |
| #include "Conversion.h" |
| #include "FormalEvaluation.h" |
| #include "Initialization.h" |
| #include "LValue.h" |
| #include "RValue.h" |
| #include "ResultPlan.h" |
| #include "Scope.h" |
| #include "SpecializedEmitter.h" |
| #include "Varargs.h" |
| #include "swift/AST/ASTContext.h" |
| #include "swift/AST/DiagnosticsSIL.h" |
| #include "swift/AST/ForeignErrorConvention.h" |
| #include "swift/AST/GenericSignature.h" |
| #include "swift/AST/Module.h" |
| #include "swift/AST/SubstitutionMap.h" |
| #include "swift/Basic/ExternalUnion.h" |
| #include "swift/Basic/Range.h" |
| #include "swift/Basic/STLExtras.h" |
| #include "swift/Basic/Unicode.h" |
| #include "swift/SIL/PrettyStackTrace.h" |
| #include "swift/SIL/SILArgument.h" |
| #include "llvm/Support/Compiler.h" |
| |
| using namespace swift; |
| using namespace Lowering; |
| |
| //===----------------------------------------------------------------------===// |
| // Utility Functions |
| //===----------------------------------------------------------------------===// |
| |
| /// Return the abstraction pattern to use when calling a function value. |
| static AbstractionPattern |
| getIndirectApplyAbstractionPattern(SILGenFunction &SGF, |
| CanFunctionType fnType) { |
| assert(fnType); |
| AbstractionPattern pattern(fnType); |
| switch (fnType->getRepresentation()) { |
| case FunctionTypeRepresentation::Swift: |
| case FunctionTypeRepresentation::Thin: |
| return pattern; |
| |
| case FunctionTypeRepresentation::CFunctionPointer: |
| case FunctionTypeRepresentation::Block: { |
| // C and block function parameters and results are implicitly |
| // bridged to a foreign type. |
| auto bridgedType = |
| SGF.SGM.Types.getBridgedFunctionType(pattern, fnType, |
| fnType->getExtInfo()); |
| pattern.rewriteType(CanGenericSignature(), bridgedType); |
| return pattern; |
| } |
| } |
| llvm_unreachable("bad representation"); |
| } |
| |
| /// Return the formal type for the partial-apply result type of a |
| /// dynamic method invocation. |
| static CanFunctionType |
| getPartialApplyOfDynamicMethodFormalType(SILGenModule &SGM, SILDeclRef member, |
| ConcreteDeclRef memberRef) { |
| auto memberCI = SGM.Types.getConstantInfo(member); |
| |
| // Construct a non-generic version of the formal type. |
| // This works because we're only using foreign members, where presumably |
| // substitution doesn't matter. |
| CanAnyFunctionType completeMethodTy = memberCI.LoweredType; |
| if (auto genericFnType = dyn_cast<GenericFunctionType>(completeMethodTy)) { |
| completeMethodTy = cast<FunctionType>( |
| genericFnType->substGenericArgs(memberRef.getSubstitutions()) |
| ->getCanonicalType()); |
| } |
| |
| // Adjust the parameters by removing the self parameter, which we |
| // will be partially applying. |
| auto params = completeMethodTy.getParams().drop_back(); |
| |
| // Adjust the result type to replace dynamic-self with AnyObject. |
| CanType resultType = completeMethodTy.getResult(); |
| if (auto fnDecl = dyn_cast<FuncDecl>(member.getDecl())) { |
| if (fnDecl->hasDynamicSelf()) { |
| auto anyObjectTy = SGM.getASTContext().getAnyObjectType(); |
| resultType = resultType->replaceCovariantResultType(anyObjectTy, 0) |
| ->getCanonicalType(); |
| } |
| } |
| |
| // Adjust the ExtInfo by using a Swift representation. |
| auto extInfo = completeMethodTy->getExtInfo() |
| .withRepresentation(FunctionTypeRepresentation::Swift); |
| |
| auto fnType = CanFunctionType::get(params, resultType, extInfo); |
| return fnType; |
| } |
| |
| /// Retrieve the type to use for a method found via dynamic lookup. |
| static SILType |
| getDynamicMethodLoweredType(SILModule &M, |
| SILDeclRef constant, |
| CanAnyFunctionType substMemberTy) { |
| assert(constant.isForeign); |
| auto objcFormalTy = substMemberTy.withExtInfo(substMemberTy->getExtInfo() |
| .withSILRepresentation(SILFunctionTypeRepresentation::ObjCMethod)); |
| return SILType::getPrimitiveObjectType( |
| M.Types.getUncachedSILFunctionTypeForConstant(constant, objcFormalTy)); |
| } |
| |
| /// Check if we can perform a dynamic dispatch on a super method call. |
| static bool canUseStaticDispatch(SILGenFunction &SGF, |
| SILDeclRef constant) { |
| auto *funcDecl = cast<AbstractFunctionDecl>(constant.getDecl()); |
| |
| if (funcDecl->isFinal()) |
| return true; |
| // Extension methods currently must be statically dispatched, unless they're |
| // @objc or dynamic. |
| if (funcDecl->getDeclContext()->isExtensionContext() |
| && !constant.isForeign) |
| return true; |
| |
| // We cannot form a direct reference to a method body defined in |
| // Objective-C. |
| if (constant.isForeign) |
| return false; |
| |
| // If we cannot form a direct reference due to resilience constraints, |
| // we have to dynamic dispatch. |
| if (SGF.F.isSerialized()) |
| return false; |
| |
| // If the method is defined in the same module, we can reference it |
| // directly. |
| auto thisModule = SGF.SGM.M.getSwiftModule(); |
| if (thisModule == funcDecl->getModuleContext()) |
| return true; |
| |
| // Otherwise, we must dynamic dispatch. |
| return false; |
| } |
| |
| static SILValue getOriginalSelfValue(SILValue selfValue) { |
| if (auto *TTOI = dyn_cast<ThickToObjCMetatypeInst>(selfValue)) |
| selfValue = TTOI->getOperand(); |
| |
| if (auto *BBI = dyn_cast<BeginBorrowInst>(selfValue)) |
| selfValue = BBI->getOperand(); |
| |
| while (auto *UI = dyn_cast<UpcastInst>(selfValue)) |
| selfValue = UI->getOperand(); |
| |
| if (auto *UTBCI = dyn_cast<UncheckedTrivialBitCastInst>(selfValue)) |
| selfValue = UTBCI->getOperand(); |
| |
| return selfValue; |
| } |
| |
| /// Borrow self and then upcast self to its original type. If self is a |
| /// metatype, we just return the original metatype since metatypes are trivial. |
| static ManagedValue borrowedCastToOriginalSelfType(SILGenFunction &SGF, |
| SILLocation loc, |
| ManagedValue self) { |
| SILValue originalSelf = getOriginalSelfValue(self.getValue()); |
| SILType originalSelfType = originalSelf->getType(); |
| |
| // If we have a metatype, then we just return the original self value since |
| // metatypes are trivial, so we can avoid ownership concerns. |
| if (originalSelfType.getSwiftRValueType()->is<AnyMetatypeType>()) { |
| assert(originalSelfType.isTrivial(SGF.getModule()) && |
| "Metatypes should always be trivial"); |
| return ManagedValue::forUnmanaged(originalSelf); |
| } |
| |
| // Otherwise, we have a non-metatype. Use a borrow+unchecked_ref_cast. |
| return SGF.B.createUncheckedRefCast(loc, self.borrow(SGF, loc), |
| originalSelfType); |
| } |
| |
| static ManagedValue convertOwnershipConventionGivenParamInfo(SILGenFunction &SGF, |
| SILParameterInfo param, |
| ManagedValue value, |
| SILLocation loc) { |
| if (param.isConsumed() && |
| value.getOwnershipKind() == ValueOwnershipKind::Guaranteed) { |
| return value.copyUnmanaged(SGF, loc); |
| } |
| |
| if (SGF.F.getModule().getOptions().EnableSILOwnership && |
| value.getOwnershipKind() == ValueOwnershipKind::Owned) { |
| if (param.isDirectGuaranteed() || (!SGF.silConv.useLoweredAddresses() && |
| param.isIndirectInGuaranteed())) { |
| return value.borrow(SGF, loc); |
| } |
| } |
| |
| return value; |
| } |
| |
| static void convertOwnershipConventionsGivenParamInfos( |
| SILGenFunction &SGF, |
| ArrayRef<SILParameterInfo> params, |
| ArrayRef<ManagedValue> values, |
| SILLocation loc, |
| llvm::SmallVectorImpl<ManagedValue> &outVar) { |
| assert(params.size() == values.size() && |
| "Different number of params from arguments"); |
| transform(indices(params), std::back_inserter(outVar), |
| [&](unsigned i) -> ManagedValue { |
| return convertOwnershipConventionGivenParamInfo(SGF, params[i], values[i], loc); |
| }); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Callee |
| //===----------------------------------------------------------------------===// |
| |
| namespace { |
| |
| /// Abstractly represents a callee, which may be a constant or function value, |
| /// and knows how to perform dynamic dispatch and reference the appropriate |
| /// entry point at any valid uncurry level. |
| class Callee { |
| public: |
| enum class Kind { |
| /// An indirect function value. |
| IndirectValue, |
| |
| /// A direct standalone function call, referenceable by a FunctionRefInst. |
| StandaloneFunction, |
| |
| /// Enum case constructor call. |
| EnumElement, |
| |
| /// A method call using class method dispatch. |
| ClassMethod, |
| |
| /// A method call using super method dispatch. |
| SuperMethod, |
| |
| /// A method call using protocol witness table dispatch. |
| WitnessMethod, |
| |
| /// A method call using dynamic lookup. |
| DynamicMethod, |
| }; |
| |
| const Kind kind; |
| |
| // Move, don't copy. |
| Callee(const Callee &) = delete; |
| Callee &operator=(const Callee &) = delete; |
| |
| private: |
| /// An IndirectValue callee represents something like a swift closure or a c |
| /// function pointer where we have /no/ information at all on what the callee |
| /// is. This contrasts with a class method, where we may not know the exact |
| /// method that is being called, but we have some information from the type |
| /// system that we have an actual method. |
| /// |
| /// *NOTE* This will never be non-null if Constant is non-null. |
| ManagedValue IndirectValue; |
| |
| /// If we are trying to call a specific method or function, this field is set |
| /// to the decl ref information for that callee. |
| /// |
| /// *NOTE* This should never be non-null if IndirectValue is non-null. |
| SILDeclRef Constant; |
| |
| /// The abstraction pattern of the callee. |
| AbstractionPattern OrigFormalInterfaceType; |
| |
| /// The callee's formal type with substitutions applied. |
| CanFunctionType SubstFormalInterfaceType; |
| |
| /// The substitutions applied to OrigFormalInterfaceType to produce |
| /// SubstFormalInterfaceType. |
| SubstitutionList Substitutions; |
| |
| /// The list of values captured by our callee. |
| Optional<SmallVector<ManagedValue, 2>> Captures; |
| |
| // The pointer back to the AST node that produced the callee. |
| SILLocation Loc; |
| |
| static CanFunctionType |
| getSubstFormalInterfaceType(CanAnyFunctionType substFormalType, |
| SubstitutionList subs) { |
| if (auto *gft = substFormalType->getAs<GenericFunctionType>()) { |
| return cast<FunctionType>( |
| gft->substGenericArgs(subs) |
| ->getCanonicalType()); |
| } |
| |
| return cast<FunctionType>(substFormalType); |
| } |
| |
| /// Constructor for Callee::forIndirect. |
| Callee(ManagedValue indirectValue, |
| AbstractionPattern origFormalType, |
| CanFunctionType substFormalType, |
| SILLocation l) |
| : kind(Kind::IndirectValue), |
| IndirectValue(indirectValue), |
| OrigFormalInterfaceType(origFormalType), |
| SubstFormalInterfaceType(substFormalType), |
| Loc(l) |
| {} |
| |
| /// Constructor for Callee::forDirect. |
| Callee(SILGenFunction &SGF, SILDeclRef standaloneFunction, |
| AbstractionPattern origFormalType, |
| CanAnyFunctionType substFormalType, |
| SubstitutionList subs, SILLocation l) |
| : kind(Kind::StandaloneFunction), Constant(standaloneFunction), |
| OrigFormalInterfaceType(origFormalType), |
| SubstFormalInterfaceType(getSubstFormalInterfaceType(substFormalType, |
| subs)), |
| Substitutions(subs), |
| Loc(l) |
| { |
| } |
| |
| /// Constructor called by all for* factory methods except forDirect and |
| /// forIndirect. |
| Callee(Kind methodKind, SILGenFunction &SGF, SILDeclRef methodName, |
| AbstractionPattern origFormalType, CanAnyFunctionType substFormalType, |
| SubstitutionList subs, SILLocation l) |
| : kind(methodKind), Constant(methodName), |
| OrigFormalInterfaceType(origFormalType), |
| SubstFormalInterfaceType( |
| getSubstFormalInterfaceType(substFormalType, subs)), |
| Substitutions(subs), Loc(l) {} |
| |
| public: |
| |
| static Callee forIndirect(ManagedValue indirectValue, |
| AbstractionPattern origFormalType, |
| CanFunctionType substFormalType, |
| SILLocation l) { |
| return Callee(indirectValue, origFormalType, substFormalType, l); |
| } |
| static Callee forDirect(SILGenFunction &SGF, SILDeclRef c, |
| SubstitutionList subs, |
| SILLocation l) { |
| auto &ci = SGF.getConstantInfo(c); |
| return Callee(SGF, c, ci.FormalPattern, ci.FormalType, subs, l); |
| } |
| static Callee forEnumElement(SILGenFunction &SGF, SILDeclRef c, |
| SubstitutionList subs, |
| SILLocation l) { |
| assert(isa<EnumElementDecl>(c.getDecl())); |
| auto &ci = SGF.getConstantInfo(c); |
| return Callee(Kind::EnumElement, SGF, c, ci.FormalPattern, |
| ci.FormalType, subs, l); |
| } |
| static Callee forClassMethod(SILGenFunction &SGF, |
| SILDeclRef c, SubstitutionList subs, |
| SILLocation l) { |
| auto base = c.getOverriddenVTableEntry(); |
| auto &baseCI = SGF.getConstantInfo(base); |
| auto &derivedCI = SGF.getConstantInfo(c); |
| return Callee(Kind::ClassMethod, SGF, c, |
| baseCI.FormalPattern, derivedCI.FormalType, subs, l); |
| } |
| static Callee forSuperMethod(SILGenFunction &SGF, |
| SILDeclRef c, SubstitutionList subs, |
| SILLocation l) { |
| auto &ci = SGF.getConstantInfo(c); |
| return Callee(Kind::SuperMethod, SGF, c, |
| ci.FormalPattern, ci.FormalType, subs, l); |
| } |
| static Callee forWitnessMethod(SILGenFunction &SGF, |
| CanType protocolSelfType, |
| SILDeclRef c, |
| SubstitutionList subs, |
| SILLocation l) { |
| auto &ci = SGF.getConstantInfo(c); |
| return Callee(Kind::WitnessMethod, SGF, c, ci.FormalPattern, |
| ci.FormalType, subs, l); |
| } |
| static Callee forDynamic(SILGenFunction &SGF, |
| SILDeclRef c, const SubstitutionList &constantSubs, |
| CanAnyFunctionType substFormalType, |
| SubstitutionList subs, SILLocation l) { |
| auto &ci = SGF.getConstantInfo(c); |
| AbstractionPattern origFormalType = ci.FormalPattern; |
| |
| // Replace the original self type with the partially-applied subst type. |
| auto origFormalFnType = cast<AnyFunctionType>(origFormalType.getType()); |
| if (auto genericFnType = dyn_cast<GenericFunctionType>(origFormalFnType)) { |
| // If we have a generic function type, substitute it. This is normally |
| // a huge no-no, but the partial-application hacks we're doing here |
| // really kindof mandate it, and it works out because we're always using |
| // a foreign function. If/when we support native dynamic functions, |
| // this will stop working and we will need a completely different |
| // approach. |
| origFormalFnType = |
| cast<FunctionType>(genericFnType->substGenericArgs(constantSubs) |
| ->getCanonicalType()); |
| } |
| origFormalType.rewriteType(CanGenericSignature(), origFormalFnType); |
| |
| return Callee(Kind::DynamicMethod, SGF, c, origFormalType, |
| substFormalType, subs, l); |
| } |
| |
| Callee(Callee &&) = default; |
| Callee &operator=(Callee &&) = default; |
| |
| void setCaptures(SmallVectorImpl<ManagedValue> &&captures) { |
| Captures = std::move(captures); |
| } |
| |
| ArrayRef<ManagedValue> getCaptures() const { |
| if (Captures) |
| return *Captures; |
| return {}; |
| } |
| |
| bool hasCaptures() const { |
| return Captures.hasValue(); |
| } |
| |
| AbstractionPattern getOrigFormalType() const { |
| return AbstractionPattern(OrigFormalInterfaceType); |
| } |
| |
| CanFunctionType getSubstFormalType() const { |
| return SubstFormalInterfaceType; |
| } |
| |
| unsigned getParameterListCount() const { |
| switch (kind) { |
| case Kind::IndirectValue: |
| return 1; |
| |
| case Kind::StandaloneFunction: |
| case Kind::EnumElement: |
| case Kind::ClassMethod: |
| case Kind::SuperMethod: |
| case Kind::WitnessMethod: |
| case Kind::DynamicMethod: |
| return Constant.getParameterListCount(); |
| } |
| |
| llvm_unreachable("Unhandled Kind in switch."); |
| } |
| |
| bool requiresSelfValueForDispatch() const { |
| switch (kind) { |
| case Kind::IndirectValue: |
| case Kind::StandaloneFunction: |
| case Kind::EnumElement: |
| return false; |
| case Kind::WitnessMethod: |
| if (Constant.isForeign) |
| return true; |
| return false; |
| case Kind::ClassMethod: |
| case Kind::SuperMethod: |
| case Kind::DynamicMethod: |
| return true; |
| } |
| |
| llvm_unreachable("Unhandled Kind in switch."); |
| } |
| |
| EnumElementDecl *getEnumElementDecl() { |
| assert(kind == Kind::EnumElement); |
| return cast<EnumElementDecl>(Constant.getDecl()); |
| } |
| |
| CalleeTypeInfo createCalleeTypeInfo(SILGenFunction &SGF, |
| Optional<SILDeclRef> constant, |
| SILType formalFnType) const & { |
| CalleeTypeInfo result; |
| |
| result.substFnType = |
| formalFnType.castTo<SILFunctionType>()->substGenericArgs(SGF.SGM.M, |
| Substitutions); |
| |
| if (!constant || !constant->isForeign) |
| return result; |
| |
| auto func = cast<AbstractFunctionDecl>(constant->getDecl()); |
| result.foreignError = func->getForeignErrorConvention(); |
| result.foreignSelf = func->getImportAsMemberStatus(); |
| |
| return result; |
| } |
| |
| SILDeclRef getCurriedConstant(bool isCurried) const { |
| if (isCurried) { |
| auto constant = Constant.asCurried(); |
| |
| // If we're currying a direct reference to a class-dispatched method, |
| // make sure we emit the right set of thunks. |
| if (kind == Kind::StandaloneFunction) { |
| if (auto func = Constant.getAbstractFunctionDecl()) { |
| if (getMethodDispatch(func) == MethodDispatch::Class) { |
| return constant.asDirectReference(true); |
| } |
| } |
| } |
| |
| return constant; |
| } |
| |
| return Constant; |
| } |
| |
| ManagedValue getFnValue(SILGenFunction &SGF, bool isCurried, |
| Optional<ManagedValue> borrowedSelf) const & { |
| Optional<SILDeclRef> constant = None; |
| |
| if (!Constant) { |
| assert(!isCurried && "can't curry indirect function"); |
| } else { |
| constant = getCurriedConstant(isCurried); |
| |
| // If the call is curried, emit a direct call to the curry thunk. |
| if (constant->isCurried) { |
| auto constantInfo = SGF.getConstantInfo(*constant); |
| SILValue ref = SGF.emitGlobalFunctionRef(Loc, *constant, constantInfo); |
| return ManagedValue::forUnmanaged(ref); |
| } |
| } |
| |
| switch (kind) { |
| case Kind::IndirectValue: |
| assert(Substitutions.empty()); |
| return IndirectValue; |
| |
| case Kind::StandaloneFunction: { |
| auto constantInfo = SGF.getConstantInfo(*constant); |
| SILValue ref = SGF.emitGlobalFunctionRef(Loc, *constant, constantInfo); |
| return ManagedValue::forUnmanaged(ref); |
| } |
| case Kind::EnumElement: |
| llvm_unreachable("Should have been curried"); |
| case Kind::ClassMethod: { |
| auto methodTy = SGF.SGM.Types.getConstantOverrideType(*constant); |
| |
| // Otherwise, do the dynamic dispatch inline. |
| Scope S(SGF, Loc); |
| |
| SILValue methodVal; |
| if (!constant->isForeign) { |
| methodVal = SGF.emitClassMethodRef( |
| Loc, borrowedSelf->getValue(), *constant, methodTy); |
| } else { |
| methodVal = SGF.B.createObjCMethod( |
| Loc, borrowedSelf->getValue(), *constant, |
| SILType::getPrimitiveObjectType(methodTy)); |
| } |
| return ManagedValue::forUnmanaged(methodVal); |
| } |
| case Kind::SuperMethod: { |
| assert(!constant->isCurried); |
| |
| Scope S(SGF, Loc); |
| ManagedValue castValue = borrowedCastToOriginalSelfType( |
| SGF, Loc, *borrowedSelf); |
| |
| auto base = constant->getOverriddenVTableEntry(); |
| auto constantInfo = |
| SGF.SGM.Types.getConstantOverrideInfo(*constant, base); |
| |
| if (!constant->isForeign) { |
| return SGF.B.createSuperMethod(Loc, castValue, *constant, |
| constantInfo.getSILType()); |
| } else { |
| return SGF.B.createObjCSuperMethod(Loc, castValue, *constant, |
| constantInfo.getSILType()); |
| } |
| } |
| case Kind::WitnessMethod: { |
| auto constantInfo = SGF.getConstantInfo(*constant); |
| |
| auto proto = cast<ProtocolDecl>( |
| Constant.getDecl()->getDeclContext()); |
| auto lookupType = getSubstFormalType() |
| .getInput() |
| ->getRValueInstanceType() |
| ->getCanonicalType(); |
| |
| SILValue fn; |
| |
| if (!constant->isForeign) { |
| fn = SGF.B.createWitnessMethod( |
| Loc, lookupType, ProtocolConformanceRef(proto), *constant, |
| constantInfo.getSILType()); |
| } else { |
| fn = SGF.B.createObjCMethod(Loc, borrowedSelf->getValue(), |
| *constant, constantInfo.getSILType()); |
| } |
| |
| return ManagedValue::forUnmanaged(fn); |
| } |
| case Kind::DynamicMethod: { |
| auto closureType = getDynamicMethodLoweredType( |
| SGF.SGM.M, *constant, getSubstFormalType()); |
| |
| Scope S(SGF, Loc); |
| SILValue fn = SGF.B.createObjCMethod( |
| Loc, borrowedSelf->getValue(), *constant, |
| closureType); |
| return ManagedValue::forUnmanaged(fn); |
| } |
| } |
| } |
| |
| CalleeTypeInfo getTypeInfo(SILGenFunction &SGF, bool isCurried) const & { |
| Optional<SILDeclRef> constant = None; |
| |
| if (!Constant) { |
| assert(!isCurried && "can't curry indirect function"); |
| } else { |
| constant = getCurriedConstant(isCurried); |
| |
| // If the call is curried, emit a direct call to the curry thunk. |
| if (constant->isCurried) { |
| auto constantInfo = SGF.getConstantInfo(*constant); |
| return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType()); |
| } |
| } |
| |
| switch (kind) { |
| case Kind::IndirectValue: |
| assert(Substitutions.empty()); |
| return createCalleeTypeInfo(SGF, constant, IndirectValue.getType()); |
| |
| case Kind::StandaloneFunction: { |
| auto constantInfo = SGF.getConstantInfo(*constant); |
| return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType()); |
| } |
| case Kind::EnumElement: |
| llvm_unreachable("Should have been curried"); |
| case Kind::ClassMethod: { |
| auto constantInfo = SGF.SGM.Types.getConstantOverrideInfo(*constant); |
| return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType()); |
| } |
| case Kind::SuperMethod: { |
| auto base = constant->getOverriddenVTableEntry(); |
| auto constantInfo = |
| SGF.SGM.Types.getConstantOverrideInfo(*constant, base); |
| return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType()); |
| } |
| case Kind::WitnessMethod: { |
| auto constantInfo = SGF.getConstantInfo(*constant); |
| return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType()); |
| } |
| case Kind::DynamicMethod: { |
| auto formalType = getDynamicMethodLoweredType( |
| SGF.SGM.M, *constant, getSubstFormalType()); |
| return createCalleeTypeInfo(SGF, constant, formalType); |
| } |
| } |
| } |
| |
| SubstitutionList getSubstitutions() const { |
| return Substitutions; |
| } |
| |
| SILDeclRef getMethodName() const { |
| return Constant; |
| } |
| |
| /// Return a specialized emission function if this is a function with a known |
| /// lowering, such as a builtin, or return null if there is no specialized |
| /// emitter. |
| Optional<SpecializedEmitter> |
| getSpecializedEmitter(SILGenModule &SGM) const { |
| switch (kind) { |
| case Kind::StandaloneFunction: { |
| return SpecializedEmitter::forDecl(SGM, Constant); |
| } |
| case Kind::EnumElement: |
| case Kind::IndirectValue: |
| case Kind::ClassMethod: |
| case Kind::SuperMethod: |
| case Kind::WitnessMethod: |
| case Kind::DynamicMethod: |
| return None; |
| } |
| llvm_unreachable("bad callee kind"); |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| //===----------------------------------------------------------------------===// |
| // SILGenApply ASTVisitor |
| //===----------------------------------------------------------------------===// |
| |
| /// For ObjC init methods, we generate a shared-linkage Swift allocating entry |
| /// point that does the [[T alloc] init] dance. We want to use this native |
| /// thunk where we expect to be calling an allocating entry point for an ObjC |
| /// constructor. |
| static bool isConstructorWithGeneratedAllocatorThunk(ValueDecl *vd) { |
| return vd->isObjC() && isa<ConstructorDecl>(vd); |
| } |
| |
| namespace { |
| |
| /// An ASTVisitor for decomposing a nesting of ApplyExprs into an initial |
| /// Callee and a list of CallSites. The CallEmission class below uses these |
| /// to generate the actual SIL call. |
| /// |
| /// Formally, an ApplyExpr in the AST always has a single argument, which may |
| /// be of tuple type, possibly empty. Also, some callees have a formal type |
| /// which is curried -- for example, methods have type Self -> Arg -> Result. |
| /// |
| /// However, SIL functions take zero or more parameters and the natural entry |
| /// point of a method takes Self as an additional argument, rather than |
| /// returning a partial application. |
| /// |
| /// Therefore, nested ApplyExprs applied to a constant are flattened into a |
| /// single call of the most uncurried entry point fitting the call site. |
| /// This avoids intermediate closure construction. |
| /// |
| /// For example, a method reference 'self.method' decomposes into curry thunk |
| /// as the callee, with a single call site '(self)'. |
| /// |
| /// On the other hand, a call of a method 'self.method(x)(y)' with a function |
| /// return type decomposes into the method's natural entry point as the callee, |
| /// and two call sites, first '(x, self)' then '(y)'. |
| class SILGenApply : public Lowering::ExprVisitor<SILGenApply> { |
| public: |
| /// The SILGenFunction that we are emitting SIL into. |
| SILGenFunction &SGF; |
| |
| /// The apply callee that abstractly represents the entry point that is being |
| /// called. |
| Optional<Callee> applyCallee; |
| |
| /// The lvalue or rvalue representing the argument source of self. |
| ArgumentSource selfParam; |
| Type selfType; |
| std::vector<ApplyExpr*> callSites; |
| Expr *sideEffect = nullptr; |
| |
| SILGenApply(SILGenFunction &SGF) |
| : SGF(SGF) |
| {} |
| |
| void setCallee(Callee &&c) { |
| assert(!applyCallee && "already set callee!"); |
| applyCallee.emplace(std::move(c)); |
| } |
| |
| void setSideEffect(Expr *sideEffectExpr) { |
| assert(!sideEffect && "already set side effect!"); |
| sideEffect = sideEffectExpr; |
| } |
| |
| void setSelfParam(ArgumentSource &&theSelfParam, Expr *theSelfApplyExpr) { |
| assert(!selfParam && "already set this!"); |
| selfParam = std::move(theSelfParam); |
| selfType = theSelfApplyExpr->getType(); |
| } |
| |
| void decompose(Expr *e) { |
| visit(e); |
| } |
| |
| /// Fall back to an unknown, indirect callee. |
| void visitExpr(Expr *e) { |
| // TODO: preserve the function pointer at its original abstraction level |
| // when loading from memory. |
| |
| ManagedValue fn = SGF.emitRValueAsSingleValue(e); |
| auto substType = cast<FunctionType>(e->getType()->getCanonicalType()); |
| |
| // When calling an C or block function, there's implicit bridging. |
| auto origType = getIndirectApplyAbstractionPattern(SGF, substType); |
| |
| setCallee(Callee::forIndirect(fn, origType, substType, e)); |
| } |
| |
| /// Add a call site to the curry. |
| void visitApplyExpr(ApplyExpr *e) { |
| if (e->isSuper()) { |
| applySuper(e); |
| return; |
| } |
| |
| if (applyInitDelegation(e)) |
| return; |
| |
| callSites.push_back(e); |
| visit(e->getFn()); |
| } |
| |
| /// Idempotently convert a metatype to an objc metatype. |
| std::pair<ManagedValue, SILType> convertToObjCMetatype(ManagedValue selfMeta, |
| SILLocation loc) { |
| auto metaType = selfMeta.getType().castTo<AnyMetatypeType>(); |
| CanType instanceType = metaType.getInstanceType(); |
| |
| // If we are already objc, just return. |
| if (metaType->getRepresentation() == MetatypeRepresentation::ObjC) { |
| return {selfMeta, SGF.SGM.getLoweredType(instanceType)}; |
| } |
| |
| CanAnyMetatypeType objcMetaType; |
| if (isa<MetatypeType>(metaType)) { |
| objcMetaType = |
| CanMetatypeType::get(instanceType, MetatypeRepresentation::ObjC); |
| } else { |
| objcMetaType = CanExistentialMetatypeType::get( |
| instanceType, MetatypeRepresentation::ObjC); |
| } |
| // ObjC metatypes are trivial and thus do not have a cleanup. Only if we |
| // convert them to an object do they become non-trivial. |
| assert(!selfMeta.hasCleanup()); |
| auto result = ManagedValue::forUnmanaged(SGF.B.emitThickToObjCMetatype( |
| loc, selfMeta.getValue(), SGF.SGM.getLoweredType(objcMetaType))); |
| return {result, SGF.SGM.getLoweredType(instanceType)}; |
| } |
| |
| /// Given a metatype value for the type, allocate an Objective-C |
| /// object (with alloc_ref_dynamic) of that type. |
| /// |
| /// \returns the self object. |
| ManagedValue allocateObjCObject(ManagedValue selfMeta, SILLocation loc) { |
| // Convert to an Objective-C metatype representation, if needed. |
| ManagedValue selfMetaObjC; |
| SILType instanceType; |
| std::tie(selfMetaObjC, instanceType) = convertToObjCMetatype(selfMeta, loc); |
| |
| // Allocate the object. |
| return SGF.B.createAllocRefDynamic(loc, selfMetaObjC, instanceType, |
| /*objc=*/true, {}, {}); |
| } |
| |
| void processProtocolMethod(DeclRefExpr *e, AbstractFunctionDecl *afd, |
| ProtocolDecl *proto) { |
| assert(!callSites.empty()); |
| ApplyExpr *thisCallSite = callSites.back(); |
| callSites.pop_back(); |
| |
| ArgumentSource selfValue = thisCallSite->getArg(); |
| |
| SubstitutionList subs = e->getDeclRef().getSubstitutions(); |
| |
| SILDeclRef::Kind kind = SILDeclRef::Kind::Func; |
| if (isa<ConstructorDecl>(afd)) { |
| if (proto->isObjC()) { |
| SILLocation loc = thisCallSite->getArg(); |
| |
| // For Objective-C initializers, we only have an initializing |
| // initializer. We need to allocate the object ourselves. |
| kind = SILDeclRef::Kind::Initializer; |
| |
| auto metatype = std::move(selfValue).getAsSingleValue(SGF); |
| auto allocated = allocateObjCObject(metatype, loc); |
| auto allocatedType = allocated.getType().getSwiftRValueType(); |
| selfValue = |
| ArgumentSource(loc, RValue(SGF, loc, allocatedType, allocated)); |
| } else { |
| // For non-Objective-C initializers, we have an allocating |
| // initializer to call. |
| kind = SILDeclRef::Kind::Allocator; |
| } |
| } |
| |
| SILDeclRef constant(afd, kind); |
| constant = constant.asForeign(afd->isObjC()); |
| |
| // Prepare the callee. |
| Callee theCallee = Callee::forWitnessMethod( |
| SGF, selfValue.getSubstRValueType(), |
| constant, subs, e); |
| |
| setSelfParam(std::move(selfValue), thisCallSite); |
| setCallee(std::move(theCallee)); |
| } |
| |
| bool isClassMethod(DeclRefExpr *e, AbstractFunctionDecl *afd) { |
| if (e->getAccessSemantics() != AccessSemantics::Ordinary) |
| return false; |
| |
| if (getMethodDispatch(afd) == MethodDispatch::Static) |
| return false; |
| |
| if (auto ctor = dyn_cast<ConstructorDecl>(afd)) { |
| // Non-required initializers are statically dispatched. |
| if (!ctor->isRequired()) |
| return false; |
| |
| // Required constructors are statically dispatched when the 'self' |
| // value is statically derived. |
| ApplyExpr *thisCallSite = callSites.back(); |
| assert(thisCallSite->getArg()->getType()->is<AnyMetatypeType>()); |
| if (thisCallSite->getArg()->isStaticallyDerivedMetatype()) |
| return false; |
| } |
| |
| // Ok, we're dynamically dispatched. |
| return true; |
| } |
| |
| void processClassMethod(DeclRefExpr *e, AbstractFunctionDecl *afd) { |
| SILDeclRef::Kind kind; |
| bool requiresAllocRefDynamic = false; |
| |
| if (isa<FuncDecl>(afd)) { |
| kind = SILDeclRef::Kind::Func; |
| } else { |
| if (requiresForeignEntryPoint(afd)) { |
| // When we're performing Objective-C dispatch, we don't have an |
| // allocating constructor to call. So, perform an alloc_ref_dynamic |
| // and pass that along to the initializer. |
| requiresAllocRefDynamic = true; |
| kind = SILDeclRef::Kind::Initializer; |
| } else { |
| kind = SILDeclRef::Kind::Allocator; |
| } |
| } |
| |
| ApplyExpr *thisCallSite = callSites.back(); |
| callSites.pop_back(); |
| |
| // If we require a dynamic allocation of the object here, do so now. |
| if (requiresAllocRefDynamic) { |
| SILLocation loc = thisCallSite->getArg(); |
| RValue selfMetatype = SGF.emitRValue(thisCallSite->getArg()); |
| auto selfValue = |
| allocateObjCObject(std::move(selfMetatype).getAsSingleValue(SGF, loc), loc); |
| RValue self = RValue(SGF, loc, selfValue.getType().getSwiftRValueType(), |
| selfValue); |
| ArgumentSource selfArgSource(thisCallSite->getArg(), std::move(self)); |
| setSelfParam(std::move(selfArgSource), thisCallSite); |
| } else { |
| ArgumentSource selfArgSource(thisCallSite->getArg()); |
| setSelfParam(std::move(selfArgSource), thisCallSite); |
| } |
| |
| auto constant = SILDeclRef(afd, kind) |
| .asForeign(requiresForeignEntryPoint(afd)); |
| |
| auto subs = e->getDeclRef().getSubstitutions(); |
| setCallee(Callee::forClassMethod(SGF, constant, subs, e)); |
| } |
| |
| // |
| // Known callees. |
| // |
| void visitDeclRefExpr(DeclRefExpr *e) { |
| SubstitutionList subs = e->getDeclRef().getSubstitutions(); |
| |
| // If this is a direct reference to a vardecl, just emit its value directly. |
| // Recursive references to callable declarations are allowed. |
| if (isa<VarDecl>(e->getDecl())) { |
| visitExpr(e); |
| return; |
| } |
| |
| // Enum case constructor references are open-coded. |
| if (auto *eed = dyn_cast<EnumElementDecl>(e->getDecl())) { |
| setCallee(Callee::forEnumElement(SGF, SILDeclRef(eed), subs, e)); |
| return; |
| } |
| |
| // Ok, we have a constructor or a function. |
| auto *afd = cast<AbstractFunctionDecl>(e->getDecl()); |
| |
| // Witness method or @objc protocol dispatch. |
| if (auto *proto = dyn_cast<ProtocolDecl>(afd->getDeclContext())) { |
| processProtocolMethod(e, afd, proto); |
| return; |
| } |
| |
| // VTable class method or @objc class method dispatch. |
| if (isClassMethod(e, afd)) { |
| processClassMethod(e, afd); |
| return; |
| } |
| |
| // Otherwise, we have a statically-dispatched call. |
| auto constant = SILDeclRef(e->getDecl()) |
| .asForeign(!isConstructorWithGeneratedAllocatorThunk(e->getDecl()) |
| && requiresForeignEntryPoint(e->getDecl())); |
| |
| auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(afd); |
| if (afd->getDeclContext()->isLocalContext() && |
| !captureInfo.hasGenericParamCaptures()) |
| subs = SubstitutionList(); |
| |
| setCallee(Callee::forDirect(SGF, constant, subs, e)); |
| |
| // If the decl ref requires captures, emit the capture params. |
| if (!captureInfo.getCaptures().empty()) { |
| SmallVector<ManagedValue, 4> captures; |
| SGF.emitCaptures(e, afd, CaptureEmission::ImmediateApplication, |
| captures); |
| applyCallee->setCaptures(std::move(captures)); |
| } |
| } |
| |
| void visitAbstractClosureExpr(AbstractClosureExpr *e) { |
| // Emit the closure body. |
| SGF.SGM.emitClosure(e); |
| |
| // If we're in top-level code, we don't need to physically capture script |
| // globals, but we still need to mark them as escaping so that DI can flag |
| // uninitialized uses. |
| if (&SGF == SGF.SGM.TopLevelSGF) { |
| SGF.SGM.emitMarkFunctionEscapeForTopLevelCodeGlobals(e,e->getCaptureInfo()); |
| } |
| |
| // A directly-called closure can be emitted as a direct call instead of |
| // really producing a closure object. |
| SILDeclRef constant(e); |
| |
| SubstitutionList subs; |
| if (e->getCaptureInfo().hasGenericParamCaptures()) |
| subs = SGF.getForwardingSubstitutions(); |
| |
| setCallee(Callee::forDirect(SGF, constant, subs, e)); |
| |
| // If the closure requires captures, emit them. |
| bool hasCaptures = SGF.SGM.M.Types.hasLoweredLocalCaptures(e); |
| if (hasCaptures) { |
| SmallVector<ManagedValue, 4> captures; |
| SGF.emitCaptures(e, e, CaptureEmission::ImmediateApplication, |
| captures); |
| applyCallee->setCaptures(std::move(captures)); |
| } |
| } |
| |
| void visitOtherConstructorDeclRefExpr(OtherConstructorDeclRefExpr *e) { |
| auto subs = e->getDeclRef().getSubstitutions(); |
| |
| // FIXME: We might need to go through ObjC dispatch for references to |
| // constructors imported from Clang (which won't have a direct entry point) |
| // or to delegate to a designated initializer. |
| setCallee(Callee::forDirect(SGF, |
| SILDeclRef(e->getDecl(), SILDeclRef::Kind::Initializer), subs, e)); |
| } |
| |
| void visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *e) { |
| setSideEffect(e->getLHS()); |
| visit(e->getRHS()); |
| } |
| |
| void visitFunctionConversionExpr(FunctionConversionExpr *e) { |
| // FIXME: Check whether this function conversion requires us to build a |
| // thunk. |
| visit(e->getSubExpr()); |
| } |
| |
| void visitCovariantFunctionConversionExpr(CovariantFunctionConversionExpr *e){ |
| // FIXME: These expressions merely adjust the result type for DynamicSelf |
| // in an unchecked, ABI-compatible manner. They shouldn't prevent us form |
| // forming a complete call. |
| visitExpr(e); |
| } |
| |
| void visitImplicitlyUnwrappedFunctionConversionExpr( |
| ImplicitlyUnwrappedFunctionConversionExpr *e) { |
| // These are generated for short term use in the type checker. |
| llvm_unreachable( |
| "We should not see ImplicitlyUnwrappedFunctionConversionExpr here"); |
| } |
| |
| void visitIdentityExpr(IdentityExpr *e) { |
| visit(e->getSubExpr()); |
| } |
| |
| void applySuper(ApplyExpr *apply) { |
| // Load the 'super' argument. |
| Expr *arg = apply->getArg(); |
| RValue super; |
| CanType superFormalType = arg->getType()->getCanonicalType(); |
| |
| // The callee for a super call has to be either a method or constructor. |
| Expr *fn = apply->getFn(); |
| SubstitutionList substitutions; |
| SILDeclRef constant; |
| if (auto *ctorRef = dyn_cast<OtherConstructorDeclRefExpr>(fn)) { |
| constant = SILDeclRef(ctorRef->getDecl(), SILDeclRef::Kind::Initializer) |
| .asForeign(requiresForeignEntryPoint(ctorRef->getDecl())); |
| |
| if (ctorRef->getDeclRef().isSpecialized()) |
| substitutions = ctorRef->getDeclRef().getSubstitutions(); |
| |
| assert(SGF.SelfInitDelegationState == |
| SILGenFunction::WillSharedBorrowSelf); |
| SGF.SelfInitDelegationState = SILGenFunction::WillExclusiveBorrowSelf; |
| super = SGF.emitRValue(arg); |
| assert(SGF.SelfInitDelegationState == |
| SILGenFunction::DidExclusiveBorrowSelf); |
| |
| // We know that we have a single ManagedValue rvalue for self. |
| ManagedValue superMV = std::move(super).getScalarValue(); |
| |
| // Check if super is not the same as our base type. This means that we |
| // performed an upcast, and we must have consumed the special cleanup |
| // we installed. Install a new special cleanup. |
| if (superMV.getValue() != SGF.InitDelegationSelf.getValue()) { |
| SILValue underlyingSelf = SGF.InitDelegationSelf.getValue(); |
| SGF.InitDelegationSelf = ManagedValue::forUnmanaged(underlyingSelf); |
| CleanupHandle newWriteback = SGF.enterDelegateInitSelfWritebackCleanup( |
| SGF.InitDelegationLoc.getValue(), SGF.InitDelegationSelfBox, |
| superMV.forward(SGF)); |
| SGF.SuperInitDelegationSelf = |
| ManagedValue(superMV.getValue(), newWriteback); |
| super = RValue(SGF, SGF.InitDelegationLoc.getValue(), superFormalType, |
| SGF.SuperInitDelegationSelf); |
| } |
| |
| } else if (auto *declRef = dyn_cast<DeclRefExpr>(fn)) { |
| assert(isa<FuncDecl>(declRef->getDecl()) && "non-function super call?!"); |
| constant = SILDeclRef(declRef->getDecl()) |
| .asForeign(requiresForeignEntryPoint(declRef->getDecl())); |
| |
| if (declRef->getDeclRef().isSpecialized()) |
| substitutions = declRef->getDeclRef().getSubstitutions(); |
| super = SGF.emitRValue(arg); |
| } else { |
| llvm_unreachable("invalid super callee"); |
| } |
| |
| assert(super.isComplete() && "At this point super should be a complete " |
| "rvalue that is not in any special states"); |
| ArgumentSource superArgSource(arg, std::move(super)); |
| if (!canUseStaticDispatch(SGF, constant)) { |
| // ObjC super calls require dynamic dispatch. |
| setCallee(Callee::forSuperMethod(SGF, constant, substitutions, fn)); |
| } else { |
| // Native Swift super calls to final methods are direct. |
| setCallee(Callee::forDirect(SGF, constant, substitutions, fn)); |
| } |
| |
| setSelfParam(std::move(superArgSource), apply); |
| } |
| |
| /// Walk the given \c selfArg expression that produces the appropriate |
| /// `self` for a call, applying the same transformations to the provided |
| /// \c selfValue (which might be a metatype). |
| /// |
| /// This is used for initializer delegation, so it covers only the narrow |
| /// subset of expressions used there. |
| ManagedValue emitCorrespondingSelfValue(ManagedValue selfValue, |
| Expr *selfArg) { |
| while (true) { |
| // Handle archetype-to-super and derived-to-base upcasts. |
| if (isa<ArchetypeToSuperExpr>(selfArg) || |
| isa<DerivedToBaseExpr>(selfArg)) { |
| auto ice = cast<ImplicitConversionExpr>(selfArg); |
| auto resultTy = ice->getType()->getCanonicalType(); |
| |
| // If the 'self' value is a metatype, update the target type |
| // accordingly. |
| if (auto selfMetaTy = selfValue.getType().getAs<AnyMetatypeType>()) { |
| resultTy = CanMetatypeType::get(resultTy, |
| selfMetaTy->getRepresentation()); |
| } |
| auto loweredResultTy = SGF.getLoweredLoadableType(resultTy); |
| if (loweredResultTy != selfValue.getType()) { |
| selfValue = SGF.emitManagedRValueWithCleanup( |
| SGF.B.createUpcast(ice, selfValue.forward(SGF), loweredResultTy)); |
| } |
| |
| selfArg = ice->getSubExpr(); |
| continue; |
| } |
| |
| // Skip over loads. |
| if (auto load = dyn_cast<LoadExpr>(selfArg)) { |
| selfArg = load->getSubExpr(); |
| continue; |
| } |
| |
| // Skip over inout expressions. |
| if (auto inout = dyn_cast<InOutExpr>(selfArg)) { |
| selfArg = inout->getSubExpr(); |
| continue; |
| } |
| |
| // Declaration references terminate the search. |
| if (isa<DeclRefExpr>(selfArg)) |
| break; |
| |
| llvm_unreachable("unhandled conversion for metatype value"); |
| } |
| |
| return selfValue; |
| } |
| |
| /// Try to emit the given application as initializer delegation. |
| bool applyInitDelegation(ApplyExpr *expr) { |
| // Dig out the constructor we're delegating to. |
| Expr *fn = expr->getFn(); |
| auto ctorRef = dyn_cast<OtherConstructorDeclRefExpr>( |
| fn->getSemanticsProvidingExpr()); |
| if (!ctorRef) |
| return false; |
| |
| // Determine whether we'll need to use an allocating constructor (vs. the |
| // initializing constructor). |
| auto nominal = ctorRef->getDecl()->getDeclContext() |
| ->getAsNominalTypeOrNominalTypeExtensionContext(); |
| bool useAllocatingCtor; |
| |
| // Value types only have allocating initializers. |
| if (isa<StructDecl>(nominal) || isa<EnumDecl>(nominal)) |
| useAllocatingCtor = true; |
| // Protocols only witness allocating initializers, except for @objc |
| // protocols, which only witness initializing initializers. |
| else if (auto proto = dyn_cast<ProtocolDecl>(nominal)) { |
| useAllocatingCtor = !proto->isObjC(); |
| // Factory initializers are effectively "allocating" initializers with no |
| // corresponding initializing entry point. |
| } else if (ctorRef->getDecl()->isFactoryInit()) { |
| useAllocatingCtor = true; |
| } else { |
| // We've established we're in a class initializer or a protocol extension |
| // initializer for a class-bound protocol, In either case, we're |
| // delegating initialization, but we only have an instance in the former |
| // case. |
| assert(isa<ClassDecl>(nominal) |
| && "some new kind of init context we haven't implemented"); |
| useAllocatingCtor = static_cast<bool>(SGF.AllocatorMetatype) && |
| !ctorRef->getDecl()->isObjC(); |
| } |
| |
| // Load the 'self' argument. |
| Expr *arg = expr->getArg(); |
| ManagedValue self; |
| CanType selfFormalType = arg->getType()->getCanonicalType(); |
| |
| // If we're using the allocating constructor, we need to pass along the |
| // metatype. |
| if (useAllocatingCtor) { |
| selfFormalType = CanMetatypeType::get( |
| selfFormalType->getInOutObjectType()->getCanonicalType()); |
| |
| // If the initializer is a C function imported as a member, |
| // there is no 'self' parameter. Mark it undef. |
| if (ctorRef->getDecl()->isImportAsMember()) { |
| self = SGF.emitUndef(expr, selfFormalType); |
| } else if (SGF.AllocatorMetatype) { |
| self = emitCorrespondingSelfValue( |
| ManagedValue::forUnmanaged(SGF.AllocatorMetatype), arg); |
| } else { |
| self = ManagedValue::forUnmanaged(SGF.emitMetatypeOfValue(expr, arg)); |
| } |
| } else { |
| // If we're in a protocol extension initializer, we haven't allocated |
| // "self" yet at this point. Do so. Use alloc_ref_dynamic since we should |
| // only ever get here in ObjC protocol extensions currently. |
| if (SGF.AllocatorMetatype) { |
| assert(ctorRef->getDecl()->isObjC() |
| && "only expect to delegate an initializer from an allocator " |
| "in objc protocol extensions"); |
| |
| self = allocateObjCObject( |
| ManagedValue::forUnmanaged(SGF.AllocatorMetatype), arg); |
| |
| // Perform any adjustments needed to 'self'. |
| self = emitCorrespondingSelfValue(self, arg); |
| } else { |
| assert(SGF.SelfInitDelegationState == |
| SILGenFunction::WillSharedBorrowSelf); |
| SGF.SelfInitDelegationState = SILGenFunction::WillExclusiveBorrowSelf; |
| self = SGF.emitRValueAsSingleValue(arg); |
| assert(SGF.SelfInitDelegationState == |
| SILGenFunction::DidExclusiveBorrowSelf); |
| } |
| } |
| |
| auto subs = ctorRef->getDeclRef().getSubstitutions(); |
| ArgumentSource selfArgSource(arg, RValue(SGF, expr, selfFormalType, self)); |
| |
| SILDeclRef constant(ctorRef->getDecl(), |
| useAllocatingCtor |
| ? SILDeclRef::Kind::Allocator |
| : SILDeclRef::Kind::Initializer); |
| |
| constant = constant.asForeign(requiresForeignEntryPoint(ctorRef->getDecl())); |
| |
| // Determine the callee. For structs and enums, this is the allocating |
| // constructor (because there is no initializing constructor). For protocol |
| // default implementations, we also use the allocating constructor, because |
| // that's the only thing that's witnessed. For classes, |
| // this is the initializing constructor, to which we will dynamically |
| // dispatch. |
| if (isa<ProtocolDecl>(ctorRef->getDecl()->getDeclContext())) { |
| // Look up the witness for the constructor. |
| setCallee(Callee::forWitnessMethod( |
| SGF, self.getType().getSwiftRValueType(), |
| constant, subs, expr)); |
| } else if (getMethodDispatch(ctorRef->getDecl()) |
| == MethodDispatch::Class) { |
| // Dynamic dispatch to the initializer. |
| Scope S(SGF, expr); |
| setCallee(Callee::forClassMethod( |
| SGF, constant, subs, fn)); |
| } else { |
| // Directly call the peer constructor. |
| setCallee( |
| Callee::forDirect(SGF, constant, subs, fn)); |
| } |
| |
| setSelfParam(std::move(selfArgSource), expr); |
| |
| return true; |
| } |
| |
| Callee getCallee() { |
| assert(applyCallee && "did not find callee?!"); |
| return std::move(*applyCallee); |
| } |
| |
| /// Ignore parentheses and implicit conversions. |
| static Expr *ignoreParensAndImpConversions(Expr *expr) { |
| while (true) { |
| if (auto ice = dyn_cast<ImplicitConversionExpr>(expr)) { |
| expr = ice->getSubExpr(); |
| continue; |
| } |
| |
| // Simple optional-to-optional conversions. This doesn't work |
| // for the full generality of OptionalEvaluationExpr, but it |
| // works given that we check the result for certain forms. |
| if (auto eval = dyn_cast<OptionalEvaluationExpr>(expr)) { |
| if (auto inject = dyn_cast<InjectIntoOptionalExpr>(eval->getSubExpr())) { |
| if (auto bind = dyn_cast<BindOptionalExpr>(inject->getSubExpr())) { |
| if (bind->getDepth() == 0) |
| return bind->getSubExpr(); |
| } |
| } |
| } |
| |
| auto valueProviding = expr->getValueProvidingExpr(); |
| if (valueProviding != expr) { |
| expr = valueProviding; |
| continue; |
| } |
| |
| return expr; |
| } |
| } |
| |
| void visitForceValueExpr(ForceValueExpr *e) { |
| // If this application is a dynamic member reference that is forced to |
| // succeed with the '!' operator, emit it as a direct invocation of the |
| // method we found. |
| if (emitForcedDynamicMemberRef(e)) |
| return; |
| |
| visitExpr(e); |
| } |
| |
| /// If this application forces a dynamic member reference with !, emit |
| /// a direct reference to the member. |
| bool emitForcedDynamicMemberRef(ForceValueExpr *e) { |
| // Check whether the argument is a dynamic member reference. |
| auto arg = ignoreParensAndImpConversions(e->getSubExpr()); |
| |
| auto openExistential = dyn_cast<OpenExistentialExpr>(arg); |
| if (openExistential) |
| arg = openExistential->getSubExpr(); |
| |
| auto dynamicMemberRef = dyn_cast<DynamicMemberRefExpr>(arg); |
| if (!dynamicMemberRef) |
| return false; |
| |
| // Since we'll be collapsing this call site, make sure there's another |
| // call site that will actually perform the invocation. |
| if (callSites.empty()) |
| return false; |
| |
| // Only @objc methods can be forced. |
| auto memberRef = dynamicMemberRef->getMember(); |
| auto *fd = dyn_cast<FuncDecl>(memberRef.getDecl()); |
| if (!fd || !fd->isObjC()) |
| return false; |
| |
| // Local function that actually emits the dynamic member reference. |
| auto emitDynamicMemberRef = [&] { |
| // We found it. Emit the base. |
| ArgumentSource baseArgSource(dynamicMemberRef->getBase(), |
| SGF.emitRValue(dynamicMemberRef->getBase())); |
| |
| // Determine the type of the method we referenced, by replacing the |
| // class type of the 'Self' parameter with AnyObject. |
| auto member = SILDeclRef(fd).asForeign(); |
| |
| auto substFormalType = cast<FunctionType>(dynamicMemberRef->getType() |
| ->getCanonicalType() |
| .getOptionalObjectType()); |
| substFormalType = CanFunctionType::get( |
| dynamicMemberRef->getBase()->getType()->getCanonicalType(), |
| substFormalType, AnyFunctionType::ExtInfo()); |
| |
| setCallee(Callee::forDynamic(SGF, member, memberRef.getSubstitutions(), |
| substFormalType, {}, e)); |
| setSelfParam(std::move(baseArgSource), dynamicMemberRef); |
| }; |
| |
| // When we have an open existential, open it and then emit the |
| // member reference. |
| if (openExistential) { |
| SGF.emitOpenExistentialExpr(openExistential, |
| [&](Expr*) { emitDynamicMemberRef(); }); |
| } else { |
| emitDynamicMemberRef(); |
| } |
| return true; |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| static RValue emitStringLiteral(SILGenFunction &SGF, Expr *E, StringRef Str, |
| SGFContext C, |
| StringLiteralExpr::Encoding encoding) { |
| uint64_t Length; |
| bool isASCII = true; |
| for (unsigned char c : Str) { |
| if (c > 127) { |
| isASCII = false; |
| break; |
| } |
| } |
| bool useConstantStringBuiltin = false; |
| StringLiteralInst::Encoding instEncoding; |
| ConstStringLiteralInst::Encoding constInstEncoding; |
| switch (encoding) { |
| case StringLiteralExpr::UTF8: |
| instEncoding = StringLiteralInst::Encoding::UTF8; |
| Length = Str.size(); |
| break; |
| |
| case StringLiteralExpr::UTF16: { |
| instEncoding = StringLiteralInst::Encoding::UTF16; |
| Length = unicode::getUTF16Length(Str); |
| break; |
| } |
| case StringLiteralExpr::UTF8ConstString: |
| constInstEncoding = ConstStringLiteralInst::Encoding::UTF8; |
| useConstantStringBuiltin = true; |
| break; |
| |
| case StringLiteralExpr::UTF16ConstString: { |
| constInstEncoding = ConstStringLiteralInst::Encoding::UTF16; |
| useConstantStringBuiltin = true; |
| break; |
| } |
| case StringLiteralExpr::OneUnicodeScalar: { |
| SILType Int32Ty = SILType::getBuiltinIntegerType(32, SGF.getASTContext()); |
| SILValue UnicodeScalarValue = |
| SGF.B.createIntegerLiteral(E, Int32Ty, |
| unicode::extractFirstUnicodeScalar(Str)); |
| return RValue(SGF, E, Int32Ty.getSwiftRValueType(), |
| ManagedValue::forUnmanaged(UnicodeScalarValue)); |
| } |
| } |
| |
| // Should we build a constant string literal? |
| if (useConstantStringBuiltin) { |
| auto *string = SGF.B.createConstStringLiteral(E, Str, constInstEncoding); |
| ManagedValue Elts[] = {ManagedValue::forUnmanaged(string)}; |
| TupleTypeElt TypeElts[] = {Elts[0].getType().getSwiftRValueType()}; |
| CanType ty = |
| TupleType::get(TypeElts, SGF.getASTContext())->getCanonicalType(); |
| return RValue(SGF, Elts, ty); |
| } |
| |
| // The string literal provides the data. |
| auto *string = SGF.B.createStringLiteral(E, Str, instEncoding); |
| |
| // The length is lowered as an integer_literal. |
| auto WordTy = SILType::getBuiltinWordType(SGF.getASTContext()); |
| auto *lengthInst = SGF.B.createIntegerLiteral(E, WordTy, Length); |
| |
| // The 'isascii' bit is lowered as an integer_literal. |
| auto Int1Ty = SILType::getBuiltinIntegerType(1, SGF.getASTContext()); |
| auto *isASCIIInst = SGF.B.createIntegerLiteral(E, Int1Ty, isASCII); |
| |
| ManagedValue EltsArray[] = { |
| ManagedValue::forUnmanaged(string), |
| ManagedValue::forUnmanaged(lengthInst), |
| ManagedValue::forUnmanaged(isASCIIInst) |
| }; |
| |
| TupleTypeElt TypeEltsArray[] = { |
| EltsArray[0].getType().getSwiftRValueType(), |
| EltsArray[1].getType().getSwiftRValueType(), |
| EltsArray[2].getType().getSwiftRValueType() |
| }; |
| |
| ArrayRef<ManagedValue> Elts; |
| ArrayRef<TupleTypeElt> TypeElts; |
| switch (instEncoding) { |
| case StringLiteralInst::Encoding::UTF16: |
| Elts = llvm::makeArrayRef(EltsArray).slice(0, 2); |
| TypeElts = llvm::makeArrayRef(TypeEltsArray).slice(0, 2); |
| break; |
| |
| case StringLiteralInst::Encoding::UTF8: |
| Elts = EltsArray; |
| TypeElts = TypeEltsArray; |
| break; |
| |
| case StringLiteralInst::Encoding::ObjCSelector: |
| llvm_unreachable("Objective-C selectors cannot be formed here"); |
| } |
| |
| CanType ty = |
| TupleType::get(TypeElts, SGF.getASTContext())->getCanonicalType(); |
| return RValue(SGF, Elts, ty); |
| } |
| |
| /// Emit a raw apply operation, performing no additional lowering of |
| /// either the arguments or the result. |
| static SILValue emitRawApply(SILGenFunction &SGF, |
| SILLocation loc, |
| ManagedValue fn, |
| SubstitutionList subs, |
| ArrayRef<ManagedValue> args, |
| CanSILFunctionType substFnType, |
| ApplyOptions options, |
| ArrayRef<SILValue> indirectResultAddrs) { |
| SILFunctionConventions substFnConv(substFnType, SGF.SGM.M); |
| // Get the callee value. |
| bool isConsumed = substFnType->isCalleeConsumed(); |
| bool isUnowned = substFnType->isCalleeUnowned(); |
| SILValue fnValue = |
| isUnowned ? fn.getValue() |
| : isConsumed ? fn.forward(SGF) : fn.borrow(SGF, loc).getValue(); |
| |
| SmallVector<SILValue, 4> argValues; |
| |
| // Add the buffers for the indirect results if needed. |
| #ifndef NDEBUG |
| assert(indirectResultAddrs.size() == substFnConv.getNumIndirectSILResults()); |
| unsigned resultIdx = 0; |
| for (auto indResultTy : substFnConv.getIndirectSILResultTypes()) { |
| assert(indResultTy == indirectResultAddrs[resultIdx++]->getType()); |
| } |
| #endif |
| argValues.append(indirectResultAddrs.begin(), indirectResultAddrs.end()); |
| |
| auto inputParams = substFnType->getParameters(); |
| assert(inputParams.size() == args.size()); |
| |
| // Gather the arguments. |
| for (auto i : indices(args)) { |
| auto argValue = (inputParams[i].isConsumed() ? args[i].forward(SGF) |
| : args[i].getValue()); |
| #ifndef NDEBUG |
| auto inputTy = substFnConv.getSILType(inputParams[i]); |
| if (argValue->getType() != inputTy) { |
| auto &out = llvm::errs(); |
| out << "TYPE MISMATCH IN ARGUMENT " << i << " OF APPLY AT "; |
| printSILLocationDescription(out, loc, SGF.getASTContext()); |
| out << " argument value: "; |
| argValue->print(out); |
| out << " parameter type: "; |
| inputTy.print(out); |
| out << "\n"; |
| abort(); |
| } |
| #endif |
| argValues.push_back(argValue); |
| } |
| |
| auto resultType = substFnConv.getSILResultType(); |
| auto calleeType = SILType::getPrimitiveObjectType(substFnType); |
| |
| // If we don't have an error result, we can make a simple 'apply'. |
| SILValue result; |
| if (!substFnType->hasErrorResult()) { |
| result = SGF.B.createApply(loc, fnValue, calleeType, |
| resultType, subs, argValues); |
| |
| // Otherwise, we need to create a try_apply. |
| } else { |
| SILBasicBlock *normalBB = SGF.createBasicBlock(); |
| result = normalBB->createPHIArgument(resultType, ValueOwnershipKind::Owned); |
| |
| SILBasicBlock *errorBB = |
| SGF.getTryApplyErrorDest(loc, substFnType->getErrorResult(), |
| options & ApplyOptions::DoesNotThrow); |
| |
| SGF.B.createTryApply(loc, fnValue, calleeType, subs, argValues, |
| normalBB, errorBB); |
| SGF.B.emitBlock(normalBB); |
| } |
| return result; |
| } |
| |
| static bool hasUnownedInnerPointerResult(CanSILFunctionType fnType) { |
| for (auto result : fnType->getResults()) { |
| if (result.getConvention() == ResultConvention::UnownedInnerPointer) |
| return true; |
| } |
| return false; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Argument Emission |
| //===----------------------------------------------------------------------===// |
| |
| /// Count the number of SILParameterInfos that are needed in order to |
| /// pass the given argument. |
| static unsigned getFlattenedValueCount(AbstractionPattern origType, |
| CanType substType, |
| ImportAsMemberStatus foreignSelf) { |
| // C functions imported as static methods don't consume any real arguments. |
| if (foreignSelf.isStatic()) |
| return 0; |
| |
| // The count is always 1 unless the substituted type is a tuple. |
| auto substTuple = dyn_cast<TupleType>(substType); |
| if (!substTuple) return 1; |
| |
| // If the original type is opaque and the substituted type is |
| // materializable, the count is 1 anyway. |
| if (origType.isTypeParameter() && substTuple->isMaterializable()) |
| return 1; |
| |
| // Otherwise, add up the elements. |
| unsigned count = 0; |
| for (auto i : indices(substTuple.getElementTypes())) { |
| count += getFlattenedValueCount(origType.getTupleElementType(i), |
| substTuple.getElementType(i), |
| ImportAsMemberStatus()); |
| } |
| return count; |
| } |
| |
| static AbstractionPattern claimNextParamClause(AbstractionPattern &type) { |
| auto result = type.getFunctionInputType(); |
| type = type.getFunctionResultType(); |
| return result; |
| } |
| |
| static CanType claimNextParamClause(CanAnyFunctionType &type) { |
| auto result = type.getInput(); |
| type = dyn_cast<AnyFunctionType>(type.getResult()); |
| return result; |
| } |
| |
| namespace { |
| |
| /// The original argument expression for some sort of complex |
| /// argument emission. |
| class OriginalArgument { |
| llvm::PointerIntPair<Expr*, 1, bool> ExprAndIsIndirect; |
| |
| public: |
| OriginalArgument() = default; |
| OriginalArgument(Expr *expr, bool indirect) |
| : ExprAndIsIndirect(expr, indirect) {} |
| |
| Expr *getExpr() const { return ExprAndIsIndirect.getPointer(); } |
| bool isIndirect() const { return ExprAndIsIndirect.getInt(); } |
| }; |
| |
| /// A delayed argument. Call arguments are evaluated in two phases: |
| /// a formal evaluation phase and a formal access phase. The primary |
| /// example of this is an l-value that is passed by reference, where |
| /// the access to the l-value does not begin until the formal access |
| /// phase, but there are other examples, generally relating to pointer |
| /// conversions. |
| /// |
| /// A DelayedArgument represents the part of evaluating an argument |
| /// that's been delayed until the formal access phase. |
| class DelayedArgument { |
| public: |
| enum KindTy { |
| /// This is a true inout argument. |
| InOut, |
| |
| /// This is a borrowed direct argument. |
| BorrowDirect, |
| |
| /// This is a borrowed indirect argument. |
| BorrowIndirect, |
| |
| LastLVKindWithoutExtra = BorrowIndirect, |
| |
| /// The l-value needs to be converted to a pointer type. |
| LValueToPointer, |
| |
| /// An array l-value needs to be converted to a pointer type. |
| LValueArrayToPointer, |
| |
| LastLVKind = LValueArrayToPointer, |
| |
| /// An array r-value needs to be converted to a pointer type. |
| RValueArrayToPointer, |
| |
| /// A string r-value needs to be converted to a pointer type. |
| RValueStringToPointer, |
| }; |
| |
| private: |
| KindTy Kind; |
| |
| struct LValueStorage { |
| LValue LV; |
| SILLocation Loc; |
| |
| LValueStorage(LValue &&lv, SILLocation loc) : LV(std::move(lv)), Loc(loc) {} |
| }; |
| struct RValueStorage { |
| ManagedValue RV; |
| |
| RValueStorage(ManagedValue rv) : RV(rv) {} |
| }; |
| |
| using ValueMembers = ExternalUnionMembers<RValueStorage, LValueStorage>; |
| static ValueMembers::Index getValueMemberIndexForKind(KindTy kind) { |
| return (kind <= LastLVKind ? ValueMembers::indexOf<LValueStorage>() |
| : ValueMembers::indexOf<RValueStorage>()); |
| } |
| |
| /// Storage for either the l-value or the r-value. |
| ExternalUnion<KindTy, ValueMembers, getValueMemberIndexForKind> Value; |
| |
| LValueStorage &LV() { return Value.get<LValueStorage>(Kind); } |
| const LValueStorage &LV() const { return Value.get<LValueStorage>(Kind); } |
| RValueStorage &RV() { return Value.get<RValueStorage>(Kind); } |
| const RValueStorage &RV() const { return Value.get<RValueStorage>(Kind); } |
| |
| /// The original argument expression, which will be emitted down |
| /// to the point from which the l-value or r-value was generated. |
| OriginalArgument Original; |
| |
| using PointerAccessInfo = SILGenFunction::PointerAccessInfo; |
| using ArrayAccessInfo = SILGenFunction::ArrayAccessInfo; |
| |
| using ExtraMembers = |
| ExternalUnionMembers<void, ArrayAccessInfo, PointerAccessInfo>; |
| static ExtraMembers::Index getExtraMemberIndexForKind(KindTy kind) { |
| switch (kind) { |
| case LValueToPointer: |
| return ExtraMembers::indexOf<PointerAccessInfo>(); |
| case LValueArrayToPointer: |
| case RValueArrayToPointer: |
| return ExtraMembers::indexOf<ArrayAccessInfo>(); |
| default: |
| return ExtraMembers::indexOf<void>(); |
| } |
| } |
| |
| ExternalUnion<KindTy, ExtraMembers, getExtraMemberIndexForKind> Extra; |
| |
| public: |
| DelayedArgument(KindTy kind, LValue &&lv, SILLocation loc) |
| : Kind(kind) { |
| assert(kind <= LastLVKindWithoutExtra && |
| "this constructor should only be used for simple l-value kinds"); |
| Value.emplace<LValueStorage>(Kind, std::move(lv), loc); |
| } |
| |
| DelayedArgument(KindTy kind, ManagedValue rv, OriginalArgument original) |
| : Kind(kind), Original(original) { |
| Value.emplace<RValueStorage>(Kind, rv); |
| } |
| |
| DelayedArgument(SILGenFunction::PointerAccessInfo pointerInfo, |
| LValue &&lv, SILLocation loc, OriginalArgument original) |
| : Kind(LValueToPointer), Original(original) { |
| Value.emplace<LValueStorage>(Kind, std::move(lv), loc); |
| Extra.emplace<PointerAccessInfo>(Kind, pointerInfo); |
| } |
| |
| DelayedArgument(SILGenFunction::ArrayAccessInfo arrayInfo, |
| LValue &&lv, SILLocation loc, OriginalArgument original) |
| : Kind(LValueArrayToPointer), Original(original) { |
| Value.emplace<LValueStorage>(Kind, std::move(lv), loc); |
| Extra.emplace<ArrayAccessInfo>(Kind, arrayInfo); |
| } |
| |
| DelayedArgument(KindTy kind, |
| SILGenFunction::ArrayAccessInfo arrayInfo, |
| ManagedValue rv, OriginalArgument original) |
| : Kind(kind), Original(original) { |
| Value.emplace<RValueStorage>(Kind, rv); |
| Extra.emplace<ArrayAccessInfo>(Kind, arrayInfo); |
| } |
| |
| DelayedArgument(DelayedArgument &&other) |
| : Kind(other.Kind), Original(other.Original) { |
| Value.moveConstruct(Kind, std::move(other.Value)); |
| Extra.moveConstruct(Kind, std::move(other.Extra)); |
| } |
| |
| DelayedArgument &operator=(DelayedArgument &&other) { |
| Value.moveAssign(Kind, other.Kind, std::move(other.Value)); |
| Extra.moveAssign(Kind, other.Kind, std::move(other.Extra)); |
| Kind = other.Kind; |
| Original = other.Original; |
| return *this; |
| } |
| |
| ~DelayedArgument() { |
| Extra.destruct(Kind); |
| Value.destruct(Kind); |
| } |
| |
| bool isSimpleInOut() const { return Kind == InOut; } |
| SILLocation getInOutLocation() const { |
| assert(isSimpleInOut()); |
| return LV().Loc; |
| } |
| |
| ManagedValue emit(SILGenFunction &SGF) { |
| switch (Kind) { |
| case InOut: |
| return emitInOut(SGF); |
| case BorrowDirect: |
| return emitBorrowDirect(SGF); |
| case BorrowIndirect: |
| return emitBorrowIndirect(SGF); |
| case LValueToPointer: |
| case LValueArrayToPointer: |
| case RValueArrayToPointer: |
| case RValueStringToPointer: |
| return finishOriginalArgument(SGF); |
| } |
| llvm_unreachable("bad kind"); |
| } |
| |
| private: |
| ManagedValue emitInOut(SILGenFunction &SGF) { |
| return emitAddress(SGF, AccessKind::ReadWrite); |
| } |
| |
| ManagedValue emitBorrowIndirect(SILGenFunction &SGF) { |
| return emitAddress(SGF, AccessKind::Read); |
| } |
| |
| ManagedValue emitBorrowDirect(SILGenFunction &SGF) { |
| ManagedValue address = emitAddress(SGF, AccessKind::Read); |
| return SGF.B.createLoadBorrow(LV().Loc, address); |
| } |
| |
| ManagedValue emitAddress(SILGenFunction &SGF, AccessKind accessKind) { |
| auto tsanKind = |
| (accessKind == AccessKind::Read ? TSanKind::None : TSanKind::InoutAccess); |
| return SGF.emitAddressOfLValue(LV().Loc, std::move(LV().LV), |
| accessKind, tsanKind); |
| } |
| |
| /// Replay the original argument expression. |
| ManagedValue finishOriginalArgument(SILGenFunction &SGF) { |
| auto results = finishOriginalExpr(SGF, Original.getExpr()); |
| auto value = results.first; // just let the owner go |
| |
| if (Original.isIndirect() && !value.getType().isAddress()) { |
| value = value.materialize(SGF, Original.getExpr()); |
| } |
| |
| return value; |
| } |
| |
| // (value, owner) |
| std::pair<ManagedValue, ManagedValue> |
| finishOriginalExpr(SILGenFunction &SGF, Expr *expr) { |
| |
| // This needs to handle all of the recursive cases from |
| // ArgEmission::maybeEmitDelayed. |
| |
| expr = expr->getSemanticsProvidingExpr(); |
| |
| // Handle injections into optionals. |
| if (auto inject = dyn_cast<InjectIntoOptionalExpr>(expr)) { |
| auto ownedValue = |
| finishOriginalExpr(SGF, inject->getSubExpr()); |
| auto &optionalTL = SGF.getTypeLowering(expr->getType()); |
| |
| auto optValue = SGF.emitInjectOptional(inject, optionalTL, SGFContext(), |
| [&](SGFContext ctx) { return ownedValue.first; }); |
| return {optValue, ownedValue.second}; |
| } |
| |
| // Handle try!. |
| if (auto forceTry = dyn_cast<ForceTryExpr>(expr)) { |
| // Handle throws from the accessor? But what if the writeback throws? |
| SILGenFunction::ForceTryEmission emission(SGF, forceTry); |
| return finishOriginalExpr(SGF, forceTry->getSubExpr()); |
| } |
| |
| // Handle optional evaluations. |
| if (auto optEval = dyn_cast<OptionalEvaluationExpr>(expr)) { |
| return finishOptionalEvaluation(SGF, optEval); |
| } |
| |
| // Done with the recursive cases. Make sure we handled everything. |
| assert(isa<InOutToPointerExpr>(expr) || |
| isa<ArrayToPointerExpr>(expr) || |
| isa<StringToPointerExpr>(expr)); |
| |
| switch (Kind) { |
| case InOut: |
| case BorrowDirect: |
| case BorrowIndirect: |
| llvm_unreachable("no original expr to finish in these cases"); |
| |
| case LValueToPointer: |
| return {SGF.emitLValueToPointer(LV().Loc, std::move(LV().LV), |
| Extra.get<PointerAccessInfo>(Kind)), |
| /*owner*/ ManagedValue()}; |
| |
| case LValueArrayToPointer: |
| return SGF.emitArrayToPointer(LV().Loc, std::move(LV().LV), |
| Extra.get<ArrayAccessInfo>(Kind)); |
| |
| case RValueArrayToPointer: { |
| auto pointerExpr = cast<ArrayToPointerExpr>(expr); |
| auto optArrayValue = RV().RV; |
| auto arrayValue = emitBindOptionals(SGF, optArrayValue, |
| pointerExpr->getSubExpr()); |
| return SGF.emitArrayToPointer(pointerExpr, arrayValue, |
| Extra.get<ArrayAccessInfo>(Kind)); |
| } |
| |
| case RValueStringToPointer: { |
| auto pointerExpr = cast<StringToPointerExpr>(expr); |
| auto optStringValue = RV().RV; |
| auto stringValue = |
| emitBindOptionals(SGF, optStringValue, pointerExpr->getSubExpr()); |
| return SGF.emitStringToPointer(pointerExpr, stringValue, |
| pointerExpr->getType()); |
| } |
| } |
| llvm_unreachable("bad kind"); |
| } |
| |
| ManagedValue emitBindOptionals(SILGenFunction &SGF, ManagedValue optValue, |
| Expr *expr) { |
| expr = expr->getSemanticsProvidingExpr(); |
| auto bind = dyn_cast<BindOptionalExpr>(expr); |
| |
| // If we don't find a bind, the value isn't optional. |
| if (!bind) return optValue; |
| |
| // Recurse. |
| optValue = emitBindOptionals(SGF, optValue, bind->getSubExpr()); |
| |
| // Check whether the value is non-nil and if the value is not-nil, return |
| // the unwrapped value. |
| return SGF.emitBindOptional(bind, optValue, bind->getDepth()); |
| } |
| |
| std::pair<ManagedValue, ManagedValue> |
| finishOptionalEvaluation(SILGenFunction &SGF, OptionalEvaluationExpr *eval) { |
| SmallVector<ManagedValue, 2> results; |
| |
| SGF.emitOptionalEvaluation(eval, eval->getType(), results, SGFContext(), |
| [&](SmallVectorImpl<ManagedValue> &results, SGFContext C) { |
| // Recurse. |
| auto values = finishOriginalExpr(SGF, eval->getSubExpr()); |
| |
| // Our primary result is the value. |
| results.push_back(values.first); |
| |
| // Our secondary result is the owner, if we have one. |
| if (auto owner = values.second) results.push_back(owner); |
| }); |
| |
| assert(results.size() == 1 || results.size() == 2); |
| |
| ManagedValue value = results[0]; |
| |
| ManagedValue owner; |
| if (results.size() == 2) { |
| owner = results[1]; |
| |
| // Create a new value-dependence here if the primary result is |
| // trivial. |
| auto &valueTL = SGF.getTypeLowering(value.getType()); |
| if (valueTL.isTrivial()) { |
| SILValue dependentValue = |
| SGF.B.createMarkDependence(eval, value.forward(SGF), |
| owner.getValue()); |
| value = SGF.emitManagedRValueWithCleanup(dependentValue, valueTL); |
| } |
| } |
| |
| return {value, owner}; |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| /// Perform the formal-access phase of call argument emission by emitting |
| /// all of the delayed arguments. |
| static void emitDelayedArguments(SILGenFunction &SGF, |
| MutableArrayRef<DelayedArgument> delayedArgs, |
| MutableArrayRef<SmallVector<ManagedValue, 4>> args) { |
| assert(!delayedArgs.empty()); |
| |
| SmallVector<std::pair<SILValue, SILLocation>, 4> emittedInoutArgs; |
| auto delayedNext = delayedArgs.begin(); |
| |
| // The assumption we make is that 'args' and 'inoutArgs' were built |
| // up in parallel, with empty spots being dropped into 'args' |
| // wherever there's an inout argument to insert. |
| // |
| // Note that this also begins the formal accesses in evaluation order. |
| for (auto &siteArgs : args) { |
| for (ManagedValue &siteArg : siteArgs) { |
| if (siteArg) continue; |
| |
| assert(delayedNext != delayedArgs.end()); |
| auto &delayedArg = *delayedNext; |
| |
| // Emit the delayed argument and replace it in the arguments array. |
| auto value = delayedArg.emit(SGF); |
| siteArg = value; |
| |
| // Remember all the simple inouts we emitted so we can perform |
| // a basic inout-aliasing analysis. |
| // This should be completely obviated by static enforcement. |
| if (delayedArg.isSimpleInOut()) { |
| emittedInoutArgs.push_back({value.getValue(), |
| delayedArg.getInOutLocation()}); |
| } |
| |
| if (++delayedNext == delayedArgs.end()) |
| goto done; |
| } |
| } |
| |
| llvm_unreachable("ran out of null arguments before we ran out of inouts"); |
| |
| done: |
| |
| // Check to see if we have multiple inout arguments which obviously |
| // alias. Note that we could do this in a later SILDiagnostics pass |
| // as well: this would be stronger (more equivalences exposed) but |
| // would have worse source location information. |
| for (auto i = emittedInoutArgs.begin(), e = emittedInoutArgs.end(); |
| i != e; ++i) { |
| for (auto j = emittedInoutArgs.begin(); j != i; ++j) { |
| if (!RValue::areObviouslySameValue(i->first, j->first)) continue; |
| |
| SGF.SGM.diagnose(i->second, diag::inout_argument_alias) |
| .highlight(i->second.getSourceRange()); |
| SGF.SGM.diagnose(j->second, diag::previous_inout_alias) |
| .highlight(j->second.getSourceRange()); |
| } |
| } |
| } |
| |
| namespace { |
| |
| /// A destination for an argument other than just "onto to the end |
| /// of the arguments lists". |
| /// |
| /// This allows us to re-use the argument expression emitter for |
| /// some weird cases, like a shuffled tuple where some of the |
| /// arguments are going into a varargs array. |
| struct ArgSpecialDest { |
| VarargsInfo *SharedInfo; |
| unsigned Index; |
| CleanupHandle Cleanup; |
| |
| ArgSpecialDest() : SharedInfo(nullptr) {} |
| explicit ArgSpecialDest(VarargsInfo &info, unsigned index) |
| : SharedInfo(&info), Index(index) {} |
| |
| // Reference semantics: need to preserve the cleanup handle. |
| ArgSpecialDest(const ArgSpecialDest &) = delete; |
| ArgSpecialDest &operator=(const ArgSpecialDest &) = delete; |
| ArgSpecialDest(ArgSpecialDest &&other) |
| : SharedInfo(other.SharedInfo), Index(other.Index), |
| Cleanup(other.Cleanup) { |
| other.SharedInfo = nullptr; |
| } |
| ArgSpecialDest &operator=(ArgSpecialDest &&other) { |
| assert(!isValid() && "overwriting valid special destination!"); |
| SharedInfo = other.SharedInfo; |
| Index = other.Index; |
| Cleanup = other.Cleanup; |
| other.SharedInfo = nullptr; |
| return *this; |
| } |
| |
| ~ArgSpecialDest() { |
| assert(!isValid() && "failed to deactivate special dest"); |
| } |
| |
| /// Is this a valid special destination? |
| /// |
| /// Most of the time, most arguments don't have special |
| /// destinations, and making an array of Optional<Special special |
| /// destinations has t |
| bool isValid() const { return SharedInfo != nullptr; } |
| |
| /// Fill this special destination with a value. |
| void fill(SILGenFunction &SGF, ArgumentSource &&arg, |
| AbstractionPattern _unused_origType, |
| SILType loweredSubstParamType) { |
| assert(isValid() && "filling an invalid destination"); |
| |
| SILLocation loc = arg.getLocation(); |
| auto destAddr = SharedInfo->getBaseAddress(); |
| if (Index != 0) { |
| SILValue index = SGF.B.createIntegerLiteral(loc, |
| SILType::getBuiltinWordType(SGF.getASTContext()), Index); |
| destAddr = SGF.B.createIndexAddr(loc, destAddr, index); |
| } |
| |
| assert(destAddr->getType() == loweredSubstParamType.getAddressType()); |
| |
| auto &destTL = SharedInfo->getBaseTypeLowering(); |
| Cleanup = |
| SGF.enterDormantFormalAccessTemporaryCleanup(destAddr, loc, destTL); |
| |
| TemporaryInitialization init(destAddr, Cleanup); |
| std::move(arg).forwardInto(SGF, SharedInfo->getBaseAbstractionPattern(), |
| &init, destTL); |
| } |
| |
| /// Deactivate this special destination. Must always be called |
| /// before destruction. |
| void deactivate(SILGenFunction &SGF) { |
| assert(isValid() && "deactivating an invalid destination"); |
| if (Cleanup.isValid()) |
| SGF.Cleanups.forwardCleanup(Cleanup); |
| SharedInfo = nullptr; |
| } |
| }; |
| |
| /// A possibly-discontiguous slice of function parameters claimed by a |
| /// function application. |
| class ClaimedParamsRef { |
| public: |
| static constexpr const unsigned NoSkip = (unsigned)-1; |
| private: |
| ArrayRef<SILParameterInfo> Params; |
| |
| // The index of the param excluded from this range, if any, or ~0. |
| unsigned SkipParamIndex; |
| |
| friend struct ParamLowering; |
| explicit ClaimedParamsRef(ArrayRef<SILParameterInfo> params, |
| unsigned skip) |
| : Params(params), SkipParamIndex(skip) |
| { |
| // Eagerly chop a skipped parameter off either end. |
| if (SkipParamIndex == 0) { |
| Params = Params.slice(1); |
| SkipParamIndex = NoSkip; |
| } |
| assert(!hasSkip() || SkipParamIndex < Params.size()); |
| } |
| |
| bool hasSkip() const { |
| return SkipParamIndex != (unsigned)NoSkip; |
| } |
| public: |
| ClaimedParamsRef() : Params({}), SkipParamIndex(-1) {} |
| explicit ClaimedParamsRef(ArrayRef<SILParameterInfo> params) |
| : Params(params), SkipParamIndex(NoSkip) |
| {} |
| |
| struct iterator : public std::iterator<std::random_access_iterator_tag, |
| SILParameterInfo> |
| { |
| const SILParameterInfo *Base; |
| unsigned I, SkipParamIndex; |
| |
| iterator(const SILParameterInfo *Base, |
| unsigned I, unsigned SkipParamIndex) |
| : Base(Base), I(I), SkipParamIndex(SkipParamIndex) |
| {} |
| |
| iterator &operator++() { |
| ++I; |
| if (I == SkipParamIndex) |
| ++I; |
| return *this; |
| } |
| iterator operator++(int) { |
| iterator old(*this); |
| ++*this; |
| return old; |
| } |
| iterator &operator--() { |
| --I; |
| if (I == SkipParamIndex) |
| --I; |
| return *this; |
| } |
| iterator operator--(int) { |
| iterator old(*this); |
| --*this; |
| return old; |
| } |
| |
| const SILParameterInfo &operator*() const { |
| return Base[I]; |
| } |
| const SILParameterInfo *operator->() const { |
| return Base + I; |
| } |
| |
| bool operator==(iterator other) const { |
| return Base == other.Base && I == other.I |
| && SkipParamIndex == other.SkipParamIndex; |
| } |
| |
| bool operator!=(iterator other) const { |
| return !(*this == other); |
| } |
| |
| iterator operator+(std::ptrdiff_t distance) const { |
| if (distance > 0) |
| return goForward(distance); |
| if (distance < 0) |
| return goBackward(distance); |
| return *this; |
| } |
| iterator operator-(std::ptrdiff_t distance) const { |
| if (distance > 0) |
| return goBackward(distance); |
| if (distance < 0) |
| return goForward(distance); |
| return *this; |
| } |
| std::ptrdiff_t operator-(iterator other) const { |
| assert(Base == other.Base && SkipParamIndex == other.SkipParamIndex); |
| auto baseDistance = (std::ptrdiff_t)I - (std::ptrdiff_t)other.I; |
| if (std::min(I, other.I) < SkipParamIndex && |
| std::max(I, other.I) > SkipParamIndex) |
| return baseDistance - 1; |
| return baseDistance; |
| } |
| |
| iterator goBackward(unsigned distance) const { |
| auto result = *this; |
| if (I > SkipParamIndex && I <= SkipParamIndex + distance) |
| result.I -= (distance + 1); |
| result.I -= distance; |
| return result; |
| } |
| |
| iterator goForward(unsigned distance) const { |
| auto result = *this; |
| if (I < SkipParamIndex && I + distance >= SkipParamIndex) |
| result.I += distance + 1; |
| result.I += distance; |
| return result; |
| } |
| }; |
| |
| iterator begin() const { |
| return iterator{Params.data(), 0, SkipParamIndex}; |
| } |
| |
| iterator end() const { |
| return iterator{Params.data(), (unsigned)Params.size(), SkipParamIndex}; |
| } |
| |
| unsigned size() const { |
| return Params.size() - (hasSkip() ? 1 : 0); |
| } |
| |
| bool empty() const { return size() == 0; } |
| |
| SILParameterInfo front() const { return *begin(); } |
| |
| ClaimedParamsRef slice(unsigned start) const { |
| if (start >= SkipParamIndex) |
| return ClaimedParamsRef(Params.slice(start + 1), NoSkip); |
| return ClaimedParamsRef(Params.slice(start), |
| hasSkip() ? SkipParamIndex - start : NoSkip); |
| } |
| ClaimedParamsRef slice(unsigned start, unsigned count) const { |
| if (start >= SkipParamIndex) |
| return ClaimedParamsRef(Params.slice(start + 1, count), NoSkip); |
| unsigned newSkip = SkipParamIndex; |
| if (hasSkip()) |
| newSkip -= start; |
| |
| if (newSkip < count) |
| return ClaimedParamsRef(Params.slice(start, count+1), newSkip); |
| return ClaimedParamsRef(Params.slice(start, count), NoSkip); |
| } |
| }; |
| |
| using ArgSpecialDestArray = MutableArrayRef<ArgSpecialDest>; |
| |
| class TupleShuffleArgEmitter; |
| |
| class ArgEmitter { |
| // TODO: Refactor out the parts of ArgEmitter needed by TupleShuffleArgEmitter |
| // into its own "context struct". |
| friend class TupleShuffleArgEmitter; |
| |
| SILGenFunction &SGF; |
| SILFunctionTypeRepresentation Rep; |
| const Optional<ForeignErrorConvention> &ForeignError; |
| ImportAsMemberStatus ForeignSelf; |
| ClaimedParamsRef ParamInfos; |
| SmallVectorImpl<ManagedValue> &Args; |
| |
| /// Track any delayed arguments that are emitted. Each corresponds |
| /// in order to a "hole" (a null value) in Args. |
| SmallVectorImpl<DelayedArgument> &DelayedArguments; |
| |
| Optional<ArgSpecialDestArray> SpecialDests; |
| public: |
| ArgEmitter(SILGenFunction &SGF, SILFunctionTypeRepresentation Rep, |
| ClaimedParamsRef paramInfos, |
| SmallVectorImpl<ManagedValue> &args, |
| SmallVectorImpl<DelayedArgument> &delayedArgs, |
| const Optional<ForeignErrorConvention> &foreignError, |
| ImportAsMemberStatus foreignSelf, |
| Optional<ArgSpecialDestArray> specialDests = None) |
| : SGF(SGF), Rep(Rep), ForeignError(foreignError), |
| ForeignSelf(foreignSelf), |
| ParamInfos(paramInfos), |
| Args(args), DelayedArguments(delayedArgs), SpecialDests(specialDests) { |
| assert(!specialDests || specialDests->size() == paramInfos.size()); |
| } |
| |
| void emitTopLevel(ArgumentSource &&arg, AbstractionPattern origParamType) { |
| emit(std::move(arg), origParamType); |
| maybeEmitForeignErrorArgument(); |
| } |
| |
| private: |
| void emit(ArgumentSource &&arg, AbstractionPattern origParamType) { |
| // If it was a tuple in the original type, or the argument |
| // requires the callee to evaluate, the parameters will have |
| // been exploded. |
| if (origParamType.isTuple() || arg.requiresCalleeToEvaluate()) { |
| emitExpanded(std::move(arg), origParamType); |
| return; |
| } |
| |
| auto substArgType = arg.getSubstType(); |
| |
| // Otherwise, if the substituted type is a tuple, then we should |
| // emit the tuple in its most general form, because there's a |
| // substitution of an opaque archetype to a tuple or function |
| // type in play. The most general convention is generally to |
| // pass the entire tuple indirectly, but if it's not |
| // materializable, the convention is actually to break it up |
| // into materializable chunks. See the comment in SILType.cpp. |
| if (isUnmaterializableTupleType(substArgType)) { |
| assert(origParamType.isTypeParameter()); |
| emitExpanded(std::move(arg), origParamType); |
| return; |
| } |
| |
| // Okay, everything else will be passed as a single value, one |
| // way or another. |
| |
| // If this is a discarded foreign static 'self' parameter, force the |
| // argument and discard it. |
| if (ForeignSelf.isStatic()) { |
| std::move(arg).getAsRValue(SGF); |
| return; |
| } |
| |
| // Adjust for the foreign-error argument if necessary. |
| maybeEmitForeignErrorArgument(); |
| |
| // The substituted parameter type. Might be different from the |
| // substituted argument type by abstraction and/or bridging. |
| SILParameterInfo param = claimNextParameter(); |
| ArgSpecialDest *specialDest = claimNextSpecialDest(); |
| |
| // Make sure we use the same value category for these so that we |
| // can hereafter just use simple equality checks to test for |
| // abstraction. |
| SILType loweredSubstArgType = SGF.getLoweredType(substArgType); |
| SILType loweredSubstParamType = |
| SILType::getPrimitiveType(param.getType(), |
| loweredSubstArgType.getCategory()); |
| |
| // If the caller takes the argument indirectly, the argument has an |
| // inout type. |
| if (param.isIndirectInOut()) { |
| assert(!specialDest); |
| assert(isa<InOutType>(substArgType)); |
| emitInOut(std::move(arg), loweredSubstArgType, loweredSubstParamType, |
| origParamType, substArgType); |
| return; |
| } |
| |
| // If the original type is passed indirectly, copy to memory if |
| // it's not already there. (Note that this potentially includes |
| // conventions which pass indirectly without transferring |
| // ownership, like Itanium C++.) |
| if (specialDest) { |
| assert(param.isFormalIndirect() && |
| "SpecialDest should imply indirect parameter"); |
| // TODO: Change the way we initialize array storage in opaque mode |
| emitIndirectInto(std::move(arg), origParamType, loweredSubstParamType, |
| *specialDest); |
| Args.push_back(ManagedValue::forInContext()); |
| return; |
| } else if (SGF.silConv.isSILIndirect(param)) { |
| emitIndirect(std::move(arg), loweredSubstArgType, origParamType, param); |
| return; |
| } |
| |
| // Okay, if the original parameter is passed directly, then we |
| // just need to handle abstraction differences and bridging. |
| assert(!specialDest); |
| emitDirect(std::move(arg), loweredSubstArgType, origParamType, param); |
| } |
| |
| SILParameterInfo claimNextParameter() { |
| assert(!ParamInfos.empty()); |
| auto param = ParamInfos.front(); |
| ParamInfos = ParamInfos.slice(1); |
| return param; |
| } |
| |
| /// Claim the next destination, returning a null pointer if there |
| /// is no special destination. |
| ArgSpecialDest *claimNextSpecialDest() { |
| if (!SpecialDests) return nullptr; |
| assert(!SpecialDests->empty()); |
| auto dest = &SpecialDests->front(); |
| SpecialDests = SpecialDests->slice(1); |
| return (dest->isValid() ? dest : nullptr); |
| } |
| |
| bool isUnmaterializableTupleType(CanType type) { |
| if (auto tuple = dyn_cast<TupleType>(type)) |
| if (tuple->hasInOutElement()) |
| return true; |
| return false; |
| } |
| |
| /// Emit an argument as an expanded tuple. |
| void emitExpanded(ArgumentSource &&arg, AbstractionPattern origParamType) { |
| assert(!arg.isLValue() && "argument is l-value but parameter is tuple?"); |
| |
| // If we're working with an r-value, just expand it out and emit |
| // all the elements individually. |
| if (arg.isRValue()) { |
| if (CanTupleType substArgType = |
| dyn_cast<TupleType>(arg.getSubstType())) { |
| // The original type isn't necessarily a tuple. |
| assert(origParamType.matchesTuple(substArgType)); |
| |
| auto loc = arg.getKnownRValueLocation(); |
| SmallVector<RValue, 4> elts; |
| std::move(arg).asKnownRValue(SGF).extractElements(elts); |
| for (auto i : indices(substArgType.getElementTypes())) { |
| emit({ loc, std::move(elts[i]) }, |
| origParamType.getTupleElementType(i)); |
| } |
| return; |
| } |
| |
| auto loc = arg.getKnownRValueLocation(); |
| SmallVector<RValue, 1> elts; |
| std::move(arg).asKnownRValue(SGF).extractElements(elts); |
| emit({ loc, std::move(elts[0]) }, |
| origParamType.getTupleElementType(0)); |
| return; |
| } |
| |
| // If we're working with a tuple source, expand it. |
| if (arg.isTuple()) { |
| (void) std::move(arg).withKnownTupleElementSources<int>( |
| [&](SILLocation loc, CanTupleType type, |
| MutableArrayRef<ArgumentSource> elts) { |
| for (auto i : indices(elts)) { |
| emit(std::move(elts[i]), origParamType.getTupleElementType(i)); |
| } |
| return 0; // We need a fake return value because <void> won't compile. |
| }); |
| return; |
| } |
| |
| // Otherwise, we're working with an expression. |
| Expr *e = std::move(arg).asKnownExpr(); |
| e = e->getSemanticsProvidingExpr(); |
| |
| // If the source expression is a tuple literal, we can break it |
| // up directly. |
| if (auto tuple = dyn_cast<TupleExpr>(e)) { |
| for (auto i : indices(tuple->getElements())) { |
| emit(tuple->getElement(i), |
| origParamType.getTupleElementType(i)); |
| } |
| return; |
| } |
| |
| if (auto shuffle = dyn_cast<TupleShuffleExpr>(e)) { |
| emitShuffle(shuffle, origParamType); |
| return; |
| } |
| |
| // Fall back to the r-value case. |
| emitExpanded({ e, SGF.emitRValue(e) }, origParamType); |
| } |
| |
| void emitShuffle(TupleShuffleExpr *shuffle, AbstractionPattern origType); |
| |
| void emitIndirect(ArgumentSource &&arg, |
| SILType loweredSubstArgType, |
| AbstractionPattern origParamType, |
| SILParameterInfo param) { |
| auto contexts = getRValueEmissionContexts(loweredSubstArgType, param); |
| ManagedValue result; |
| |
| // If no abstraction is required, try to honor the emission contexts. |
| if (!contexts.RequiresReabstraction) { |
| auto loc = arg.getLocation(); |
| |
| // Peephole certain argument emissions. |
| if (arg.isExpr()) { |
| auto expr = std::move(arg).asKnownExpr(); |
| |
| // Try the peepholes. |
| if (maybeEmitDelayed(expr, OriginalArgument(expr, /*indirect*/ true))) |
| return; |
| |
| // Otherwise, just use the default logic. |
| result = SGF.emitRValueAsSingleValue(expr, contexts.FinalContext); |
| } else { |
| result = std::move(arg).getAsSingleValue(SGF, contexts.FinalContext); |
| } |
| |
| // If it's not already in memory, put it there. |
| if (!result.getType().isAddress()) { |
| result = result.materialize(SGF, loc); |
| } |
| |
| // Otherwise, simultaneously emit and reabstract. |
| } else { |
| result = std::move(arg).materialize(SGF, origParamType, |
| SGF.getSILType(param)); |
| } |
| |
| Args.push_back(result); |
| } |
| |
| void emitIndirectInto(ArgumentSource &&arg, |
| AbstractionPattern origType, |
| SILType loweredSubstParamType, |
| ArgSpecialDest &dest) { |
| dest.fill(SGF, std::move(arg), origType, loweredSubstParamType); |
| } |
| |
| void emitInOut(ArgumentSource &&arg, |
| SILType loweredSubstArgType, SILType loweredSubstParamType, |
| AbstractionPattern origType, CanType substType) { |
| SILLocation loc = arg.getLocation(); |
| |
| LValue lv = [&]{ |
| // If the argument is already lowered to an LValue, it must be the |
| // receiver of a self argument, which will be the first inout. |
| if (arg.isLValue()) { |
| return std::move(arg).asKnownLValue(); |
| |
| // This is logically wrong, but propagating l-values within |
| // RValues is hard to avoid in custom argument-emission code |
| // without making ArgumentSource capable of holding mixed |
| // RValue/LValue tuples. (materializeForSet has to do this, |
| // for one.) The onus is on the caller to ensure that formal |
| // access semantics are honored. |
| } else if (arg.isRValue()) { |
| auto address = std::move(arg).asKnownRValue(SGF).getAsSingleValue( |
| SGF, arg.getKnownRValueLocation()); |
| assert(address.isLValue()); |
| auto substObjectType = cast<InOutType>(substType).getObjectType(); |
| return LValue::forAddress(address, None, |
| AbstractionPattern(substObjectType), |
| substObjectType); |
| } else { |
| auto *e = cast<InOutExpr>(std::move(arg).asKnownExpr()-> |
| getSemanticsProvidingExpr()); |
| return SGF.emitLValue(e->getSubExpr(), AccessKind::ReadWrite); |
| } |
| }(); |
| |
| if (loweredSubstParamType.hasAbstractionDifference(Rep, |
| loweredSubstArgType)) { |
| AbstractionPattern origObjectType = origType.transformType( |
| [](CanType type)->CanType { |
| return CanType(type->getInOutObjectType()); |
| }); |
| lv.addSubstToOrigComponent(origObjectType, loweredSubstParamType); |
| } |
| |
| // Leave an empty space in the ManagedValue sequence and |
| // remember that we had an inout argument. |
| DelayedArguments.emplace_back(DelayedArgument::InOut, std::move(lv), loc); |
| Args.push_back(ManagedValue()); |
| return; |
| } |
| |
| void emitDirect(ArgumentSource &&arg, SILType loweredSubstArgType, |
| AbstractionPattern origParamType, |
| SILParameterInfo param) { |
| ManagedValue value; |
| auto loc = arg.getLocation(); |
| |
| auto convertOwnershipConvention = [&](ManagedValue value) { |
| return convertOwnershipConventionGivenParamInfo(SGF, param, value, loc); |
| }; |
| |
| auto contexts = getRValueEmissionContexts(loweredSubstArgType, param); |
| if (contexts.RequiresReabstraction) { |
| auto conversion = [&] { |
| switch (getSILFunctionLanguage(Rep)) { |
| case SILFunctionLanguage::Swift: |
| return Conversion::getSubstToOrig(origParamType, arg.getSubstType()); |
| case SILFunctionLanguage::C: |
| return Conversion::getBridging(Conversion::BridgeToObjC, |
| arg.getSubstType(), |
| origParamType.getType(), |
| param.getSILStorageType()); |
| } |
| llvm_unreachable("bad language"); |
| }(); |
| value = emitConvertedArgument(std::move(arg), conversion, |
| contexts.FinalContext); |
| Args.push_back(convertOwnershipConvention(value)); |
| return; |
| } |
| |
| // Peephole certain argument emissions. |
| if (arg.isExpr()) { |
| auto expr = std::move(arg).asKnownExpr(); |
| |
| // Try the peepholes. |
| if (maybeEmitDelayed(expr, OriginalArgument(expr, /*indirect*/ false))) |
| return; |
| |
| // Any borrows from any rvalue accesses, we want to be cleaned up at this |
| // point. |
| FormalEvaluationScope S(SGF); |
| |
| // Otherwise, just use the default logic. |
| value = SGF.emitRValueAsSingleValue(expr, contexts.FinalContext); |
| Args.push_back(convertOwnershipConvention(value)); |
| return; |
| } |
| |
| value = std::move(arg).getAsSingleValue(SGF, contexts.FinalContext); |
| Args.push_back(convertOwnershipConvention(value)); |
| } |
| |
| bool maybeEmitDelayed(Expr *expr, OriginalArgument original) { |
| expr = expr->getSemanticsProvidingExpr(); |
| |
| // Delay accessing inout-to-pointer arguments until the call. |
| if (auto inoutToPointer = dyn_cast<InOutToPointerExpr>(expr)) { |
| return emitDelayedConversion(inoutToPointer, original); |
| } |
| |
| // Delay accessing array-to-pointer arguments until the call. |
| if (auto arrayToPointer = dyn_cast<ArrayToPointerExpr>(expr)) { |
| return emitDelayedConversion(arrayToPointer, original); |
| } |
| |
| // Delay accessing string-to-pointer arguments until the call. |
| if (auto stringToPointer = dyn_cast<StringToPointerExpr>(expr)) { |
| return emitDelayedConversion(stringToPointer, original); |
| } |
| |
| // Any recursive cases we handle here need to be handled in |
| // DelayedArgument::finishOriginalExpr. |
| |
| // Handle optional evaluations. |
| if (auto optional = dyn_cast<OptionalEvaluationExpr>(expr)) { |
| // The validity of just recursing here depends on the fact |
| // that we only return true for the specific conversions above, |
| // which are constrained by the ASTVerifier to only appear in |
| // specific forms. |
| return maybeEmitDelayed(optional->getSubExpr(), original); |
| } |
| |
| // Handle injections into optionals. |
| if (auto inject = dyn_cast<InjectIntoOptionalExpr>(expr)) { |
| return maybeEmitDelayed(inject->getSubExpr(), original); |
| } |
| |
| // Handle try! expressions. |
| if (auto forceTry = dyn_cast<ForceTryExpr>(expr)) { |
| // Any expressions in the l-value must be routed appropriately. |
| SILGenFunction::ForceTryEmission emission(SGF, forceTry); |
| |
| return maybeEmitDelayed(forceTry->getSubExpr(), original); |
| } |
| |
| return false; |
| } |
| |
| bool emitDelayedConversion(InOutToPointerExpr *pointerExpr, |
| OriginalArgument original) { |
| auto info = SGF.getPointerAccessInfo(pointerExpr->getType()); |
| LValueOptions options; |
| options.IsNonAccessing = pointerExpr->isNonAccessing(); |
| LValue lv = SGF.emitLValue(pointerExpr->getSubExpr(), info.AccessKind, |
| options); |
| DelayedArguments.emplace_back(info, std::move(lv), pointerExpr, original); |
| Args.push_back(ManagedValue()); |
| return true; |
| } |
| |
| bool emitDelayedConversion(ArrayToPointerExpr *pointerExpr, |
| OriginalArgument original) { |
| auto arrayExpr = pointerExpr->getSubExpr(); |
| |
| // If the source of the conversion is an inout, emit the l-value |
| // but delay the formal access. |
| if (arrayExpr->isSemanticallyInOutExpr()) { |
| auto info = SGF.getArrayAccessInfo(pointerExpr->getType(), |
| arrayExpr->getType()->getInOutObjectType()); |
| LValueOptions options; |
| options.IsNonAccessing = pointerExpr->isNonAccessing(); |
| LValue lv = SGF.emitLValue(arrayExpr, info.AccessKind, options); |
| DelayedArguments.emplace_back(info, std::move(lv), pointerExpr, |
| original); |
| Args.push_back(ManagedValue()); |
| return true; |
| } |
| |
| // Otherwise, it's an r-value conversion. |
| auto info = SGF.getArrayAccessInfo(pointerExpr->getType(), |
| arrayExpr->getType()); |
| |
| auto rvalueExpr = lookThroughBindOptionals(arrayExpr); |
| ManagedValue value = SGF.emitRValueAsSingleValue(rvalueExpr); |
| DelayedArguments.emplace_back(DelayedArgument::RValueArrayToPointer, |
| info, value, original); |
| Args.push_back(ManagedValue()); |
| return true; |
| } |
| |
| /// Emit an rvalue-array-to-pointer conversion as a delayed argument. |
| bool emitDelayedConversion(StringToPointerExpr *pointerExpr, |
| OriginalArgument original) { |
| auto rvalueExpr = lookThroughBindOptionals(pointerExpr->getSubExpr()); |
| ManagedValue value = SGF.emitRValueAsSingleValue(rvalueExpr); |
| DelayedArguments.emplace_back(DelayedArgument::RValueStringToPointer, |
| value, original); |
| Args.push_back(ManagedValue()); |
| return true; |
| } |
| |
| static Expr *lookThroughBindOptionals(Expr *expr) { |
| while (true) { |
| expr = expr->getSemanticsProvidingExpr(); |
| if (auto bind = dyn_cast<BindOptionalExpr>(expr)) { |
| expr = bind->getSubExpr(); |
| } else { |
| return expr; |
| } |
| } |
| } |
| |
| ManagedValue emitConvertedArgument(ArgumentSource &&arg, |
| Conversion conversion, |
| SGFContext C) { |
| auto loc = arg.getLocation(); |
| Scope scope(SGF, loc); |
| |
| // TODO: honor C here. |
| auto result = std::move(arg).getConverted(SGF, conversion); |
| |
| return scope.popPreservingValue(result); |
| } |
| |
| void maybeEmitForeignErrorArgument() { |
| if (!ForeignError || |
| ForeignError->getErrorParameterIndex() != Args.size()) |
| return; |
| |
| SILParameterInfo param = claimNextParameter(); |
| ArgSpecialDest *specialDest = claimNextSpecialDest(); |
| |
| assert(param.getConvention() == ParameterConvention::Direct_Unowned); |
| assert(!specialDest && "special dest for error argument?"); |
| (void) param; (void) specialDest; |
| |
| // Leave a placeholder in the position. |
| Args.push_back(ManagedValue::forInContext()); |
| } |
| |
| struct EmissionContexts { |
| /// The context for emitting the r-value. |
| SGFContext FinalContext; |
| /// If the context requires reabstraction |
| bool RequiresReabstraction; |
| }; |
| static EmissionContexts getRValueEmissionContexts(SILType loweredArgType, |
| SILParameterInfo param) { |
| bool requiresReabstraction = |
| loweredArgType.getSwiftRValueType() != param.getType(); |
| // If the parameter is consumed, we have to emit at +1. |
| if (param.isConsumed()) { |
| return {SGFContext(), requiresReabstraction}; |
| } |
| |
| // Otherwise, we can emit the final value at +0 (but only with a |
| // guarantee that the value will survive). |
| // |
| // TODO: we can pass at +0 (immediate) to an unowned parameter |
| // if we know that there will be no arbitrary side-effects |
| // between now and the call. |
| return {SGFContext::AllowGuaranteedPlusZero, requiresReabstraction}; |
| } |
| }; |
| |
| struct ElementExtent { |
| /// The parameters which go into this tuple element. |
| /// This is set in the first pass. |
| ClaimedParamsRef Params; |
| /// The destination index, if any. |
| /// This is set in the first pass. |
| unsigned DestIndex : 30; |
| unsigned HasDestIndex : 1; |
| #ifndef NDEBUG |
| unsigned Used : 1; |
| #endif |
| /// The arguments which feed this tuple element. |
| /// This is set in the second pass. |
| ArrayRef<ManagedValue> Args; |
| /// The inout arguments which feed this tuple element. |
| /// This is set in the second pass. |
| MutableArrayRef<DelayedArgument> DelayedArgs; |
| |
| ElementExtent() |
| : HasDestIndex(false) |
| #ifndef NDEBUG |
| , |
| Used(false) |
| #endif |
| { |
| } |
| }; |
| |
| class TupleShuffleArgEmitter { |
| Expr *inner; |
| Expr *outer; |
| ArrayRef<TupleTypeElt> innerElts; |
| ConcreteDeclRef defaultArgsOwner; |
| ArrayRef<Expr *> callerDefaultArgs; |
| ArrayRef<int> elementMapping; |
| ArrayRef<unsigned> variadicArgs; |
| Type varargsArrayType; |
| AbstractionPattern origParamType; |
| bool isResultScalar; |
| |
| TupleTypeElt singleOuterElement; |
| ArrayRef<TupleTypeElt> outerElements; |
| CanType canVarargsArrayType; |
| |
| /// The original parameter type. |
| SmallVector<AbstractionPattern, 8> origInnerElts; |
| AbstractionPattern innerOrigParamType; |
| /// Flattened inner parameter sequence. |
| SmallVector<SILParameterInfo, 8> innerParams; |
| /// Extents of the inner elements. |
| SmallVector<ElementExtent, 8> innerExtents; |
| Optional<VarargsInfo> varargsInfo; |
| SILParameterInfo variadicParamInfo; // innerExtents will point at this |
| Optional<SmallVector<ArgSpecialDest, 8>> innerSpecialDests; |
| |
| // Used by flattenPatternFromInnerExtendIntoInnerParams and |
| // splitInnerArgumentsCorrectly. |
| SmallVector<ManagedValue, 8> innerArgs; |
| SmallVector<DelayedArgument, 2> innerDelayedArgs; |
| |
| public: |
| TupleShuffleArgEmitter(TupleShuffleExpr *e, ArrayRef<TupleTypeElt> innerElts, |
| AbstractionPattern origParamType) |
| : inner(e->getSubExpr()), outer(e), innerElts(innerElts), |
| defaultArgsOwner(e->getDefaultArgsOwner()), |
| callerDefaultArgs(e->getCallerDefaultArgs()), |
| elementMapping(e->getElementMapping()), |
| variadicArgs(e->getVariadicArgs()), |
| varargsArrayType(e->getVarargsArrayTypeOrNull()), |
| origParamType(origParamType), isResultScalar(e->isResultScalar()), |
| canVarargsArrayType(), |
| origInnerElts(innerElts.size(), AbstractionPattern::getInvalid()), |
| innerOrigParamType(AbstractionPattern::getInvalid()), innerParams(), |
| innerExtents(innerElts.size()), varargsInfo(), variadicParamInfo(), |
| innerSpecialDests() { |
| |
| // Decompose the shuffle result. |
| CanType resultType = e->getType()->getCanonicalType(); |
| if (isResultScalar) { |
| singleOuterElement = TupleTypeElt(resultType); |
| outerElements = singleOuterElement; |
| } else { |
| outerElements = cast<TupleType>(resultType)->getElements(); |
| } |
| |
| if (varargsArrayType) |
| canVarargsArrayType = varargsArrayType->getCanonicalType(); |
| } |
| |
| TupleShuffleArgEmitter(const TupleShuffleArgEmitter &) = delete; |
| TupleShuffleArgEmitter &operator=(const TupleShuffleArgEmitter &) = delete; |
| TupleShuffleArgEmitter(TupleShuffleArgEmitter &&) = delete; |
| TupleShuffleArgEmitter &operator=(TupleShuffleArgEmitter &&) = delete; |
| |
| void emit(ArgEmitter &parent); |
| |
| private: |
| void constructInnerTupleTypeInfo(ArgEmitter &parent); |
| void flattenPatternFromInnerExtendIntoInnerParams(ArgEmitter &parent); |
| void splitInnerArgumentsCorrectly(ArgEmitter &parent); |
| void emitDefaultArgsAndFinalize(ArgEmitter &parent); |
| |
| AbstractionPattern getOutputOrigElementType(unsigned index) { |
| if (isResultScalar) { |
| assert(index == 0); |
| return origParamType; |
| } else { |
| return origParamType.getTupleElementType(index); |
| } |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| void TupleShuffleArgEmitter::constructInnerTupleTypeInfo(ArgEmitter &parent) { |
| unsigned nextParamIndex = 0; |
| for (unsigned outerIndex : indices(outerElements)) { |
| CanType substEltType = |
| outerElements[outerIndex].getType()->getCanonicalType(); |
| AbstractionPattern origEltType = |
| getOutputOrigElementType(outerIndex); |
| unsigned numParams = |
| getFlattenedValueCount(origEltType, substEltType, parent.ForeignSelf); |
| |
| // Skip the foreign-error parameter. |
| assert((!parent.ForeignError || |
| parent.ForeignError->getErrorParameterIndex() <= nextParamIndex || |
| parent.ForeignError->getErrorParameterIndex() >= |
| nextParamIndex + numParams) && |
| "error parameter falls within shuffled range?"); |
| if (numParams && // Don't skip it twice if there's an empty tuple. |
| parent.ForeignError && |
| parent.ForeignError->getErrorParameterIndex() == nextParamIndex) { |
| nextParamIndex++; |
| } |
| |
| // Grab the parameter infos corresponding to this tuple element |
| // (but don't drop them from ParamInfos yet). |
| auto eltParams = parent.ParamInfos.slice(nextParamIndex, numParams); |
| nextParamIndex += numParams; |
| |
| int innerIndex = elementMapping[outerIndex]; |
| if (innerIndex >= 0) { |
| #ifndef NDEBUG |
| assert(!innerExtents[innerIndex].Used && "using element twice"); |
| innerExtents[innerIndex].Used = true; |
| #endif |
| innerExtents[innerIndex].Params = eltParams; |
| origInnerElts[innerIndex] = origEltType; |
| } else if (innerIndex == TupleShuffleExpr::Variadic) { |
| auto &varargsField = outerElements[outerIndex]; |
| assert(varargsField.isVararg()); |
| assert(!varargsInfo.hasValue() && "already had varargs entry?"); |
| |
| CanType varargsEltType = CanType(varargsField.getVarargBaseTy()); |
| unsigned numVarargs = variadicArgs.size(); |
| assert(canVarargsArrayType == substEltType); |
| |
| // Create the array value. |
| varargsInfo.emplace(emitBeginVarargs(parent.SGF, outer, varargsEltType, |
| canVarargsArrayType, numVarargs)); |
| |
| // If we have any varargs, we'll need to actually initialize |
| // the array buffer. |
| if (numVarargs) { |
| // For this, we'll need special destinations. |
| assert(!innerSpecialDests); |
| innerSpecialDests.emplace(); |
| |
| // Prepare the variadic "arguments" as single +1 indirect parameters |
| // with the array's desired abstraction pattern. The vararg element |
| // type should be materializable, and the abstraction pattern should be |
| // opaque, so ArgEmitter's lowering should always generate exactly one |
| // "argument" per element even if the substituted element type is a |
| // tuple. |
| variadicParamInfo = |
| SILParameterInfo(varargsInfo->getBaseTypeLowering() |
| .getLoweredType().getSwiftRValueType(), |
| ParameterConvention::Indirect_In); |
| |
| unsigned i = 0; |
| for (unsigned innerIndex : variadicArgs) { |
| // Find out where the next varargs element is coming from. |
| assert(innerIndex >= 0 && "special source for varargs element??"); |
| #ifndef NDEBUG |
| assert(!innerExtents[innerIndex].Used && "using element twice"); |
| innerExtents[innerIndex].Used = true; |
| #endif |
| |
| // Set the destination index. |
| innerExtents[innerIndex].HasDestIndex = true; |
| innerExtents[innerIndex].DestIndex = i++; |
| |
| // Use the singleton param info we prepared before. |
| innerExtents[innerIndex].Params = |
| ClaimedParamsRef(variadicParamInfo); |
| |
| // Propagate the element abstraction pattern. |
| origInnerElts[innerIndex] = |
| varargsInfo->getBaseAbstractionPattern(); |
| } |
| } |
| } |
| } |
| } |
| |
| void TupleShuffleArgEmitter::flattenPatternFromInnerExtendIntoInnerParams( |
| ArgEmitter &parent) { |
| for (auto &extent : innerExtents) { |
| assert(extent.Used && "didn't use all the inner tuple elements!"); |
| |
| for (auto param : extent.Params) { |
| innerParams.push_back(param); |
| } |
| |
| // Fill in the special destinations array. |
| if (innerSpecialDests) { |
| // Use the saved index if applicable. |
| if (extent.HasDestIndex) { |
| assert(extent.Params.size() == 1); |
| innerSpecialDests->push_back( |
| ArgSpecialDest(*varargsInfo, extent.DestIndex)); |
| |
| // Otherwise, fill in with the appropriate number of invalid |
| // special dests. |
| } else { |
| // ArgSpecialDest isn't copyable, so we can't just use append. |
| for (auto &p : extent.Params) { |
| (void)p; |
| innerSpecialDests->push_back(ArgSpecialDest()); |
| } |
| } |
| } |
| } |
| } |
| |
| void TupleShuffleArgEmitter::splitInnerArgumentsCorrectly(ArgEmitter &parent) { |
| ArrayRef<ManagedValue> nextArgs = innerArgs; |
| MutableArrayRef<DelayedArgument> nextDelayedArgs = innerDelayedArgs; |
| for (auto &extent : innerExtents) { |
| auto length = extent.Params.size(); |
| |
| // Claim the next N inner args for this inner argument. |
| extent.Args = nextArgs.slice(0, length); |
| nextArgs = nextArgs.slice(length); |
| |
| // Claim the correct number of inout arguments as well. |
| size_t numDelayed = 0; |
| for (auto arg : extent.Args) { |
| assert(!arg.isInContext() || extent.HasDestIndex); |
| if (!arg) |
| numDelayed++; |
| } |
| extent.DelayedArgs = nextDelayedArgs.slice(0, numDelayed); |
| nextDelayedArgs = nextDelayedArgs.slice(numDelayed); |
| } |
| |
| assert(nextArgs.empty() && "didn't claim all args"); |
| assert(nextDelayedArgs.empty() && "didn't claim all inout args"); |
| } |
| |
| void TupleShuffleArgEmitter::emitDefaultArgsAndFinalize(ArgEmitter &parent) { |
| unsigned nextCallerDefaultArg = 0; |
| for (unsigned outerIndex = 0, e = outerElements.size(); |
| outerIndex != e; ++outerIndex) { |
| // If this comes from an inner element, move the appropriate |
| // inner element values over. |
| int innerIndex = elementMapping[outerIndex]; |
| if (innerIndex >= 0) { |
| auto &extent = innerExtents[innerIndex]; |
| auto numArgs = extent.Args.size(); |
| |
| parent.maybeEmitForeignErrorArgument(); |
| |
| // Drop N parameters off of ParamInfos. |
| parent.ParamInfos = parent.ParamInfos.slice(numArgs); |
| |
| // Move the appropriate inner arguments over as outer arguments. |
| parent.Args.append(extent.Args.begin(), extent.Args.end()); |
| for (auto &delayedArg : extent.DelayedArgs) |
| parent.DelayedArguments.push_back(std::move(delayedArg)); |
| continue; |
| } |
| |
| // If this is default initialization, call the default argument |
| // generator. |
| if (innerIndex == TupleShuffleExpr::DefaultInitialize) { |
| // Otherwise, emit the default initializer, then map that as a |
| // default argument. |
| CanType eltType = outerElements[outerIndex].getType()->getCanonicalType(); |
| auto origType = getOutputOrigElementType(outerIndex); |
| RValue value = parent.SGF.emitApplyOfDefaultArgGenerator( |
| outer, defaultArgsOwner, outerIndex, eltType, origType); |
| parent.emit(ArgumentSource(outer, std::move(value)), origType); |
| continue; |
| } |
| |
| // If this is caller default initialization, generate the |
| // appropriate value. |
| if (innerIndex == TupleShuffleExpr::CallerDefaultInitialize) { |
| auto arg = callerDefaultArgs[nextCallerDefaultArg++]; |
| parent.emit(ArgumentSource(arg), |
| getOutputOrigElementType(outerIndex)); |
| continue; |
| } |
| |
| // If we're supposed to create a varargs array with the rest, do so. |
| if (innerIndex == TupleShuffleExpr::Variadic) { |
| auto &varargsField = outerElements[outerIndex]; |
| assert(varargsField.isVararg() && |
| "Cannot initialize nonvariadic element"); |
| assert(varargsInfo.hasValue()); |
| (void) varargsField; |
| |
| // We've successfully built the varargs array; deactivate all |
| // the special destinations. |
| if (innerSpecialDests) { |
| for (auto &dest : *innerSpecialDests) { |
| if (dest.isValid()) |
| dest.deactivate(parent.SGF); |
| } |
| } |
| |
| CanType eltType = outerElements[outerIndex].getType()->getCanonicalType(); |
| ManagedValue varargs = |
| emitEndVarargs(parent.SGF, outer, std::move(*varargsInfo)); |
| parent.emit( |
| ArgumentSource(outer, RValue(parent.SGF, outer, eltType, varargs)), |
| getOutputOrigElementType(outerIndex)); |
| continue; |
| } |
| |
| // That's the last special case defined so far. |
| llvm_unreachable("unexpected special case in tuple shuffle!"); |
| } |
| } |
| |
| void TupleShuffleArgEmitter::emit(ArgEmitter &parent) { |
| // We could support dest addrs here, but it can't actually happen |
| // with the current limitations on default arguments in tuples. |
| assert(!parent.SpecialDests && "shuffle nested within varargs expansion?"); |
| |
| // First, construct an abstraction pattern and parameter sequence |
| // which we can use to emit the inner tuple. |
| constructInnerTupleTypeInfo(parent); |
| |
| // The inner abstraction pattern is opaque if we started with an |
| // opaque pattern; otherwise, it's a tuple of the de-shuffled |
| // tuple elements. |
| innerOrigParamType = origParamType; |
| if (!origParamType.isTypeParameter()) { |
| // That "tuple" might not actually be a tuple. |
| if (innerElts.size() == 1 && !innerElts[0].hasName()) { |
| innerOrigParamType = origInnerElts[0]; |
| } else { |
| innerOrigParamType = AbstractionPattern::getTuple(origInnerElts); |
| } |
| } |
| |
| flattenPatternFromInnerExtendIntoInnerParams(parent); |
| |
| // Emit the inner expression. |
| if (!innerParams.empty()) { |
| ArgEmitter(parent.SGF, parent.Rep, ClaimedParamsRef(innerParams), innerArgs, |
| innerDelayedArgs, |
| /*foreign error*/ None, /*foreign self*/ ImportAsMemberStatus(), |
| (innerSpecialDests ? ArgSpecialDestArray(*innerSpecialDests) |
| : Optional<ArgSpecialDestArray>())) |
| .emitTopLevel(ArgumentSource(inner), innerOrigParamType); |
| } |
| |
| // Make a second pass to split the inner arguments correctly. |
| splitInnerArgumentsCorrectly(parent); |
| |
| // Make a final pass to emit default arguments and move things into |
| // the outer arguments lists. |
| emitDefaultArgsAndFinalize(parent); |
| } |
| |
| void ArgEmitter::emitShuffle(TupleShuffleExpr *E, |
| AbstractionPattern origParamType) { |
| ArrayRef<TupleTypeElt> srcElts; |
| TupleTypeElt singletonSrcElt; |
| auto srcEltTy = E->getSubExpr()->getType()->getCanonicalType(); |
| if (E->isSourceScalar()) { |
| ParameterTypeFlags flags; |
| if (E->getSubExpr()->isSemanticallyInOutExpr()) { |
| flags = flags.withInOut(true); |
| } |
| singletonSrcElt = {srcEltTy->getInOutObjectType(), Identifier(), flags}; |
| srcElts = singletonSrcElt; |
| } else { |
| srcElts = cast<TupleType>(srcEltTy)->getElements(); |
| } |
| |
| TupleShuffleArgEmitter(E, srcElts, origParamType).emit(*this); |
| } |
| |
| namespace { |
| /// Cleanup to destroy an uninitialized box. |
| class DeallocateUninitializedBox : public Cleanup { |
| SILValue box; |
| public: |
| DeallocateUninitializedBox(SILValue box) : box(box) {} |
| |
| void emit(SILGenFunction &SGF, CleanupLocation l) override { |
| SGF.B.createDeallocBox(l, box); |
| } |
| |
| void dump(SILGenFunction &SGF) const override { |
| #ifndef NDEBUG |
| llvm::errs() << "DeallocateUninitializedBox " |
| << "State:" << getState() << " " |
| << "Box: " << box << "\n"; |
| #endif |
| } |
| }; |
| } // end anonymous namespace |
| |
| CleanupHandle SILGenFunction::enterDeallocBoxCleanup(SILValue box) { |
| Cleanups.pushCleanup<DeallocateUninitializedBox>(box); |
| return Cleanups.getTopCleanup(); |
| } |
| |
| /// This is an initialization for a box. |
| class BoxInitialization : public SingleBufferInitialization { |
| SILValue box; |
| SILValue addr; |
| CleanupHandle uninitCleanup; |
| CleanupHandle initCleanup; |
| |
| public: |
| BoxInitialization(SILValue box, SILValue addr, |
| CleanupHandle uninitCleanup, |
| CleanupHandle initCleanup) |
| : box(box), addr(addr), |
| uninitCleanup(uninitCleanup), |
| initCleanup(initCleanup) {} |
| |
| void finishInitialization(SILGenFunction &SGF) override { |
| SingleBufferInitialization::finishInitialization(SGF); |
| SGF.Cleanups.setCleanupState(uninitCleanup, CleanupState::Dead); |
| if (initCleanup.isValid()) |
| SGF.Cleanups.setCleanupState(initCleanup, CleanupState::Active); |
| } |
| |
| SILValue getAddressForInPlaceInitialization(SILGenFunction &SGF, |
| SILLocation loc) override { |
| return addr; |
| } |
| |
| bool isInPlaceInitializationOfGlobal() const override { |
| return false; |
| } |
| |
| ManagedValue getManagedBox() const { |
| return ManagedValue(box, initCleanup); |
| } |
| }; |
| |
| namespace { |
| |
| /// A structure for conveniently claiming sets of uncurried parameters. |
| struct ParamLowering { |
| ArrayRef<SILParameterInfo> Params; |
| unsigned ClaimedForeignSelf = -1; |
| SILFunctionTypeRepresentation Rep; |
| SILFunctionConventions fnConv; |
| |
| ParamLowering(CanSILFunctionType fnType, SILGenFunction &SGF) |
| : Params(fnType->getParameters()), Rep(fnType->getRepresentation()), |
| fnConv(fnType, SGF.SGM.M) {} |
| |
| ClaimedParamsRef |
| claimParams(AbstractionPattern origParamType, CanType substParamType, |
| const Optional<ForeignErrorConvention> &foreignError, |
| ImportAsMemberStatus foreignSelf) { |
| unsigned count = |
| getFlattenedValueCount(origParamType, substParamType, foreignSelf); |
| if (foreignError) |
| count++; |
| |
| if (foreignSelf.isImportAsMember()) { |
| // Claim only the self parameter. |
| assert(ClaimedForeignSelf == (unsigned)-1 && |
| "already claimed foreign self?!"); |
| if (foreignSelf.isStatic()) { |
| // Imported as a static method, no real self param to claim. |
| return {}; |
| } |
| ClaimedForeignSelf = foreignSelf.getSelfIndex(); |
| return ClaimedParamsRef(Params[ClaimedForeignSelf], |
| ClaimedParamsRef::NoSkip); |
| } |
| |
| if (ClaimedForeignSelf != (unsigned)-1) { |
| assert(count + 1 == Params.size() && |
| "not claiming all params after foreign self?!"); |
| auto result = Params; |
| Params = {}; |
| return ClaimedParamsRef(result, ClaimedForeignSelf); |
| } |
| |
| assert(count <= Params.size()); |
| auto result = Params.slice(Params.size() - count, count); |
| Params = Params.slice(0, Params.size() - count); |
| return ClaimedParamsRef(result, (unsigned)-1); |
| } |
| |
| ArrayRef<SILParameterInfo> |
| claimCaptureParams(ArrayRef<ManagedValue> captures) { |
| auto firstCapture = Params.size() - captures.size(); |
| #ifndef NDEBUG |
| assert(Params.size() >= captures.size() && "more captures than params?!"); |
| for (unsigned i = 0; i < captures.size(); ++i) { |
| assert(fnConv.getSILType(Params[i + firstCapture]) == |
| captures[i].getType() && |
| "capture doesn't match param type"); |
| } |
| #endif |
| |
| auto result = Params.slice(firstCapture, captures.size()); |
| Params = Params.slice(0, firstCapture); |
| return result; |
| } |
| |
| ~ParamLowering() { |
| assert(Params.empty() && "didn't consume all the parameters"); |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| //===----------------------------------------------------------------------===// |
| // CallSite |
| //===----------------------------------------------------------------------===// |
| |
| namespace { |
| |
| /// An application of possibly unevaluated arguments in the form of an |
| /// ArgumentSource to a Callee. |
| class CallSite { |
| public: |
| SILLocation Loc; |
| CanType SubstResultType; |
| |
| private: |
| ArgumentSource ArgValue; |
| bool Throws; |
| |
| public: |
| CallSite(ApplyExpr *apply) |
| : Loc(apply), SubstResultType(apply->getType()->getCanonicalType()), |
| ArgValue(apply->getArg()), Throws(apply->throws()) {} |
| |
| CallSite(SILLocation loc, ArgumentSource &&value, CanType resultType, |
| bool throws) |
| : Loc(loc), SubstResultType(resultType), ArgValue(std::move(value)), |
| Throws(throws) {} |
| |
| CallSite(SILLocation loc, ArgumentSource &&value, CanAnyFunctionType fnType) |
| : CallSite(loc, std::move(value), fnType.getResult(), fnType->throws()) {} |
| |
| /// Return the substituted, unlowered AST type of the argument. |
| CanType getSubstArgType() const { return ArgValue.getSubstType(); } |
| |
| /// Return the substituted, unlowered AST type of the result of |
| /// this application. |
| CanType getSubstResultType() const { return SubstResultType; } |
| |
| bool throws() const { return Throws; } |
| |
| /// Evaluate arguments and begin any inout formal accesses. |
| void emit(SILGenFunction &SGF, AbstractionPattern origParamType, |
| ParamLowering &lowering, SmallVectorImpl<ManagedValue> &args, |
| SmallVectorImpl<DelayedArgument> &delayedArgs, |
| const Optional<ForeignErrorConvention> &foreignError, |
| ImportAsMemberStatus foreignSelf) && { |
| auto params = lowering.claimParams(origParamType, getSubstArgType(), |
| foreignError, foreignSelf); |
| |
| ArgEmitter emitter(SGF, lowering.Rep, params, args, delayedArgs, |
| foreignError, foreignSelf); |
| emitter.emitTopLevel(std::move(ArgValue), origParamType); |
| } |
| |
| /// Take the arguments for special processing, in place of the above. |
| ArgumentSource &&forward() && { return std::move(ArgValue); } |
| }; |
| |
| } // end anonymous namespace |
| |
| //===----------------------------------------------------------------------===// |
| // CallEmission |
| //===----------------------------------------------------------------------===// |
| |
| namespace { |
| |
| /// Once the Callee and CallSites have been prepared by SILGenApply, |
| /// generate SIL for a fully-formed call. |
| /// |
| /// The lowered function type of the callee defines an abstraction pattern |
| /// for evaluating argument values of tuple type directly into explosions of |
| /// scalars where possible. |
| /// |
| /// If there are more call sites than the natural uncurry level, they are |
| /// have to be applied recursively to each intermediate callee. |
| /// |
| /// Also inout formal access and parameter and result conventions are |
| /// handled here, with some special logic required for calls with +0 self. |
| class CallEmission { |
| SILGenFunction &SGF; |
| |
| std::vector<CallSite> uncurriedSites; |
| std::vector<CallSite> extraSites; |
| Callee callee; |
| FormalEvaluationScope initialWritebackScope; |
| unsigned expectedSiteCount; |
| |
| public: |
| /// Create an emission for a call of the given callee. |
| CallEmission(SILGenFunction &SGF, Callee &&callee, |
| FormalEvaluationScope &&writebackScope) |
| : SGF(SGF), callee(std::move(callee)), |
| initialWritebackScope(std::move(writebackScope)), |
| expectedSiteCount(callee.getParameterListCount()) {} |
| |
| /// A factory method for decomposing the apply expr \p e into a call |
| /// emission. |
| static CallEmission forApplyExpr(SILGenFunction &SGF, Expr *e); |
| |
| /// Add a level of function application by passing in its possibly |
| /// unevaluated arguments and their formal type. |
| void addCallSite(CallSite &&site) { |
| // Append to the main argument list if we have uncurry levels remaining. |
| if (uncurriedSites.size() < expectedSiteCount) { |
| uncurriedSites.push_back(std::move(site)); |
| return; |
| } |
| |
| // Otherwise, apply these arguments to the result of the previous call. |
| extraSites.push_back(std::move(site)); |
| } |
| |
| /// Add a level of function application by passing in its possibly |
| /// unevaluated arguments and their formal type |
| template<typename...T> |
| void addCallSite(T &&...args) { |
| addCallSite(CallSite{std::forward<T>(args)...}); |
| } |
| |
| /// Is this a fully-applied enum element constructor call? |
| bool isEnumElementConstructor() { |
| return (callee.kind == Callee::Kind::EnumElement && |
| uncurriedSites.size() == expectedSiteCount); |
| } |
| |
| /// True if this is a completely unapplied super method call |
| bool isPartiallyAppliedSuperMethod() { |
| return (callee.kind == Callee::Kind::SuperMethod && |
| uncurriedSites.size() == 1); |
| } |
| |
| RValue apply(SGFContext C = SGFContext()) { |
| initialWritebackScope.verify(); |
| |
| // Emit the first level of call. |
| auto firstLevelResult = applyFirstLevelCallee(C); |
| |
| // End of the initial writeback scope. |
| initialWritebackScope.verify(); |
| initialWritebackScope.pop(); |
| |
| // If we do not have any more call sites, bail early and just return the |
| // value. |
| if (extraSites.empty()) { |
| return std::move(firstLevelResult.value); |
| } |
| |
| // At this point, firstLevelResult should have a formal type for the |
| // remaining call sites. Do a quick assert to make sure that we have our |
| // rvalue and the relevant foreign type. |
| assert(firstLevelResult.isComplete()); |
| |
| AbstractionPattern origFormalType = |
| getIndirectApplyAbstractionPattern(SGF, firstLevelResult.formalType); |
| bool formalTypeThrows = |
| !cast<FunctionType>(firstLevelResult.formalType)->getExtInfo().throws(); |
| |
| // Then handle the remaining call sites. |
| return applyRemainingCallSites(std::move(firstLevelResult.value), |
| origFormalType, firstLevelResult.foreignSelf, |
| C, formalTypeThrows); |
| } |
| |
| // Movable, but not copyable. |
| CallEmission(CallEmission &&e) = default; |
| |
| private: |
| CallEmission(const CallEmission &) = delete; |
| CallEmission &operator=(const CallEmission &) = delete; |
| |
| /// Emit all of the arguments for a normal apply. This means an apply that |
| /// is not: |
| /// |
| /// 1. A specialized emitter (e.g. an emitter for a builtin). |
| /// 2. A partially applied super method. |
| /// 3. An enum element constructor. |
| /// |
| /// It is though all other initial calls and subsequent callees that we feed |
| /// the first callee into. |
| /// |
| /// This returns whether or not any arguments were able to throw in |
| /// ApplyOptions. |
| ApplyOptions emitArgumentsForNormalApply( |
| CanFunctionType &formalType, AbstractionPattern &origFormalType, |
| CanSILFunctionType substFnType, |
| const Optional<ForeignErrorConvention> &foreignError, |
| ImportAsMemberStatus foreignSelf, |
| SmallVectorImpl<ManagedValue> &uncurriedArgs, |
| Optional<SILLocation> &uncurriedLoc, CanFunctionType &formalApplyType); |
| |
| struct FirstLevelApplicationResult { |
| RValue value; |
| CanFunctionType formalType; |
| ImportAsMemberStatus foreignSelf; |
| |
| FirstLevelApplicationResult() = default; |
| |
| // Delete copy constructor/operator, |
| FirstLevelApplicationResult(const FirstLevelApplicationResult &) = delete; |
| FirstLevelApplicationResult & |
| operator=(const FirstLevelApplicationResult &) = delete; |
| |
| // This is a move only type. |
| FirstLevelApplicationResult(FirstLevelApplicationResult &&other) |
| : value(std::move(other.value)), formalType(other.formalType), |
| foreignSelf(other.foreignSelf) {} |
| FirstLevelApplicationResult & |
| operator=(FirstLevelApplicationResult &&other) { |
| value = std::move(other.value); |
| formalType = other.formalType; |
| foreignSelf = other.foreignSelf; |
| return *this; |
| } |
| |
| /// Verify some variants around a complete FirstLevelApplicationResult. |
| /// |
| /// The specific invariants is that value is complete and that we have a |
| /// formal type. |
| bool isComplete() const { return value.isComplete() && bool(formalType); } |
| }; |
| |
| FirstLevelApplicationResult |
| applySpecializedEmitter(SpecializedEmitter &specializedEmitter, SGFContext C); |
| |
| FirstLevelApplicationResult applyPartiallyAppliedSuperMethod(SGFContext C); |
| |
| FirstLevelApplicationResult applyEnumElementConstructor(SGFContext C); |
| |
| FirstLevelApplicationResult applyNormalCall(SGFContext C); |
| |
| FirstLevelApplicationResult applyFirstLevelCallee(SGFContext C); |
| |
| RValue applyRemainingCallSites(RValue &&result, |
| AbstractionPattern origFormalType, |
| ImportAsMemberStatus foreignSelf, SGFContext C, |
| bool formalTypeThrows); |
| }; |
| |
| } // end anonymous namespace |
| |
| /// This function claims param clauses from the passed in formal type until the |
| /// type is completely uncurried. This will be the final result type for a |
| /// normal call. |
| static AbstractionPattern |
| getUncurriedOrigFormalResultType(AbstractionPattern origFormalType, |
| unsigned numUncurriedSites) { |
| for (unsigned i = 0, e = numUncurriedSites; i < e; ++i) { |
| claimNextParamClause(origFormalType); |
| } |
| |
| return origFormalType; |
| } |
| |
| CallEmission::FirstLevelApplicationResult |
| CallEmission::applyFirstLevelCallee(SGFContext C) { |
| // Check for a specialized emitter. |
| if (uncurriedSites.size() == expectedSiteCount) { |
| if (auto emitter = callee.getSpecializedEmitter(SGF.SGM)) { |
| return applySpecializedEmitter(emitter.getValue(), C); |
| } |
| } |
| |
| if (isPartiallyAppliedSuperMethod()) { |
| return applyPartiallyAppliedSuperMethod(C); |
| } |
| |
| if (isEnumElementConstructor()) { |
| return applyEnumElementConstructor(C); |
| } |
| |
| return applyNormalCall(C); |
| } |
| |
| CallEmission::FirstLevelApplicationResult |
| CallEmission::applyNormalCall(SGFContext C) { |
| FirstLevelApplicationResult firstLevelResult; |
| |
| // We use the context emit-into initialization only for the |
| // outermost call. |
| SGFContext uncurriedContext = (extraSites.empty() ? C : SGFContext()); |
| |
| firstLevelResult.formalType = callee.getSubstFormalType(); |
| auto origFormalType = callee.getOrigFormalType(); |
| |
| bool isCurried = (uncurriedSites.size() < callee.getParameterListCount()); |
| |
| // Get the callee type information. |
| auto calleeTypeInfo = callee.getTypeInfo(SGF, isCurried); |
| |
| // In C language modes, substitute the type of the AbstractionPattern |
| // so that we won't see type parameters down when we try to form bridging |
| // conversions. |
| if (calleeTypeInfo.substFnType->getLanguage() == SILFunctionLanguage::C) { |
| if (auto genericFnType = |
| dyn_cast<GenericFunctionType>(origFormalType.getType())) { |
| auto fnType = genericFnType->substGenericArgs(callee.getSubstitutions()); |
| origFormalType.rewriteType(CanGenericSignature(), |
| fnType->getCanonicalType()); |
| } |
| } |
| |
| // Initialize the rest of the call info. |
| calleeTypeInfo.origResultType = |
| getUncurriedOrigFormalResultType(origFormalType, uncurriedSites.size()); |
| calleeTypeInfo.substResultType = uncurriedSites.back().getSubstResultType(); |
| |
| ResultPlanPtr resultPlan = ResultPlanBuilder::computeResultPlan( |
| SGF, calleeTypeInfo, uncurriedSites.back().Loc, uncurriedContext); |
| |
| ArgumentScope argScope(SGF, uncurriedSites.back().Loc); |
| PostponedCleanup postpone(SGF); |
| // Emit the arguments. |
| SmallVector<ManagedValue, 4> uncurriedArgs; |
| Optional<SILLocation> uncurriedLoc; |
| CanFunctionType formalApplyType; |
| |
| // *NOTE* We pass in initial options as a reference so that we can pass to |
| // emitApply if any of the arguments could have thrown. |
| ApplyOptions options = emitArgumentsForNormalApply( |
| firstLevelResult.formalType, origFormalType, calleeTypeInfo.substFnType, |
| calleeTypeInfo.foreignError, calleeTypeInfo.foreignSelf, uncurriedArgs, |
| uncurriedLoc, formalApplyType); |
| |
| // Now evaluate the callee. |
| Optional<ManagedValue> borrowedSelf; |
| if (callee.requiresSelfValueForDispatch()) { |
| borrowedSelf = uncurriedArgs.back(); |
| } |
| |
| auto mv = callee.getFnValue(SGF, isCurried, borrowedSelf); |
| |
| // Emit the uncurried call. |
| firstLevelResult.value = SGF.emitApply( |
| std::move(resultPlan), std::move(argScope), uncurriedLoc.getValue(), mv, |
| callee.getSubstitutions(), uncurriedArgs, calleeTypeInfo, options, |
| uncurriedContext, postpone); |
| firstLevelResult.foreignSelf = calleeTypeInfo.foreignSelf; |
| return firstLevelResult; |
| } |
| |
| CallEmission::FirstLevelApplicationResult |
| CallEmission::applyEnumElementConstructor(SGFContext C) { |
| FirstLevelApplicationResult firstLevelResult; |
| SGFContext uncurriedContext = (extraSites.empty() ? C : SGFContext()); |
| |
| // Get the callee type information. |
| // |
| // Enum payloads are always stored at the abstraction level of the |
| // unsubstituted payload type. This means that unlike with specialized |
| // emitters above, enum constructors use the AST-level abstraction |
| // pattern, to ensure that function types in payloads are re-abstracted |
| // correctly. |
| firstLevelResult.formalType = callee.getSubstFormalType(); |
| auto origFormalType = callee.getOrigFormalType(); |
| auto substFnType = |
| SGF.getSILFunctionType(origFormalType, firstLevelResult.formalType); |
| |
| // We have a fully-applied enum element constructor: open-code the |
| // construction. |
| EnumElementDecl *element = callee.getEnumElementDecl(); |
| |
| SILLocation uncurriedLoc = uncurriedSites[0].Loc; |
| |
| CanType formalResultType = firstLevelResult.formalType.getResult(); |
| |
| // Ignore metatype argument |
| claimNextParamClause(origFormalType); |
| claimNextParamClause(firstLevelResult.formalType); |
| std::move(uncurriedSites[0]).forward().getAsSingleValue(SGF); |
| |
| // Get the payload argument. |
| ArgumentSource payload; |
| if (element->hasAssociatedValues()) { |
| assert(uncurriedSites.size() == 2); |
| formalResultType = firstLevelResult.formalType.getResult(); |
| claimNextParamClause(origFormalType); |
| claimNextParamClause(firstLevelResult.formalType); |
| payload = std::move(uncurriedSites[1]).forward(); |
| } else { |
| assert(uncurriedSites.size() == 1); |
| } |
| |
| assert(substFnType->getNumResults() == 1); |
| ManagedValue resultMV = SGF.emitInjectEnum( |
| uncurriedLoc, std::move(payload), SGF.getLoweredType(formalResultType), |
| element, uncurriedContext); |
| firstLevelResult.value = |
| RValue(SGF, uncurriedLoc, formalResultType, resultMV); |
| return firstLevelResult; |
| } |
| |
| CallEmission::FirstLevelApplicationResult |
| CallEmission::applyPartiallyAppliedSuperMethod(SGFContext C) { |
| FirstLevelApplicationResult firstLevelResult; |
| |
| // We want to emit the arguments as fully-substituted values |
| // because that's what the partially applied super method expects; |
| firstLevelResult.formalType = callee.getSubstFormalType(); |
| auto origFormalType = AbstractionPattern(firstLevelResult.formalType); |
| auto substFnType = |
| SGF.getSILFunctionType(origFormalType, firstLevelResult.formalType); |
| |
| // Emit the arguments. |
| SmallVector<ManagedValue, 4> uncurriedArgs; |
| Optional<SILLocation> uncurriedLoc; |
| CanFunctionType formalApplyType; |
| ApplyOptions options = emitArgumentsForNormalApply( |
| firstLevelResult.formalType, origFormalType, substFnType, |
| Optional<ForeignErrorConvention>(), firstLevelResult.foreignSelf, |
| uncurriedArgs, uncurriedLoc, formalApplyType); |
| (void)options; |
| |
| // Emit the uncurried call. |
| assert(uncurriedArgs.size() == 1 && "Can only partially apply the " |
| "self parameter of a super " |
| "method call"); |
| |
| auto constant = callee.getMethodName(); |
| auto loc = uncurriedLoc.getValue(); |
| auto subs = callee.getSubstitutions(); |
| auto upcastedSelf = uncurriedArgs.back(); |
| |
| // Make sure that upcasted self is at +1 since we are going to place it into a |
| // partial_apply. |
| upcastedSelf = upcastedSelf.ensurePlusOne(SGF, loc); |
| |
| auto constantInfo = SGF.getConstantInfo(callee.getMethodName()); |
| auto functionTy = constantInfo.getSILType(); |
| ManagedValue superMethod; |
| { |
| Scope S(SGF, loc); |
| ManagedValue castValue = |
| borrowedCastToOriginalSelfType(SGF, loc, upcastedSelf); |
| if (!constant.isForeign) { |
| superMethod = SGF.B.createSuperMethod(loc, castValue, constant, |
| functionTy); |
| } else { |
| superMethod = SGF.B.createObjCSuperMethod(loc, castValue, constant, |
| functionTy); |
| } |
| } |
| auto calleeConvention = ParameterConvention::Direct_Guaranteed; |
| auto closureTy = SILGenBuilder::getPartialApplyResultType( |
| constantInfo.getSILType(), 1, SGF.B.getModule(), subs, calleeConvention); |
| |
| auto &module = SGF.getFunction().getModule(); |
| |
| auto partialApplyTy = functionTy; |
| if (constantInfo.SILFnType->isPolymorphic() && !subs.empty()) |
| partialApplyTy = partialApplyTy.substGenericArgs(module, subs); |
| |
| ManagedValue pa = SGF.B.createPartialApply(loc, superMethod, partialApplyTy, |
| subs, {upcastedSelf}, closureTy); |
| assert(!closureTy.castTo<SILFunctionType>()->isNoEscape()); |
| firstLevelResult.value = RValue(SGF, loc, formalApplyType.getResult(), pa); |
| return firstLevelResult; |
| } |
| |
| CallEmission::FirstLevelApplicationResult |
| CallEmission::applySpecializedEmitter(SpecializedEmitter &specializedEmitter, |
| SGFContext C) { |
| FirstLevelApplicationResult firstLevelResult; |
| |
| // We use the context emit-into initialization only for the |
| // outermost call. |
| SGFContext uncurriedContext = (extraSites.empty() ? C : SGFContext()); |
| |
| ManagedValue mv; |
| |
| // Get the callee type information. We want to emit the arguments as |
| // fully-substituted values because that's what the specialized emitters |
| // expect. |
| firstLevelResult.formalType = callee.getSubstFormalType(); |
| auto origFormalType = AbstractionPattern(firstLevelResult.formalType); |
| auto substFnType = |
| SGF.getSILFunctionType(origFormalType, firstLevelResult.formalType); |
| |
| // If we have an early emitter, just let it take over for the |
| // uncurried call site. |
| if (specializedEmitter.isEarlyEmitter()) { |
| auto emitter = specializedEmitter.getEarlyEmitter(); |
| |
| assert(uncurriedSites.size() == 1); |
| CanFunctionType formalApplyType = |
| cast<FunctionType>(firstLevelResult.formalType); |
| assert(!formalApplyType->getExtInfo().throws()); |
| CanType formalResultType = formalApplyType.getResult(); |
| SILLocation uncurriedLoc = uncurriedSites[0].Loc; |
| claimNextParamClause(origFormalType); |
| claimNextParamClause(firstLevelResult.formalType); |
| |
| // We should be able to enforce that these arguments are |
| // always still expressions. |
| Expr *argument = std::move(uncurriedSites[0]).forward().asKnownExpr(); |
| ManagedValue resultMV = |
| emitter(SGF, uncurriedLoc, callee.getSubstitutions(), argument, |
| uncurriedContext); |
| firstLevelResult.value = |
| RValue(SGF, uncurriedLoc, formalResultType, resultMV); |
| return firstLevelResult; |
| } |
| |
| // Emit the arguments. |
| SmallVector<ManagedValue, 4> uncurriedArgs; |
| Optional<SILLocation> uncurriedLoc; |
| CanFunctionType formalApplyType; |
| emitArgumentsForNormalApply(firstLevelResult.formalType, origFormalType, |
| substFnType, Optional<ForeignErrorConvention>(), |
| firstLevelResult.foreignSelf, uncurriedArgs, |
| uncurriedLoc, formalApplyType); |
| |
| // If we have a late emitter, just delegate to that emitter and return. |
| if (specializedEmitter.isLateEmitter()) { |
| auto emitter = specializedEmitter.getLateEmitter(); |
| ManagedValue mv = emitter(SGF, *uncurriedLoc, callee.getSubstitutions(), |
| uncurriedArgs, uncurriedContext); |
| firstLevelResult.value = |
| RValue(SGF, *uncurriedLoc, formalApplyType.getResult(), mv); |
| return firstLevelResult; |
| } |
| |
| // Builtins. |
| assert(specializedEmitter.isNamedBuiltin()); |
| auto builtinName = specializedEmitter.getBuiltinName(); |
| SmallVector<SILValue, 4> consumedArgs; |
| for (auto arg : uncurriedArgs) { |
| // Builtins have a special convention that takes everything at +1. |
| auto maybePlusOne = arg.ensurePlusOne(SGF, uncurriedLoc.getValue()); |
| consumedArgs.push_back(maybePlusOne.forward(SGF)); |
| } |
| SILFunctionConventions substConv(substFnType, SGF.SGM.M); |
| auto resultVal = SGF.B.createBuiltin(uncurriedLoc.getValue(), builtinName, |
| substConv.getSILResultType(), |
| callee.getSubstitutions(), consumedArgs); |
| firstLevelResult.value = |
| RValue(SGF, *uncurriedLoc, formalApplyType.getResult(), |
| SGF.emitManagedRValueWithCleanup(resultVal)); |
| return firstLevelResult; |
| } |
| |
| ApplyOptions CallEmission::emitArgumentsForNormalApply( |
| CanFunctionType &formalType, AbstractionPattern &origFormalType, |
| CanSILFunctionType substFnType, |
| const Optional<ForeignErrorConvention> &foreignError, |
| ImportAsMemberStatus foreignSelf, |
| SmallVectorImpl<ManagedValue> &uncurriedArgs, |
| Optional<SILLocation> &uncurriedLoc, CanFunctionType &formalApplyType) { |
| ApplyOptions options = ApplyOptions::None; |
| |
| SmallVector<SmallVector<ManagedValue, 4>, 2> args; |
| SmallVector<DelayedArgument, 2> delayedArgs; |
| auto expectedUncurriedOrigResultFormalType = |
| getUncurriedOrigFormalResultType(origFormalType, uncurriedSites.size()); |
| (void)expectedUncurriedOrigResultFormalType; |
| |
| args.reserve(uncurriedSites.size()); |
| { |
| ParamLowering paramLowering(substFnType, SGF); |
| |
| assert(!foreignError || uncurriedSites.size() == 1 || |
| (uncurriedSites.size() == 2 && substFnType->hasSelfParam())); |
| |
| if (!uncurriedSites.back().throws()) { |
| options |= ApplyOptions::DoesNotThrow; |
| } |
| |
| // Collect the captures, if any. |
| if (callee.hasCaptures()) { |
| (void)paramLowering.claimCaptureParams(callee.getCaptures()); |
| args.push_back({}); |
| args.back().append(callee.getCaptures().begin(), |
| callee.getCaptures().end()); |
| } |
| |
| // Collect the arguments to the uncurried call. |
| for (auto &site : uncurriedSites) { |
| AbstractionPattern origParamType = claimNextParamClause(origFormalType); |
| formalApplyType = cast<FunctionType>(formalType); |
| claimNextParamClause(formalType); |
| uncurriedLoc = site.Loc; |
| args.push_back({}); |
| |
| bool isParamSite = &site == &uncurriedSites.back(); |
| |
| std::move(site).emit(SGF, origParamType, paramLowering, args.back(), |
| delayedArgs, |
| // Claim the foreign error with the method |
| // formal params. |
| isParamSite ? foreignError : None, |
| // Claim the foreign "self" with the self |
| // param. |
| isParamSite ? ImportAsMemberStatus() : foreignSelf); |
| } |
| } |
| assert(uncurriedLoc); |
| assert(formalApplyType); |
| assert(origFormalType.getType() == |
| expectedUncurriedOrigResultFormalType.getType() && |
| "expectedUncurriedOrigResultFormalType and emitArgumentsForNormalCall " |
| "are out of sync"); |
| |
| // Emit any delayed arguments: formal accesses to inout arguments, etc. |
| if (!delayedArgs.empty()) { |
| emitDelayedArguments(SGF, delayedArgs, args); |
| } |
| |
| // Uncurry the arguments in calling convention order. |
| for (auto &argSet : reversed(args)) |
| uncurriedArgs.append(argSet.begin(), argSet.end()); |
| args = {}; |
| |
| // Move the foreign "self" argument into position. |
| if (foreignSelf.isInstance()) { |
| auto selfArg = uncurriedArgs.back(); |
| std::move_backward(uncurriedArgs.begin() + foreignSelf.getSelfIndex(), |
| uncurriedArgs.end() - 1, uncurriedArgs.end()); |
| uncurriedArgs[foreignSelf.getSelfIndex()] = selfArg; |
| } |
| |
| return options; |
| } |
| |
| RValue CallEmission::applyRemainingCallSites(RValue &&result, |
| AbstractionPattern origFormalType, |
| ImportAsMemberStatus foreignSelf, |
| SGFContext C, |
| bool formalTypeThrows) { |
| assert(!extraSites.empty() && |
| "We should only get here if we actually have extra callsites"); |
| |
| // Apply the remaining call sites to the result function. |
| // Each chained call gets its own writeback scope. |
| for (unsigned i = 0, size = extraSites.size(); i < size; ++i) { |
| FormalEvaluationScope writebackScope(SGF); |
| |
| SILLocation loc = extraSites[i].Loc; |
| |
| auto functionMV = std::move(result).getAsSingleValue(SGF, loc); |
| |
| auto substFnType = functionMV.getType().castTo<SILFunctionType>(); |
| ParamLowering paramLowering(substFnType, SGF); |
| |
| SmallVector<ManagedValue, 4> siteArgs; |
| SmallVector<DelayedArgument, 2> delayedArgs; |
| |
| // TODO: foreign errors for block or function pointer values? |
| assert(substFnType->hasErrorResult() || formalTypeThrows); |
| |
| AbstractionPattern origParamType = claimNextParamClause(origFormalType); |
| AbstractionPattern origResultType = origFormalType; |
| |
| SGFContext context = i == size - 1 ? C : SGFContext(); |
| |
| // Create the callee type info and initialize our indirect results. |
| CalleeTypeInfo calleeTypeInfo( |
| substFnType, origResultType, extraSites[i].getSubstResultType(), |
| Optional<ForeignErrorConvention>(), foreignSelf); |
| ResultPlanPtr resultPtr = |
| ResultPlanBuilder::computeResultPlan(SGF, calleeTypeInfo, loc, context); |
| ArgumentScope argScope(SGF, loc); |
| PostponedCleanup postpone(SGF); |
| |
| std::move(extraSites[i]) |
| .emit(SGF, origParamType, paramLowering, siteArgs, delayedArgs, |
| calleeTypeInfo.foreignError, calleeTypeInfo.foreignSelf); |
| if (!delayedArgs.empty()) { |
| emitDelayedArguments(SGF, delayedArgs, siteArgs); |
| } |
| |
| result = SGF.emitApply(std::move(resultPtr), std::move(argScope), loc, |
| functionMV, {}, siteArgs, calleeTypeInfo, |
| ApplyOptions::None, context, postpone); |
| } |
| |
| return std::move(result); |
| } |
| |
| CallEmission CallEmission::forApplyExpr(SILGenFunction &SGF, Expr *e) { |
| // Set up writebacks for the call(s). |
| FormalEvaluationScope writebacks(SGF); |
| |
| SILGenApply apply(SGF); |
| |
| // Decompose the call site. |
| apply.decompose(e); |
| |
| // Evaluate and discard the side effect if present. |
| if (apply.sideEffect) |
| SGF.emitRValue(apply.sideEffect); |
| |
| // Build the call. |
| // Pass the writeback scope on to CallEmission so it can thread scopes through |
| // nested calls. |
| CallEmission emission(SGF, apply.getCallee(), std::move(writebacks)); |
| |
| // Apply 'self' if provided. |
| if (apply.selfParam) { |
| emission.addCallSite(RegularLocation(e), std::move(apply.selfParam), |
| apply.selfType->getCanonicalType(), /*throws*/ false); |
| } |
| |
| // Apply arguments from call sites, innermost to outermost. |
| for (auto site = apply.callSites.rbegin(), end = apply.callSites.rend(); |
| site != end; |
| ++site) { |
| emission.addCallSite(*site); |
| } |
| |
| return emission; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Top Level Entrypoints |
| //===----------------------------------------------------------------------===// |
| |
| /// Emit a function application, assuming that the arguments have been |
| /// lowered appropriately for the abstraction level but that the |
| /// result does need to be turned back into something matching a |
| /// formal type. |
| RValue SILGenFunction::emitApply(ResultPlanPtr &&resultPlan, |
| ArgumentScope &&argScope, SILLocation loc, |
| ManagedValue fn, SubstitutionList subs, |
| ArrayRef<ManagedValue> args, |
| const CalleeTypeInfo &calleeTypeInfo, |
| ApplyOptions options, SGFContext evalContext, |
| PostponedCleanup &postponedCleanup) { |
| auto substFnType = calleeTypeInfo.substFnType; |
| auto substResultType = calleeTypeInfo.substResultType; |
| |
| // Create the result plan. |
| SmallVector<SILValue, 4> indirectResultAddrs; |
| resultPlan->gatherIndirectResultAddrs(*this, loc, indirectResultAddrs); |
| |
| // If the function returns an inner pointer, we'll need to lifetime-extend |
| // the 'self' parameter. |
| SILValue lifetimeExtendedSelf; |
| bool hasAlreadyLifetimeExtendedSelf = false; |
| if (hasUnownedInnerPointerResult(substFnType)) { |
| auto selfMV = args.back(); |
| lifetimeExtendedSelf = selfMV.getValue(); |
| |
| switch (substFnType->getParameters().back().getConvention()) { |
| case ParameterConvention::Direct_Owned: |
| // If the callee will consume the 'self' parameter, let's retain it so we |
| // can keep it alive. |
| lifetimeExtendedSelf = |
| B.emitCopyValueOperation(loc, lifetimeExtendedSelf); |
| break; |
| case ParameterConvention::Direct_Guaranteed: |
| case ParameterConvention::Direct_Unowned: |
| // We'll manually manage the argument's lifetime after the |
| // call. Disable its cleanup, forcing a copy if it was emitted +0. |
| if (selfMV.hasCleanup()) { |
| selfMV.forwardCleanup(*this); |
| } else { |
| lifetimeExtendedSelf = selfMV.copyUnmanaged(*this, loc).forward(*this); |
| } |
| break; |
| |
| case ParameterConvention::Indirect_In_Guaranteed: |
| case ParameterConvention::Indirect_In: |
| case ParameterConvention::Indirect_In_Constant: |
| case ParameterConvention::Indirect_Inout: |
| case ParameterConvention::Indirect_InoutAliasable: |
| // We may need to support this at some point, but currently only imported |
| // objc methods are returns_inner_pointer. |
| llvm_unreachable("indirect self argument to method that" |
| " returns_inner_pointer?!"); |
| } |
| } |
| |
| // If there's a foreign error parameter, fill it in. |
| ManagedValue errorTemp; |
| if (auto foreignError = calleeTypeInfo.foreignError) { |
| unsigned errorParamIndex = |
| calleeTypeInfo.foreignError->getErrorParameterIndex(); |
| |
| // This is pretty evil. |
| auto &errorArgSlot = const_cast<ManagedValue &>(args[errorParamIndex]); |
| |
| std::tie(errorTemp, errorArgSlot) = |
| resultPlan->emitForeignErrorArgument(*this, loc).getValue(); |
| } |
| |
| // Emit the raw application. |
| loc.decodeDebugLoc(SGM.M.getASTContext().SourceMgr); |
| postponedCleanup.end(); |
| SILValue rawDirectResult = emitRawApply( |
| *this, loc, fn, subs, args, substFnType, options, indirectResultAddrs); |
| |
| // Pop the argument scope. |
| argScope.pop(); |
| |
| // Explode the direct results. |
| SILFunctionConventions substFnConv(substFnType, SGM.M); |
| SmallVector<ManagedValue, 4> directResults; |
| auto addManagedDirectResult = [&](SILValue result, |
| const SILResultInfo &resultInfo) { |
| auto &resultTL = getTypeLowering(resultInfo.getType()); |
| |
| switch (resultInfo.getConvention()) { |
| case ResultConvention::Indirect: |
| assert(!substFnConv.isSILIndirect(resultInfo) && |
| "indirect direct result?"); |
| break; |
| |
| case ResultConvention::Owned: |
| break; |
| |
| // For autoreleased results, the reclaim is implicit, so the value is |
| // effectively +1. |
| case ResultConvention::Autoreleased: |
| break; |
| |
| // Autorelease the 'self' value to lifetime-extend it. |
| case ResultConvention::UnownedInnerPointer: |
| assert(lifetimeExtendedSelf && |
| "did not save lifetime-extended self param"); |
| if (!hasAlreadyLifetimeExtendedSelf) { |
| B.createAutoreleaseValue(loc, lifetimeExtendedSelf, |
| B.getDefaultAtomicity()); |
| hasAlreadyLifetimeExtendedSelf = true; |
| } |
| LLVM_FALLTHROUGH; |
| |
| case ResultConvention::Unowned: |
| // Unretained. Retain the value. |
| result = resultTL.emitCopyValue(B, loc, result); |
| break; |
| } |
| |
| directResults.push_back(emitManagedRValueWithCleanup(result, resultTL)); |
| }; |
| |
| auto directSILResults = substFnConv.getDirectSILResults(); |
| if (directSILResults.empty()) { |
| // Nothing to do. |
| } else if (substFnConv.getNumDirectSILResults() == 1) { |
| addManagedDirectResult(rawDirectResult, *directSILResults.begin()); |
| } else { |
| llvm::SmallVector<std::pair<SILValue, const SILResultInfo &>, 8> |
| copiedResults; |
| { |
| Scope S(Cleanups, CleanupLocation::get(loc)); |
| |
| // First create an rvalue cleanup for our direct result. |
| ManagedValue managedDirectResult = |
| emitManagedRValueWithCleanup(rawDirectResult); |
| // Then borrow the managed direct result. |
| ManagedValue borrowedDirectResult = |
| managedDirectResult.borrow(*this, loc); |
| // Then create unmanaged copies of the direct result and forward the |
| // result as expected by addManageDirectResult. |
| unsigned Index = 0; |
| for (const SILResultInfo &directResult : directSILResults) { |
| ManagedValue elt = |
| B.createTupleExtract(loc, borrowedDirectResult, Index, |
| substFnConv.getSILType(directResult)); |
| SILValue v = elt.copyUnmanaged(*this, loc).forward(*this); |
| // We assume that unowned inner pointers, autoreleased values, and |
| // indirect values are never returned in tuples. |
| // FIXME: can this assertion be removed without lowered addresses? |
| assert(directResult.getConvention() == ResultConvention::Owned || |
| directResult.getConvention() == ResultConvention::Unowned || |
| !substFnConv.useLoweredAddresses()); |
| copiedResults.push_back({v, directResult}); |
| ++Index; |
| } |
| // Then allow the cleanups to be emitted in the proper reverse order. |
| } |
| // Finally add our managed direct results. |
| for (auto p : copiedResults) { |
| addManagedDirectResult(p.first, p.second); |
| } |
| } |
| |
| // If there was a foreign error convention, consider it. |
| // TODO: maybe this should happen after managing the result if it's |
| // not a result-checking convention? |
| if (auto foreignError = calleeTypeInfo.foreignError) { |
| bool doesNotThrow = (options & ApplyOptions::DoesNotThrow); |
| emitForeignErrorCheck(loc, directResults, errorTemp, doesNotThrow, |
| *foreignError); |
| } |
| |
| auto directResultsArray = makeArrayRef(directResults); |
| RValue result = |
| resultPlan->finish(*this, loc, substResultType, directResultsArray); |
| assert(directResultsArray.empty() && "didn't claim all direct results"); |
| |
| return result; |
| } |
| |
| RValue SILGenFunction::emitMonomorphicApply( |
| SILLocation loc, ManagedValue fn, ArrayRef<ManagedValue> args, |
| CanType foreignResultType, CanType nativeResultType, ApplyOptions options, |
| Optional<SILFunctionTypeRepresentation> overrideRep, |
| const Optional<ForeignErrorConvention> &foreignError, |
| SGFContext evalContext) { |
| auto fnType = fn.getType().castTo<SILFunctionType>(); |
| assert(!fnType->isPolymorphic()); |
| CalleeTypeInfo calleeTypeInfo(fnType, AbstractionPattern(foreignResultType), |
| nativeResultType, foreignError, |
| ImportAsMemberStatus(), overrideRep); |
| ResultPlanPtr resultPlan = ResultPlanBuilder::computeResultPlan( |
| *this, calleeTypeInfo, loc, evalContext); |
| ArgumentScope argScope(*this, loc); |
| PostponedCleanup postpone(*this); |
| return emitApply(std::move(resultPlan), std::move(argScope), loc, fn, {}, |
| args, calleeTypeInfo, options, evalContext, postpone); |
| } |
| |
| /// Emit either an 'apply' or a 'try_apply', with the error branch of |
| /// the 'try_apply' simply branching out of all cleanups and throwing. |
| SILValue SILGenFunction::emitApplyWithRethrow(SILLocation loc, SILValue fn, |
| SILType substFnType, |
| SubstitutionList subs, |
| ArrayRef<SILValue> args) { |
| CanSILFunctionType silFnType = substFnType.castTo<SILFunctionType>(); |
| SILFunctionConventions fnConv(silFnType, SGM.M); |
| SILType resultType = fnConv.getSILResultType(); |
| |
| if (!silFnType->hasErrorResult()) { |
| return B.createApply(loc, fn, substFnType, resultType, subs, args); |
| } |
| |
| SILBasicBlock *errorBB = createBasicBlock(); |
| SILBasicBlock *normalBB = createBasicBlock(); |
| B.createTryApply(loc, fn, substFnType, subs, args, normalBB, errorBB); |
| |
| // Emit the rethrow logic. |
| { |
| B.emitBlock(errorBB); |
| SILValue error = errorBB->createPHIArgument(fnConv.getSILErrorType(), |
| ValueOwnershipKind::Owned); |
| |
| B.createBuiltin(loc, SGM.getASTContext().getIdentifier("willThrow"), |
| SGM.Types.getEmptyTupleType(), {}, {error}); |
| |
| Cleanups.emitCleanupsForReturn(CleanupLocation::get(loc)); |
| B.createThrow(loc, error); |
| } |
| |
| // Enter the normal path. |
| B.emitBlock(normalBB); |
| return normalBB->createPHIArgument(resultType, ValueOwnershipKind::Owned); |
| } |
| |
| /// Emits SIL instructions to create an enum value. Attempts to avoid |
| /// unnecessary copies by emitting the payload directly into the enum |
| /// payload, or into the box in the case of an indirect payload. |
| ManagedValue SILGenFunction::emitInjectEnum(SILLocation loc, |
| ArgumentSource payload, |
| SILType enumTy, |
| EnumElementDecl *element, |
| SGFContext C) { |
| // Easy case -- no payload |
| if (!payload) { |
| if (enumTy.isLoadable(SGM.M) || !silConv.useLoweredAddresses()) { |
| return emitManagedRValueWithCleanup( |
| B.createEnum(loc, SILValue(), element, enumTy.getObjectType())); |
| } |
| |
| // Emit the enum directly into the context if possible |
| return B.bufferForExpr(loc, enumTy, getTypeLowering(enumTy), C, |
| [&](SILValue newAddr) { |
| B.createInjectEnumAddr(loc, newAddr, element); |
| }); |
| } |
| |
| ManagedValue payloadMV; |
| AbstractionPattern origFormalType = |
| (element == getASTContext().getOptionalSomeDecl() |
| ? AbstractionPattern(payload.getSubstType()) |
| : SGM.M.Types.getAbstractionPattern(element)); |
| auto &payloadTL = getTypeLowering(origFormalType, payload.getSubstType()); |
| |
| SILType loweredPayloadType = payloadTL.getLoweredType(); |
| |
| // If the payload is indirect, emit it into a heap allocated box. |
| // |
| // To avoid copies, evaluate it directly into the box, being |
| // careful to stage the cleanups so that if the expression |
| // throws, we know to deallocate the uninitialized box. |
| if (element->isIndirect() || element->getParentEnum()->isIndirect()) { |
| auto boxTy = SGM.M.Types.getBoxTypeForEnumElement(enumTy, element); |
| auto *box = B.createAllocBox(loc, boxTy); |
| auto *addr = B.createProjectBox(loc, box, 0); |
| |
| CleanupHandle initCleanup = enterDestroyCleanup(box); |
| Cleanups.setCleanupState(initCleanup, CleanupState::Dormant); |
| CleanupHandle uninitCleanup = enterDeallocBoxCleanup(box); |
| |
| BoxInitialization dest(box, addr, uninitCleanup, initCleanup); |
| |
| std::move(payload).forwardInto(*this, origFormalType, &dest, payloadTL); |
| |
| payloadMV = dest.getManagedBox(); |
| loweredPayloadType = payloadMV.getType(); |
| } |
| |
| // Loadable with payload |
| if (enumTy.isLoadable(SGM.M) || !silConv.useLoweredAddresses()) { |
| if (!payloadMV) { |
| // If the payload was indirect, we already evaluated it and |
| // have a single value. Otherwise, evaluate the payload. |
| payloadMV = std::move(payload).getAsSingleValue(*this, origFormalType); |
| } |
| |
| SILValue argValue = payloadMV.forward(*this); |
| |
| return emitManagedRValueWithCleanup( |
| B.createEnum(loc, argValue, element, enumTy.getObjectType())); |
| } |
| |
| // Address-only with payload |
| return B.bufferForExpr( |
| loc, enumTy, getTypeLowering(enumTy), C, [&](SILValue bufferAddr) { |
| SILValue resultData = B.createInitEnumDataAddr( |
| loc, bufferAddr, element, loweredPayloadType.getAddressType()); |
| |
| if (payloadMV) { |
| // If the payload was indirect, we already evaluated it and |
| // have a single value. Store it into the result. |
| B.emitStoreValueOperation(loc, payloadMV.forward(*this), resultData, |
| StoreOwnershipQualifier::Init); |
| } else if (payloadTL.isLoadable()) { |
| // The payload of this specific enum case might be loadable |
| // even if the overall enum is address-only. |
| payloadMV = |
| std::move(payload).getAsSingleValue(*this, origFormalType); |
| B.emitStoreValueOperation(loc, payloadMV.forward(*this), resultData, |
| StoreOwnershipQualifier::Init); |
| } else { |
| // The payload is address-only. Evaluate it directly into |
| // the enum. |
| |
| TemporaryInitialization dest(resultData, CleanupHandle::invalid()); |
| std::move(payload).forwardInto(*this, origFormalType, &dest, |
| payloadTL); |
| } |
| |
| // The payload is initialized, now apply the tag. |
| B.createInjectEnumAddr(loc, bufferAddr, element); |
| }); |
| } |
| |
| RValue SILGenFunction::emitApplyExpr(Expr *e, SGFContext c) { |
| CallEmission emission = CallEmission::forApplyExpr(*this, e); |
| return emission.apply(c); |
| } |
| |
| RValue |
| SILGenFunction::emitApplyOfLibraryIntrinsic(SILLocation loc, |
| FuncDecl *fn, |
| const SubstitutionMap &subMap, |
| ArrayRef<ManagedValue> args, |
| SGFContext ctx) { |
| SmallVector<Substitution, 4> subs; |
| if (auto *genericSig = fn->getGenericSignature()) |
| genericSig->getSubstitutions(subMap, subs); |
| |
| return emitApplyOfLibraryIntrinsic(loc, fn, subs, args, ctx); |
| } |
| |
| RValue |
| SILGenFunction::emitApplyOfLibraryIntrinsic(SILLocation loc, |
| FuncDecl *fn, |
| const SubstitutionList &subs, |
| ArrayRef<ManagedValue> args, |
| SGFContext ctx) { |
| auto callee = Callee::forDirect(*this, SILDeclRef(fn), subs, loc); |
| |
| auto origFormalType = callee.getOrigFormalType(); |
| auto substFormalType = callee.getSubstFormalType(); |
| |
| auto calleeTypeInfo = callee.getTypeInfo(*this, /*isCurried=*/false); |
| |
| Optional<ManagedValue> borrowedSelf; |
| if (callee.requiresSelfValueForDispatch()) |
| borrowedSelf = args.back(); |
| auto mv = callee.getFnValue(*this, /*isCurried=*/false, |
| borrowedSelf); |
| |
| assert(!calleeTypeInfo.foreignError); |
| assert(!calleeTypeInfo.foreignSelf.isImportAsMember()); |
| assert(calleeTypeInfo.substFnType->getExtInfo().getLanguage() == |
| SILFunctionLanguage::Swift); |
| |
| calleeTypeInfo.origResultType = origFormalType.getFunctionResultType(); |
| calleeTypeInfo.substResultType = substFormalType.getResult(); |
| |
| SILFunctionConventions silConv(calleeTypeInfo.substFnType, getModule()); |
| llvm::SmallVector<ManagedValue, 8> finalArgs; |
| convertOwnershipConventionsGivenParamInfos(*this, silConv.getParameters(), args, loc, finalArgs); |
| |
| ResultPlanPtr resultPlan = |
| ResultPlanBuilder::computeResultPlan(*this, calleeTypeInfo, loc, ctx); |
| ArgumentScope argScope(*this, loc); |
| PostponedCleanup postpone(*this); |
| return emitApply(std::move(resultPlan), std::move(argScope), loc, mv, subs, |
| finalArgs, calleeTypeInfo, ApplyOptions::None, ctx, |
| postpone); |
| } |
| |
| static StringRef |
| getMagicFunctionString(SILGenFunction &SGF) { |
| assert(SGF.MagicFunctionName |
| && "asking for #function but we don't have a function name?!"); |
| if (SGF.MagicFunctionString.empty()) { |
| llvm::raw_string_ostream os(SGF.MagicFunctionString); |
| SGF.MagicFunctionName.printPretty(os); |
| } |
| return SGF.MagicFunctionString; |
| } |
| |
| /// Emit an application of the given allocating initializer. |
| static RValue emitApplyAllocatingInitializer(SILGenFunction &SGF, |
| SILLocation loc, |
| ConcreteDeclRef init, |
| RValue &&args, |
| Type overriddenSelfType, |
| SGFContext C) { |
| ConstructorDecl *ctor = cast<ConstructorDecl>(init.getDecl()); |
| |
| // Form the reference to the allocating initializer. |
| auto initRef = SILDeclRef(ctor, SILDeclRef::Kind::Allocator) |
| .asForeign(requiresForeignEntryPoint(ctor)); |
| auto initConstant = SGF.getConstantInfo(initRef); |
| auto subs = init.getSubstitutions(); |
| |
| // Scope any further writeback just within this operation. |
| FormalEvaluationScope writebackScope(SGF); |
| |
| // Form the metatype argument. |
| ManagedValue selfMetaVal; |
| SILType selfMetaTy; |
| { |
| // Determine the self metatype type. |
| CanSILFunctionType substFnType = |
| initConstant.SILFnType->substGenericArgs(SGF.SGM.M, subs); |
| SILType selfParamMetaTy = SGF.getSILType(substFnType->getSelfParameter()); |
| |
| if (overriddenSelfType) { |
| // If the 'self' type has been overridden, form a metatype to the |
| // overriding 'Self' type. |
| Type overriddenSelfMetaType = |
| MetatypeType::get(overriddenSelfType, |
| selfParamMetaTy.castTo<MetatypeType>() |
| ->getRepresentation()); |
| selfMetaTy = |
| SGF.getLoweredType(overriddenSelfMetaType->getCanonicalType()); |
| } else { |
| selfMetaTy = selfParamMetaTy; |
| } |
| |
| // Form the metatype value. |
| SILValue selfMeta = SGF.B.createMetatype(loc, selfMetaTy); |
| |
| // If the types differ, we need an upcast. |
| if (selfMetaTy != selfParamMetaTy) |
| selfMeta = SGF.B.createUpcast(loc, selfMeta, selfParamMetaTy); |
| |
| selfMetaVal = ManagedValue::forUnmanaged(selfMeta); |
| } |
| |
| // Form the callee. |
| Optional<Callee> callee; |
| if (isa<ProtocolDecl>(ctor->getDeclContext())) { |
| callee.emplace(Callee::forWitnessMethod( |
| SGF, selfMetaVal.getType().getSwiftRValueType(), |
| initRef, subs, loc)); |
| } else { |
| callee.emplace(Callee::forDirect(SGF, initRef, subs, loc)); |
| } |
| |
| auto substFormalType = callee->getSubstFormalType(); |
| |
| // For an inheritable initializer, determine whether we'll need to adjust the |
| // result type. |
| bool requiresDowncast = false; |
| if (ctor->isInheritable() && overriddenSelfType) { |
| CanType substResultType = substFormalType; |
| for (unsigned i : range(ctor->getNumParameterLists())) { |
| (void)i; |
| substResultType = cast<FunctionType>(substResultType).getResult(); |
| } |
| |
| if (!substResultType->isEqual(overriddenSelfType)) |
| requiresDowncast = true; |
| } |
| |
| // Form the call emission. |
| CallEmission emission(SGF, std::move(*callee), std::move(writebackScope)); |
| |
| // Self metatype. |
| emission.addCallSite(loc, |
| ArgumentSource(loc, |
| RValue(SGF, loc, |
| selfMetaVal.getType() |
| .getSwiftRValueType(), |
| std::move(selfMetaVal))), |
| substFormalType); |
| |
| // Arguments |
| emission.addCallSite(loc, ArgumentSource(loc, std::move(args)), |
| cast<FunctionType>(substFormalType.getResult())); |
| |
| // Perform the call. |
| RValue result = emission.apply(requiresDowncast ? SGFContext() : C); |
| |
| // If we need a downcast, do it down. |
| if (requiresDowncast) { |
| ManagedValue v = std::move(result).getAsSingleValue(SGF, loc); |
| CanType canOverriddenSelfType = overriddenSelfType->getCanonicalType(); |
| SILType loweredResultTy = SGF.getLoweredType(canOverriddenSelfType); |
| v = SGF.B.createUncheckedRefCast(loc, v, loweredResultTy); |
| result = RValue(SGF, loc, canOverriddenSelfType, v); |
| } |
| |
| return result; |
| } |
| |
| /// Emit a literal that applies the various initializers. |
| RValue SILGenFunction::emitLiteral(LiteralExpr *literal, SGFContext C) { |
| ConcreteDeclRef builtinInit; |
| ConcreteDeclRef init; |
| // Emit the raw, builtin literal arguments. |
| RValue builtinLiteralArgs; |
| if (auto stringLiteral = dyn_cast<StringLiteralExpr>(literal)) { |
| builtinLiteralArgs = emitStringLiteral(*this, literal, |
| stringLiteral->getValue(), C, |
| stringLiteral->getEncoding()); |
| builtinInit = stringLiteral->getBuiltinInitializer(); |
| init = stringLiteral->getInitializer(); |
| } else { |
| ASTContext &ctx = getASTContext(); |
| SourceLoc loc = literal->getStartLoc(); |
| |
| auto magicLiteral = cast<MagicIdentifierLiteralExpr>(literal); |
| switch (magicLiteral->getKind()) { |
| case MagicIdentifierLiteralExpr::File: { |
| StringRef value = ""; |
| if (loc.isValid()) |
| value = ctx.SourceMgr.getBufferIdentifierForLoc(loc); |
| builtinLiteralArgs = emitStringLiteral(*this, literal, value, C, |
| magicLiteral->getStringEncoding()); |
| builtinInit = magicLiteral->getBuiltinInitializer(); |
| init = magicLiteral->getInitializer(); |
| break; |
| } |
| |
| case MagicIdentifierLiteralExpr::Function: { |
| StringRef value = ""; |
| if (loc.isValid()) |
| value = getMagicFunctionString(*this); |
| builtinLiteralArgs = emitStringLiteral(*this, literal, value, C, |
| magicLiteral->getStringEncoding()); |
| builtinInit = magicLiteral->getBuiltinInitializer(); |
| init = magicLiteral->getInitializer(); |
| break; |
| } |
| |
| case MagicIdentifierLiteralExpr::Line: |
| case MagicIdentifierLiteralExpr::Column: |
| case MagicIdentifierLiteralExpr::DSOHandle: |
| llvm_unreachable("handled elsewhere"); |
| } |
| } |
| |
| // Helper routine to add an argument label if we need one. |
| auto relabelArgument = [&](ConcreteDeclRef callee, RValue &arg) { |
| auto name = callee.getDecl()->getFullName(); |
| auto argLabels = name.getArgumentNames(); |
| if (argLabels.size() == 1 && !argLabels[0].empty() && |
| !isa<TupleType>(arg.getType())) { |
| Type newType = TupleType::get({TupleTypeElt(arg.getType(), argLabels[0])}, |
| getASTContext()); |
| arg.rewriteType(newType->getCanonicalType()); |
| } |
| }; |
| |
| // Call the builtin initializer. |
| relabelArgument(builtinInit, builtinLiteralArgs); |
| RValue builtinLiteral = |
| emitApplyAllocatingInitializer(*this, literal, builtinInit, |
| std::move(builtinLiteralArgs), |
| Type(), |
| init ? SGFContext() : C); |
| |
| // If we were able to directly initialize the literal we wanted, we're done. |
| if (!init) return builtinLiteral; |
| |
| // Otherwise, perform the second initialization step. |
| relabelArgument(init, builtinLiteral); |
| RValue result = emitApplyAllocatingInitializer(*this, literal, init, |
| std::move(builtinLiteral), |
| literal->getType(), C); |
| return result; |
| } |
| |
| /// Allocate an uninitialized array of a given size, returning the array |
| /// and a pointer to its uninitialized contents, which must be initialized |
| /// before the array is valid. |
| std::pair<ManagedValue, SILValue> |
| SILGenFunction::emitUninitializedArrayAllocation(Type ArrayTy, |
| SILValue Length, |
| SILLocation Loc) { |
| auto &Ctx = getASTContext(); |
| auto allocate = Ctx.getAllocateUninitializedArray(nullptr); |
| |
| // Invoke the intrinsic, which returns a tuple. |
| auto subMap = ArrayTy->getContextSubstitutionMap(SGM.M.getSwiftModule(), |
| Ctx.getArrayDecl()); |
| auto result = emitApplyOfLibraryIntrinsic(Loc, allocate, |
| subMap, |
| ManagedValue::forUnmanaged(Length), |
| SGFContext()); |
| |
| // Explode the tuple. |
| SmallVector<ManagedValue, 2> resultElts; |
| std::move(result).getAll(resultElts); |
| |
| return {resultElts[0], resultElts[1].getUnmanagedValue()}; |
| } |
| |
| /// Deallocate an uninitialized array. |
| void SILGenFunction::emitUninitializedArrayDeallocation(SILLocation loc, |
| SILValue array) { |
| auto &Ctx = getASTContext(); |
| auto deallocate = Ctx.getDeallocateUninitializedArray(nullptr); |
| |
| CanType arrayTy = array->getType().getSwiftRValueType(); |
| |
| // Invoke the intrinsic. |
| auto subMap = arrayTy->getContextSubstitutionMap(SGM.M.getSwiftModule(), |
| Ctx.getArrayDecl()); |
| emitApplyOfLibraryIntrinsic(loc, deallocate, subMap, |
| ManagedValue::forUnmanaged(array), |
| SGFContext()); |
| } |
| |
| namespace { |
| /// A cleanup that deallocates an uninitialized array. |
| class DeallocateUninitializedArray: public Cleanup { |
| SILValue Array; |
| public: |
| DeallocateUninitializedArray(SILValue array) |
| : Array(array) {} |
| |
| void emit(SILGenFunction &SGF, CleanupLocation l) override { |
| SGF.emitUninitializedArrayDeallocation(l, Array); |
| } |
| |
| void dump(SILGenFunction &SGF) const override { |
| #ifndef NDEBUG |
| llvm::errs() << "DeallocateUninitializedArray " |
| << "State:" << getState() << " " |
| << "Array:" << Array << "\n"; |
| #endif |
| } |
| }; |
| } // end anonymous namespace |
| |
| CleanupHandle |
| SILGenFunction::enterDeallocateUninitializedArrayCleanup(SILValue array) { |
| Cleanups.pushCleanup<DeallocateUninitializedArray>(array); |
| return Cleanups.getTopCleanup(); |
| } |
| |
| static Callee getBaseAccessorFunctionRef(SILGenFunction &SGF, |
| SILLocation loc, |
| SILDeclRef constant, |
| ArgumentSource &selfValue, |
| bool isSuper, |
| bool isDirectUse, |
| SubstitutionList subs) { |
| auto *decl = cast<AbstractFunctionDecl>(constant.getDecl()); |
| |
| // The accessor might be a local function that does not capture any |
| // generic parameters, in which case we don't want to pass in any |
| // substitutions. |
| auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(decl); |
| if (decl->getDeclContext()->isLocalContext() && |
| !captureInfo.hasGenericParamCaptures()) { |
| subs = SubstitutionList(); |
| } |
| |
| // If this is a method in a protocol, generate it as a protocol call. |
| if (isa<ProtocolDecl>(decl->getDeclContext())) { |
| assert(!isDirectUse && "direct use of protocol accessor?"); |
| assert(!isSuper && "super call to protocol method?"); |
| |
| return Callee::forWitnessMethod( |
| SGF, selfValue.getSubstRValueType(), |
| constant, subs, loc); |
| } |
| |
| bool isClassDispatch = false; |
| if (!isDirectUse) { |
| switch (getMethodDispatch(decl)) { |
| case MethodDispatch::Class: |
| isClassDispatch = true; |
| break; |
| case MethodDispatch::Static: |
| isClassDispatch = false; |
| break; |
| } |
| } |
| |
| // Dispatch in a struct/enum or to a final method is always direct. |
| if (!isClassDispatch) |
| return Callee::forDirect(SGF, constant, subs, loc); |
| |
| // Otherwise, if we have a non-final class dispatch to a normal method, |
| // perform a dynamic dispatch. |
| if (!isSuper) |
| return Callee::forClassMethod(SGF, constant, subs, loc); |
| |
| // If this is a "super." dispatch, we do a dynamic dispatch for objc methods |
| // or non-final native Swift methods. |
| if (!canUseStaticDispatch(SGF, constant)) |
| return Callee::forSuperMethod(SGF, constant, subs, loc); |
| |
| return Callee::forDirect(SGF, constant, subs, loc); |
| } |
| |
| static Callee |
| emitSpecializedAccessorFunctionRef(SILGenFunction &SGF, |
| SILLocation loc, |
| SILDeclRef constant, |
| SubstitutionList substitutions, |
| ArgumentSource &selfValue, |
| bool isSuper, |
| bool isDirectUse) |
| { |
| // Get the accessor function. The type will be a polymorphic function if |
| // the Self type is generic. |
| Callee callee = getBaseAccessorFunctionRef(SGF, loc, constant, selfValue, |
| isSuper, isDirectUse, |
| substitutions); |
| |
| // Collect captures if the accessor has them. |
| auto accessorFn = cast<AbstractFunctionDecl>(constant.getDecl()); |
| if (SGF.SGM.M.Types.hasLoweredLocalCaptures(accessorFn)) { |
| assert(!selfValue && "local property has self param?!"); |
| SmallVector<ManagedValue, 4> captures; |
| SGF.emitCaptures(loc, accessorFn, CaptureEmission::ImmediateApplication, |
| captures); |
| callee.setCaptures(std::move(captures)); |
| } |
| |
| return callee; |
| } |
| |
| namespace { |
| |
| /// A builder class that creates the base argument for accessors. |
| /// |
| /// *NOTE* All cleanups created inside of this builder on base arguments must be |
| /// formal access to ensure that we do not extend the lifetime of a guaranteed |
| /// base after the accessor is evaluated. |
| struct AccessorBaseArgPreparer final { |
| SILGenFunction &SGF; |
| SILLocation loc; |
| ManagedValue base; |
| CanType baseFormalType; |
| SILDeclRef accessor; |
| SILParameterInfo selfParam; |
| SILType baseLoweredType; |
| |
| AccessorBaseArgPreparer(SILGenFunction &SGF, SILLocation loc, |
| ManagedValue base, CanType baseFormalType, |
| SILDeclRef accessor); |
| ArgumentSource prepare(); |
| |
| private: |
| /// Prepare our base if we have an address base. |
| ArgumentSource prepareAccessorAddressBaseArg(); |
| /// Prepare our base if we have an object base. |
| ArgumentSource prepareAccessorObjectBaseArg(); |
| |
| /// Returns true if given an address base, we need to load the underlying |
| /// address. Asserts if baseLoweredType is not an address. |
| bool shouldLoadBaseAddress() const; |
| }; |
| |
| } // end anonymous namespace |
| |
| bool AccessorBaseArgPreparer::shouldLoadBaseAddress() const { |
| assert(baseLoweredType.isAddress() && |
| "Should only call this helper method if the base is an address"); |
| switch (selfParam.getConvention()) { |
| // If the accessor wants the value 'inout', always pass the |
| // address we were given. This is semantically required. |
| case ParameterConvention::Indirect_Inout: |
| case ParameterConvention::Indirect_InoutAliasable: |
| return false; |
| |
| // If the accessor wants the value 'in', we have to copy if the |
| // base isn't a temporary. We aren't allowed to pass aliased |
| // memory to 'in', and we have pass at +1. |
| case ParameterConvention::Indirect_In: |
| case ParameterConvention::Indirect_In_Guaranteed: |
| // TODO: We shouldn't be able to get an lvalue here, but the AST |
| // sometimes produces an inout base for non-mutating accessors. |
| // rdar://problem/19782170 |
| // assert(!base.isLValue()); |
| return base.isLValue() || base.isPlusZeroRValueOrTrivial(); |
| |
| // If the accessor wants the value directly, we definitely have to |
| // load. |
| case ParameterConvention::Direct_Owned: |
| case ParameterConvention::Direct_Unowned: |
| case ParameterConvention::Direct_Guaranteed: |
| return true; |
| |
| // Should not show up here. |
| case ParameterConvention::Indirect_In_Constant: |
| break; |
| } |
| llvm_unreachable("bad convention"); |
| } |
| |
| ArgumentSource AccessorBaseArgPreparer::prepareAccessorAddressBaseArg() { |
| // If the base is currently an address, we may have to copy it. |
| if (shouldLoadBaseAddress()) { |
| if (selfParam.isConsumed() || |
| base.getType().isAddressOnly(SGF.getModule())) { |
| // The load can only be a take if the base is a +1 rvalue. |
| auto shouldTake = IsTake_t(base.hasCleanup()); |
| |
| base = SGF.emitFormalAccessLoad(loc, base.forward(SGF), |
| SGF.getTypeLowering(baseLoweredType), |
| SGFContext(), shouldTake); |
| return ArgumentSource(loc, RValue(SGF, loc, baseFormalType, base)); |
| } |
| |
| // If we do not have a consumed base and need to perform a load, perform a |
| // formal access load borrow. |
| base = SGF.B.createFormalAccessLoadBorrow(loc, base); |
| return ArgumentSource(loc, RValue(SGF, loc, baseFormalType, base)); |
| } |
| |
| // Handle inout bases specially here. |
| if (selfParam.isIndirectInOut()) { |
| // It sometimes happens that we get r-value bases here, e.g. when calling a |
| // mutating setter on a materialized temporary. Just don't claim the value. |
| if (!base.isLValue()) { |
| base = ManagedValue::forLValue(base.getValue()); |
| } |
| |
| // FIXME: this assumes that there's never meaningful reabstraction of self |
| // arguments. |
| return ArgumentSource( |
| loc, LValue::forAddress(base, None, AbstractionPattern(baseFormalType), |
| baseFormalType)); |
| } |
| |
| // Otherwise, we have a value that we can forward without any additional |
| // handling. |
| return ArgumentSource(loc, RValue(SGF, loc, baseFormalType, base)); |
| } |
| |
| ArgumentSource AccessorBaseArgPreparer::prepareAccessorObjectBaseArg() { |
| // If the base is currently scalar, we may have to drop it in |
| // memory or copy it. |
| assert(!base.isLValue()); |
| |
| // We need to produce the value at +1 if it's going to be consumed. |
| if (selfParam.isConsumed() && !base.hasCleanup()) { |
| base = base.formalAccessCopyUnmanaged(SGF, loc); |
| } |
| |
| // If the parameter is indirect, we need to drop the value into |
| // temporary memory. |
| if (SGF.silConv.isSILIndirect(selfParam)) { |
| // It's a really bad idea to materialize when we're about to |
| // pass a value to an inout argument, because it's a really easy |
| // way to silently drop modifications (e.g. from a mutating |
| // getter in a writeback pair). Our caller should always take |
| // responsibility for that decision (by doing the materialization |
| // itself). |
| assert(!selfParam.isIndirectMutating() && |
| "passing unmaterialized r-value as inout argument"); |
| |
| base = base.materialize(SGF, loc); |
| } |
| |
| return ArgumentSource(loc, RValue(SGF, loc, baseFormalType, base)); |
| } |
| |
| AccessorBaseArgPreparer::AccessorBaseArgPreparer(SILGenFunction &SGF, |
| SILLocation loc, |
| ManagedValue base, |
| CanType baseFormalType, |
| SILDeclRef accessor) |
| : SGF(SGF), loc(loc), base(base), baseFormalType(baseFormalType), |
| accessor(accessor), |
| selfParam(SGF.SGM.Types.getConstantSelfParameter(accessor)), |
| baseLoweredType(base.getType()) { |
| assert(!base.isInContext()); |
| assert(!base.isLValue() || !base.hasCleanup()); |
| } |
| |
| ArgumentSource AccessorBaseArgPreparer::prepare() { |
| // If the base is a boxed existential, we will open it later. |
| if (baseLoweredType.getPreferredExistentialRepresentation(SGF.SGM.M) == |
| ExistentialRepresentation::Boxed) { |
| assert(!baseLoweredType.isAddress() && |
| "boxed existential should not be an address"); |
| return ArgumentSource(loc, RValue(SGF, loc, baseFormalType, base)); |
| } |
| |
| if (baseLoweredType.isAddress()) |
| return prepareAccessorAddressBaseArg(); |
| |
| // At this point, we know we have an object. |
| assert(baseLoweredType.isObject()); |
| return prepareAccessorObjectBaseArg(); |
| } |
| |
| ArgumentSource SILGenFunction::prepareAccessorBaseArg(SILLocation loc, |
| ManagedValue base, |
| CanType baseFormalType, |
| SILDeclRef accessor) { |
| if (!base) |
| return ArgumentSource(); |
| |
| AccessorBaseArgPreparer Preparer(*this, loc, base, baseFormalType, accessor); |
| return Preparer.prepare(); |
| } |
| |
| SILDeclRef SILGenModule::getGetterDeclRef(AbstractStorageDecl *storage) { |
| auto *getter = storage->getGetter(); |
| return SILDeclRef(getter, SILDeclRef::Kind::Func) |
| .asForeign(requiresForeignEntryPoint(getter)); |
| } |
| |
| /// Emit a call to a getter. |
| RValue SILGenFunction:: |
| emitGetAccessor(SILLocation loc, SILDeclRef get, |
| SubstitutionList substitutions, |
| ArgumentSource &&selfValue, |
| bool isSuper, bool isDirectUse, |
| RValue &&subscripts, SGFContext c) { |
| // Scope any further writeback just within this operation. |
| FormalEvaluationScope writebackScope(*this); |
| |
| Callee getter = emitSpecializedAccessorFunctionRef(*this, loc, get, |
| substitutions, selfValue, |
| isSuper, isDirectUse); |
| bool hasSelf = (bool)selfValue; |
| CanAnyFunctionType accessType = getter.getSubstFormalType(); |
| |
| CallEmission emission(*this, std::move(getter), std::move(writebackScope)); |
| // Self -> |
| if (hasSelf) { |
| emission.addCallSite(loc, std::move(selfValue), accessType); |
| accessType = cast<AnyFunctionType>(accessType.getResult()); |
| } |
| // Index or () if none. |
| if (subscripts.isNull()) |
| subscripts = emitEmptyTupleRValue(loc, SGFContext()); |
| |
| emission.addCallSite(loc, ArgumentSource(loc, std::move(subscripts)), |
| accessType); |
| |
| // T |
| return emission.apply(c); |
| } |
| |
| SILDeclRef SILGenModule::getSetterDeclRef(AbstractStorageDecl *storage) { |
| auto *setter = storage->getSetter(); |
| return SILDeclRef(setter, SILDeclRef::Kind::Func) |
| .asForeign(requiresForeignEntryPoint(setter)); |
| } |
| |
| void SILGenFunction::emitSetAccessor(SILLocation loc, SILDeclRef set, |
| SubstitutionList substitutions, |
| ArgumentSource &&selfValue, |
| bool isSuper, bool isDirectUse, |
| RValue &&subscripts, |
| ArgumentSource &&setValue) { |
| // Scope any further writeback just within this operation. |
| FormalEvaluationScope writebackScope(*this); |
| |
| Callee setter = emitSpecializedAccessorFunctionRef(*this, loc, set, |
| substitutions, selfValue, |
| isSuper, isDirectUse); |
| bool hasSelf = (bool)selfValue; |
| CanAnyFunctionType accessType = setter.getSubstFormalType(); |
| |
| CallEmission emission(*this, std::move(setter), std::move(writebackScope)); |
| // Self -> |
| if (hasSelf) { |
| emission.addCallSite(loc, std::move(selfValue), accessType); |
| accessType = cast<AnyFunctionType>(accessType.getResult()); |
| } |
| |
| // (value) or (value, indices) |
| if (!subscripts.isNull()) { |
| // If we have a value and index list, create a new rvalue to represent the |
| // both of them together. |
| auto inputTupleType = cast<TupleType>(accessType.getInput()); |
| |
| SmallVector<ArgumentSource, 4> eltSources; |
| |
| // The value comes first. |
| eltSources.push_back(std::move(setValue)); |
| |
| // The indices come after. Whether they are expanded or not depends on |
| // whether they were written as separate parameters, which should be |
| // reflected in the params list. |
| // TODO: we should really take an array of RValues. |
| if (accessType->getNumParams() != 2) { |
| auto subscriptsTupleType = cast<TupleType>(subscripts.getType()); |
| assert(inputTupleType->getNumElements() |
| == 1 + subscriptsTupleType->getNumElements()); |
| SmallVector<RValue, 8> eltRVs; |
| std::move(subscripts).extractElements(eltRVs); |
| for (auto &elt : eltRVs) |
| eltSources.emplace_back(loc, std::move(elt)); |
| } else { |
| subscripts.rewriteType(inputTupleType.getElementType(1)); |
| eltSources.emplace_back(loc, std::move(subscripts)); |
| } |
| |
| setValue = ArgumentSource(loc, inputTupleType, eltSources); |
| } else { |
| setValue.rewriteType(accessType.getInput()); |
| } |
| emission.addCallSite(loc, std::move(setValue), accessType); |
| // () |
| emission.apply(); |
| } |
| |
| SILDeclRef |
| SILGenModule::getMaterializeForSetDeclRef(AbstractStorageDecl *storage) { |
| return SILDeclRef(storage->getMaterializeForSetFunc(), |
| SILDeclRef::Kind::Func); |
| } |
| |
| MaterializedLValue SILGenFunction:: |
| emitMaterializeForSetAccessor(SILLocation loc, SILDeclRef materializeForSet, |
| SubstitutionList substitutions, |
| ArgumentSource &&selfValue, |
| bool isSuper, bool isDirectUse, |
| RValue &&subscripts, SILValue buffer, |
| SILValue callbackStorage) { |
| // Scope any further writeback just within this operation. |
| FormalEvaluationScope writebackScope(*this); |
| |
| Callee callee = emitSpecializedAccessorFunctionRef(*this, loc, |
| materializeForSet, |
| substitutions, selfValue, |
| isSuper, isDirectUse); |
| bool hasSelf = (bool)selfValue; |
| auto accessType = callee.getSubstFormalType(); |
| |
| CallEmission emission(*this, std::move(callee), std::move(writebackScope)); |
| // Self -> |
| if (hasSelf) { |
| emission.addCallSite(loc, std::move(selfValue), accessType); |
| accessType = cast<FunctionType>(accessType.getResult()); |
| } |
| |
| // (buffer, callbackStorage) or (buffer, callbackStorage, indices) -> |
| // Note that this "RValue" stores a mixed LValue/RValue tuple. |
| RValue args = [&] () -> RValue { |
| SmallVector<ManagedValue, 4> elts; |
| |
| auto bufferPtr = |
| B.createAddressToPointer(loc, buffer, |
| SILType::getRawPointerType(getASTContext())); |
| elts.push_back(ManagedValue::forUnmanaged(bufferPtr)); |
| |
| elts.push_back(ManagedValue::forLValue(callbackStorage)); |
| |
| if (!subscripts.isNull()) { |
| std::move(subscripts).getAll(elts); |
| } |
| return RValue(*this, elts, accessType.getInput()); |
| }(); |
| emission.addCallSite(loc, ArgumentSource(loc, std::move(args)), accessType); |
| // (buffer, optionalCallback) |
| SmallVector<ManagedValue, 2> results; |
| emission.apply().getAll(results); |
| |
| // Project out the materialized address. The address directly returned by |
| // materialize for set is strictly typed, whether it is the local buffer or |
| // stored property. |
| SILValue address = results[0].getUnmanagedValue(); |
| address = B.createPointerToAddress(loc, address, buffer->getType(), |
| /*isStrict*/ true, |
| /*isInvariant*/ false); |
| |
| // Project out the optional callback. |
| SILValue optionalCallback = results[1].getUnmanagedValue(); |
| |
| auto origAccessType = SGM.Types.getConstantInfo(materializeForSet).FormalType; |
| |
| auto origSelfType = origAccessType->getInput() |
| ->getInOutObjectType() |
| ->getCanonicalType(); |
| |
| CanGenericSignature genericSig; |
| if (auto genericFnType = dyn_cast<GenericFunctionType>(origAccessType)) |
| genericSig = genericFnType.getGenericSignature(); |
| |
| return MaterializedLValue(ManagedValue::forUnmanaged(address), |
| origSelfType, genericSig, |
| optionalCallback, callbackStorage); |
| } |
| |
| SILDeclRef SILGenModule::getAddressorDeclRef(AbstractStorageDecl *storage, |
| AccessKind accessKind) { |
| FuncDecl *addressorFunc = storage->getAddressorForAccess(accessKind); |
| return SILDeclRef(addressorFunc, SILDeclRef::Kind::Func); |
| } |
| |
| /// Emit a call to an addressor. |
| /// |
| /// The first return value is the address, which will always be an |
| /// l-value managed value. The second return value is the owner |
| /// pointer, if applicable. |
| std::pair<ManagedValue, ManagedValue> SILGenFunction:: |
| emitAddressorAccessor(SILLocation loc, SILDeclRef addressor, |
| SubstitutionList substitutions, |
| ArgumentSource &&selfValue, |
| bool isSuper, bool isDirectUse, |
| RValue &&subscripts, SILType addressType) { |
| // Scope any further writeback just within this operation. |
| FormalEvaluationScope writebackScope(*this); |
| |
| Callee callee = |
| emitSpecializedAccessorFunctionRef(*this, loc, addressor, |
| substitutions, selfValue, |
| isSuper, isDirectUse); |
| bool hasSelf = (bool)selfValue; |
| CanAnyFunctionType accessType = callee.getSubstFormalType(); |
| |
| CallEmission emission(*this, std::move(callee), std::move(writebackScope)); |
| // Self -> |
| if (hasSelf) { |
| emission.addCallSite(loc, std::move(selfValue), accessType); |
| accessType = cast<AnyFunctionType>(accessType.getResult()); |
| } |
| // Index or () if none. |
| if (subscripts.isNull()) |
| subscripts = emitEmptyTupleRValue(loc, SGFContext()); |
| |
| emission.addCallSite(loc, ArgumentSource(loc, std::move(subscripts)), |
| accessType); |
| |
| // Unsafe{Mutable}Pointer<T> or |
| // (Unsafe{Mutable}Pointer<T>, Builtin.UnknownPointer) or |
| // (Unsafe{Mutable}Pointer<T>, Builtin.NativePointer) or |
| // (Unsafe{Mutable}Pointer<T>, Builtin.NativePointer?) or |
| SmallVector<ManagedValue, 2> results; |
| emission.apply().getAll(results); |
| |
| SILValue pointer; |
| ManagedValue owner; |
| switch (cast<AccessorDecl>(addressor.getDecl())->getAddressorKind()) { |
| case AddressorKind::NotAddressor: |
| llvm_unreachable("not an addressor!"); |
| case AddressorKind::Unsafe: |
| assert(results.size() == 1); |
| pointer = results[0].getUnmanagedValue(); |
| owner = ManagedValue(); |
| break; |
| case AddressorKind::Owning: |
| case AddressorKind::NativeOwning: |
| case AddressorKind::NativePinning: |
| assert(results.size() == 2); |
| pointer = results[0].getUnmanagedValue(); |
| owner = results[1]; |
| break; |
| } |
| |
| // Drill down to the raw pointer using intrinsic knowledge of those types. |
| auto pointerType = |
| pointer->getType().castTo<BoundGenericStructType>()->getDecl(); |
| auto props = pointerType->getStoredProperties(); |
| assert(props.begin() != props.end()); |
| assert(std::next(props.begin()) == props.end()); |
| VarDecl *rawPointerField = *props.begin(); |
| pointer = B.createStructExtract(loc, pointer, rawPointerField, |
| SILType::getRawPointerType(getASTContext())); |
| |
| // Convert to the appropriate address type and return. |
| SILValue address = B.createPointerToAddress(loc, pointer, addressType, |
| /*isStrict*/ true, |
| /*isInvariant*/ false); |
| |
| // Mark dependence as necessary. |
| switch (cast<AccessorDecl>(addressor.getDecl())->getAddressorKind()) { |
| case AddressorKind::NotAddressor: |
| llvm_unreachable("not an addressor!"); |
| case AddressorKind::Unsafe: |
| // TODO: we should probably mark dependence on the base. |
| break; |
| case AddressorKind::Owning: |
| case AddressorKind::NativeOwning: |
| case AddressorKind::NativePinning: |
| address = B.createMarkDependence(loc, address, owner.getValue()); |
| break; |
| } |
| |
| return { ManagedValue::forLValue(address), owner }; |
| } |
| |
| |
| // Create a partial application of a dynamic method, applying bridging thunks |
| // if necessary. |
| static ManagedValue emitDynamicPartialApply(SILGenFunction &SGF, |
| SILLocation loc, |
| SILValue method, |
| SILValue self, |
| CanAnyFunctionType foreignFormalType, |
| CanAnyFunctionType nativeFormalType) { |
| auto calleeConvention = ParameterConvention::Direct_Guaranteed; |
| |
| auto partialApplyTy = |
| SILBuilder::getPartialApplyResultType(method->getType(), |
| /*argCount*/ 1, SGF.SGM.M, |
| /*subs*/ {}, calleeConvention); |
| |
| // Retain 'self' because the partial apply will take ownership. |
| // We can't simply forward 'self' because the partial apply is conditional. |
| if (!self->getType().isAddress()) |
| self = SGF.B.emitCopyValueOperation(loc, self); |
| |
| SILValue resultValue = |
| SGF.B.createPartialApply(loc, method, method->getType(), {}, |
| self, partialApplyTy); |
| ManagedValue result = SGF.emitManagedRValueWithCleanup(resultValue); |
| |
| // If necessary, thunk to the native ownership conventions and bridged types. |
| auto nativeTy = |
| SGF.getLoweredLoadableType(nativeFormalType).castTo<SILFunctionType>(); |
| |
| if (nativeTy != partialApplyTy.getSwiftRValueType()) { |
| result = SGF.emitBlockToFunc(loc, result, foreignFormalType, |
| nativeFormalType, nativeTy); |
| } |
| |
| return result; |
| } |
| |
| RValue SILGenFunction::emitDynamicMemberRefExpr(DynamicMemberRefExpr *e, |
| SGFContext c) { |
| // Emit the operand. |
| ManagedValue base = emitRValueAsSingleValue(e->getBase()); |
| |
| SILValue operand = base.getValue(); |
| if (!e->getMember().getDecl()->isInstanceMember()) { |
| auto metatype = operand->getType().castTo<MetatypeType>(); |
| assert(metatype->getRepresentation() == MetatypeRepresentation::Thick); |
| metatype = CanMetatypeType::get(metatype.getInstanceType(), |
| MetatypeRepresentation::ObjC); |
| operand = B.createThickToObjCMetatype(e, operand, |
| SILType::getPrimitiveObjectType(metatype)); |
| } |
| |
| // Create the continuation block. |
| SILBasicBlock *contBB = createBasicBlock(); |
| |
| // Create the no-member block. |
| SILBasicBlock *noMemberBB = createBasicBlock(); |
| |
| // Create the has-member block. |
| SILBasicBlock *hasMemberBB = createBasicBlock(); |
| |
| // The continuation block |
| auto memberMethodTy = e->getType()->getOptionalObjectType(); |
| |
| const TypeLowering &optTL = getTypeLowering(e->getType()); |
| auto loweredOptTy = optTL.getLoweredType(); |
| |
| SILValue optTemp = emitTemporaryAllocation(e, loweredOptTy); |
| |
| // Create the branch. |
| FuncDecl *memberFunc; |
| if (auto *VD = dyn_cast<VarDecl>(e->getMember().getDecl())) { |
| memberFunc = VD->getGetter(); |
| memberMethodTy = FunctionType::get(getASTContext().TheEmptyTupleType, |
| memberMethodTy); |
| } else |
| memberFunc = cast<FuncDecl>(e->getMember().getDecl()); |
| auto member = SILDeclRef(memberFunc, SILDeclRef::Kind::Func) |
| .asForeign(); |
| B.createDynamicMethodBranch(e, operand, member, hasMemberBB, noMemberBB); |
| |
| // Create the has-member branch. |
| { |
| B.emitBlock(hasMemberBB); |
| |
| FullExpr hasMemberScope(Cleanups, CleanupLocation(e)); |
| |
| // The argument to the has-member block is the uncurried method. |
| auto valueTy = e->getType()->getCanonicalType().getOptionalObjectType(); |
| CanFunctionType methodTy; |
| |
| // For a computed variable, we want the getter. |
| if (isa<VarDecl>(e->getMember().getDecl())) { |
| methodTy = CanFunctionType::get(TupleType::getEmpty(getASTContext()), |
| valueTy); |
| } else { |
| methodTy = cast<FunctionType>(valueTy); |
| } |
| |
| // Build a partially-applied foreign formal type. |
| // TODO: instead of building this and then potentially converting, we |
| // should just build a single thunk. |
| auto foreignMethodTy = |
| getPartialApplyOfDynamicMethodFormalType(SGM, member, e->getMember()); |
| |
| auto memberFnTy = CanFunctionType::get( |
| operand->getType().getSwiftRValueType(), |
| memberMethodTy->getCanonicalType()); |
| |
| auto loweredMethodTy = getDynamicMethodLoweredType(SGM.M, member, |
| memberFnTy); |
| SILValue memberArg = hasMemberBB->createPHIArgument( |
| loweredMethodTy, ValueOwnershipKind::Owned); |
| |
| // Create the result value. |
| Scope applyScope(Cleanups, CleanupLocation(e)); |
| ManagedValue result = |
| emitDynamicPartialApply(*this, e, memberArg, operand, |
| foreignMethodTy, methodTy); |
| |
| RValue resultRV; |
| if (isa<VarDecl>(e->getMember().getDecl())) { |
| resultRV = emitMonomorphicApply(e, result, {}, |
| foreignMethodTy.getResult(), valueTy, |
| ApplyOptions::DoesNotThrow, |
| None, None); |
| } else { |
| resultRV = RValue(*this, e, valueTy, result); |
| } |
| |
| // Package up the result in an optional. |
| emitInjectOptionalValueInto(e, {e, std::move(resultRV)}, optTemp, optTL); |
| |
| applyScope.pop(); |
| // Branch to the continuation block. |
| B.createBranch(e, contBB); |
| } |
| |
| // Create the no-member branch. |
| { |
| B.emitBlock(noMemberBB); |
| |
| emitInjectOptionalNothingInto(e, optTemp, optTL); |
| |
| // Branch to the continuation block. |
| B.createBranch(e, contBB); |
| } |
| |
| // Emit the continuation block. |
| B.emitBlock(contBB); |
| |
| // Package up the result. |
| auto optResult = optTemp; |
| if (optTL.isLoadable()) |
| optResult = optTL.emitLoad(B, e, optResult, LoadOwnershipQualifier::Take); |
| return RValue(*this, e, emitManagedRValueWithCleanup(optResult, optTL)); |
| } |
| |
| RValue SILGenFunction::emitDynamicSubscriptExpr(DynamicSubscriptExpr *e, |
| SGFContext c) { |
| // Emit the base operand. |
| ManagedValue managedBase = emitRValueAsSingleValue(e->getBase()); |
| |
| SILValue base = managedBase.getValue(); |
| |
| // Emit the index. |
| RValue index = emitRValue(e->getIndex()); |
| |
| // Create the continuation block. |
| SILBasicBlock *contBB = createBasicBlock(); |
| |
| // Create the no-member block. |
| SILBasicBlock *noMemberBB = createBasicBlock(); |
| |
| // Create the has-member block. |
| SILBasicBlock *hasMemberBB = createBasicBlock(); |
| |
| const TypeLowering &optTL = getTypeLowering(e->getType()); |
| auto loweredOptTy = optTL.getLoweredType(); |
| SILValue optTemp = emitTemporaryAllocation(e, loweredOptTy); |
| |
| // Create the branch. |
| auto subscriptDecl = cast<SubscriptDecl>(e->getMember().getDecl()); |
| auto member = SILDeclRef(subscriptDecl->getGetter(), |
| SILDeclRef::Kind::Func) |
| .asForeign(); |
| B.createDynamicMethodBranch(e, base, member, hasMemberBB, noMemberBB); |
| |
| // Create the has-member branch. |
| { |
| B.emitBlock(hasMemberBB); |
| |
| FullExpr hasMemberScope(Cleanups, CleanupLocation(e)); |
| |
| // The argument to the has-member block is the uncurried method. |
| // Build the substituted getter type from the AST nodes. |
| auto valueTy = e->getType()->getCanonicalType().getOptionalObjectType(); |
| auto indexTy = e->getIndex()->getType()->getCanonicalType(); |
| auto methodTy = CanFunctionType::get(indexTy, |
| valueTy); |
| auto foreignMethodTy = |
| getPartialApplyOfDynamicMethodFormalType(SGM, member, e->getMember()); |
| |
| auto functionTy = CanFunctionType::get(base->getType().getSwiftRValueType(), |
| methodTy); |
| auto loweredMethodTy = getDynamicMethodLoweredType(SGM.M, member, |
| functionTy); |
| SILValue memberArg = hasMemberBB->createPHIArgument( |
| loweredMethodTy, ValueOwnershipKind::Owned); |
| // Emit the application of 'self'. |
| Scope applyScope(Cleanups, CleanupLocation(e)); |
| ManagedValue result = emitDynamicPartialApply(*this, e, memberArg, base, |
| foreignMethodTy, methodTy); |
| // Emit the index. |
| llvm::SmallVector<ManagedValue, 2> indexArgs; |
| std::move(index).getAll(indexArgs); |
| |
| auto resultRV = emitMonomorphicApply(e, result, indexArgs, |
| foreignMethodTy.getResult(), valueTy, |
| ApplyOptions::DoesNotThrow, |
| None, None); |
| |
| // Package up the result in an optional. |
| emitInjectOptionalValueInto(e, {e, std::move(resultRV)}, optTemp, optTL); |
| |
| applyScope.pop(); |
| // Branch to the continuation block. |
| B.createBranch(e, contBB); |
| } |
| |
| // Create the no-member branch. |
| { |
| B.emitBlock(noMemberBB); |
| |
| emitInjectOptionalNothingInto(e, optTemp, optTL); |
| |
| // Branch to the continuation block. |
| B.createBranch(e, contBB); |
| } |
| |
| // Emit the continuation block. |
| B.emitBlock(contBB); |
| |
| // Package up the result. |
| auto optResult = optTemp; |
| if (optTL.isLoadable()) |
| optResult = optTL.emitLoad(B, e, optResult, LoadOwnershipQualifier::Take); |
| return RValue(*this, e, emitManagedRValueWithCleanup(optResult, optTL)); |
| } |
| |
| ManagedValue ArgumentScope::popPreservingValue(ManagedValue mv) { |
| formalEvalScope.pop(); |
| return normalScope.popPreservingValue(mv); |
| } |
| |
| RValue ArgumentScope::popPreservingValue(RValue &&rv) { |
| formalEvalScope.pop(); |
| return normalScope.popPreservingValue(std::move(rv)); |
| } |