| //===- SILFunctionConventions.h - Defines SIL func. conventions -*- C++ -*-===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// |
| /// This file defines the SILModuleConventions and SILFunctionConventions |
| /// classes. These interfaces are used to determine when SIL can represent |
| /// values of a given lowered type by value and when they must be represented by |
| /// address. This is influenced by a SILModule-wide "lowered address" convention, |
| /// which reflects whether the current SIL stage requires lowered addresses. |
| /// |
| /// The primary purpose of this API is mapping the formal SIL parameter and |
| /// result conventions onto the SIL argument types. The "formal" conventions are |
| /// immutably associated with a SILFunctionType--a SIL function's type |
| /// information never changes. The SIL conventions determine how those formal |
| /// conventions will be represented in the body of SIL functions and at call |
| /// sites. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_SIL_FUNCTIONCONVENTIONS_H |
| #define SWIFT_SIL_FUNCTIONCONVENTIONS_H |
| |
| #include "swift/AST/Types.h" |
| #include "swift/SIL/SILArgumentConvention.h" |
| #include "swift/SIL/SILType.h" |
| #include "llvm/Support/ErrorHandling.h" |
| |
| namespace swift { |
| |
| template<bool _, template<typename...> class T, typename...Args> |
| struct delay_template_expansion { |
| using type = T<Args...>; |
| }; |
| |
| /// Transient wrapper for SILParameterInfo and SILResultInfo conventions. This |
| /// abstraction helps handle the transition from canonical SIL conventions to |
| /// lowered SIL conventions. |
| class SILModuleConventions { |
| friend SILParameterInfo; |
| friend SILResultInfo; |
| friend SILFunctionConventions; |
| |
| static bool isIndirectSILParam(SILParameterInfo param, |
| bool loweredAddresses); |
| |
| static bool isIndirectSILYield(SILYieldInfo yield, |
| bool loweredAddresses); |
| |
| static bool isIndirectSILResult(SILResultInfo result, |
| bool loweredAddresses); |
| |
| static SILType getSILParamInterfaceType( |
| SILParameterInfo yield, |
| bool loweredAddresses); |
| |
| static SILType getSILYieldInterfaceType( |
| SILYieldInfo yield, |
| bool loweredAddresses); |
| |
| static SILType getSILResultInterfaceType( |
| SILResultInfo param, |
| bool loweredAddresses); |
| |
| public: |
| static bool isPassedIndirectlyInSIL(SILType type, SILModule &M); |
| |
| static bool isReturnedIndirectlyInSIL(SILType type, SILModule &M); |
| |
| static SILModuleConventions getLoweredAddressConventions(SILModule &M) { |
| return SILModuleConventions(M, true); |
| } |
| |
| private: |
| SILModule *M; |
| bool loweredAddresses; |
| |
| SILModuleConventions(SILModule &M, bool loweredAddresses) |
| : M(&M), loweredAddresses(loweredAddresses) |
| {} |
| |
| public: |
| SILModuleConventions(SILModule &M); |
| |
| SILFunctionConventions getFunctionConventions(CanSILFunctionType funcTy); |
| |
| SILModule &getModule() const { return *M; } |
| |
| bool useLoweredAddresses() const { return loweredAddresses; } |
| |
| bool isSILIndirect(SILParameterInfo param) const { |
| return isIndirectSILParam(param, loweredAddresses); |
| } |
| |
| bool isSILIndirect(SILYieldInfo yield) const { |
| return isIndirectSILYield(yield, loweredAddresses); |
| } |
| |
| bool isSILIndirect(SILResultInfo result) const { |
| return isIndirectSILResult(result, loweredAddresses); |
| } |
| |
| SILType getSILType(SILParameterInfo param, CanSILFunctionType funcTy, |
| TypeExpansionContext context) const { |
| auto interfaceTy = getSILParamInterfaceType(param, loweredAddresses); |
| // TODO: Always require a function type |
| if (funcTy) |
| return funcTy->substInterfaceType(*M, interfaceTy, context); |
| return interfaceTy; |
| } |
| |
| SILType getSILType(SILYieldInfo yield, CanSILFunctionType funcTy, |
| TypeExpansionContext context) const { |
| auto interfaceTy = getSILYieldInterfaceType(yield, loweredAddresses); |
| // TODO: Always require a function type |
| if (funcTy) |
| return funcTy->substInterfaceType(*M, interfaceTy, context); |
| return interfaceTy; |
| } |
| |
| SILType getSILType(SILResultInfo result, CanSILFunctionType funcTy, |
| TypeExpansionContext context) const { |
| auto interfaceTy = getSILResultInterfaceType(result, loweredAddresses); |
| // TODO: Always require a function type |
| if (funcTy) |
| return funcTy->substInterfaceType(*M, interfaceTy, context); |
| return interfaceTy; |
| } |
| }; |
| |
| /// Transient wrapper for SIL-level argument conventions. This abstraction helps |
| /// handle the transition from canonical SIL conventions to lowered SIL |
| /// conventions. |
| class SILFunctionConventions { |
| public: |
| SILModuleConventions silConv; |
| CanSILFunctionType funcTy; |
| |
| SILFunctionConventions(CanSILFunctionType funcTy, SILModule &M) |
| : silConv(M), funcTy(funcTy) {} |
| |
| SILFunctionConventions(CanSILFunctionType funcTy, |
| SILModuleConventions silConv) |
| : silConv(silConv), funcTy(funcTy) {} |
| |
| //===--------------------------------------------------------------------===// |
| // SILModuleConventions API for convenience. |
| //===--------------------------------------------------------------------===// |
| |
| bool useLoweredAddresses() const { return silConv.useLoweredAddresses(); } |
| |
| bool isSILIndirect(SILParameterInfo param) const { |
| return silConv.isSILIndirect(param); |
| } |
| |
| bool isSILIndirect(SILYieldInfo yield) const { |
| return silConv.isSILIndirect(yield); |
| } |
| |
| bool isSILIndirect(SILResultInfo result) const { |
| return silConv.isSILIndirect(result); |
| } |
| |
| SILType getSILType(SILParameterInfo param, |
| TypeExpansionContext context) const { |
| return silConv.getSILType(param, funcTy, context); |
| } |
| |
| SILType getSILType(SILYieldInfo yield, TypeExpansionContext context) const { |
| return silConv.getSILType(yield, funcTy, context); |
| } |
| |
| SILType getSILType(SILResultInfo result, TypeExpansionContext context) const { |
| return silConv.getSILType(result, funcTy, context); |
| } |
| |
| //===--------------------------------------------------------------------===// |
| // SIL results. |
| //===--------------------------------------------------------------------===// |
| |
| /// Get the normal result type of an apply that calls this function. |
| /// This does not include indirect SIL results. |
| SILType getSILResultType(TypeExpansionContext context) { |
| if (silConv.loweredAddresses) |
| return funcTy->getDirectFormalResultsType(silConv.getModule(), context); |
| |
| return funcTy->getAllResultsSubstType(silConv.getModule(), context); |
| } |
| |
| /// Get the SIL type for the single result which may be direct or indirect. |
| SILType getSingleSILResultType(TypeExpansionContext context) { |
| return getSILType(funcTy->getSingleResult(), context); |
| } |
| |
| /// Get the error result type. |
| SILType getSILErrorType(TypeExpansionContext context) { |
| return getSILType(funcTy->getErrorResult(), context); |
| } |
| |
| /// Returns an array of result info. |
| /// Provides convenient access to the underlying SILFunctionType. |
| ArrayRef<SILResultInfo> getResults() const { |
| return funcTy->getResults(); |
| } |
| |
| /// Get the number of SIL results passed as address-typed arguments. |
| unsigned getNumIndirectSILResults() const { |
| return silConv.loweredAddresses ? funcTy->getNumIndirectFormalResults() : 0; |
| } |
| |
| /// Are any SIL results passed as address-typed arguments? |
| bool hasIndirectSILResults() const { return getNumIndirectSILResults() != 0; } |
| |
| using IndirectSILResultIter = SILFunctionType::IndirectFormalResultIter; |
| using IndirectSILResultRange = SILFunctionType::IndirectFormalResultRange; |
| |
| /// Return a range of indirect result information for results passed as |
| /// address-typed SIL arguments. |
| IndirectSILResultRange getIndirectSILResults() const { |
| if (silConv.loweredAddresses) |
| return funcTy->getIndirectFormalResults(); |
| |
| return llvm::make_filter_range( |
| llvm::make_range((const SILResultInfo *)0, (const SILResultInfo *)0), |
| SILFunctionType::IndirectFormalResultFilter()); |
| } |
| |
| struct SILResultTypeFunc; |
| |
| // Gratuitous template parameter is to delay instantiating `mapped_iterator` |
| // on the incomplete type SILParameterTypeFunc. |
| template<bool _ = false> |
| using IndirectSILResultTypeIter = typename delay_template_expansion<_, |
| llvm::mapped_iterator, IndirectSILResultIter, SILResultTypeFunc>::type; |
| template<bool _ = false> |
| using IndirectSILResultTypeRange = iterator_range<IndirectSILResultTypeIter<_>>; |
| |
| /// Return a range of SILTypes for each result passed as an address-typed SIL |
| /// argument. |
| template <bool _ = false> |
| IndirectSILResultTypeRange<_> |
| getIndirectSILResultTypes(TypeExpansionContext context) const; |
| |
| /// Get the number of SIL results directly returned by SIL value. |
| unsigned getNumDirectSILResults() const { |
| return silConv.loweredAddresses ? funcTy->getNumDirectFormalResults() |
| : funcTy->getNumResults(); |
| } |
| |
| struct DirectSILResultFilter { |
| bool loweredAddresses; |
| DirectSILResultFilter(bool loweredAddresses) |
| : loweredAddresses(loweredAddresses) {} |
| bool operator()(SILResultInfo result) const { |
| return !(loweredAddresses && result.isFormalIndirect()); |
| } |
| }; |
| using DirectSILResultIter = |
| llvm::filter_iterator<const SILResultInfo *, DirectSILResultFilter>; |
| using DirectSILResultRange = iterator_range<DirectSILResultIter>; |
| |
| /// Return a range of direct result information for results directly returned |
| /// by SIL value. |
| DirectSILResultRange getDirectSILResults() const { |
| return llvm::make_filter_range( |
| funcTy->getResults(), DirectSILResultFilter(silConv.loweredAddresses)); |
| } |
| |
| template<bool _ = false> |
| using DirectSILResultTypeIter = typename delay_template_expansion<_, |
| llvm::mapped_iterator, DirectSILResultIter, SILResultTypeFunc>::type; |
| template<bool _ = false> |
| using DirectSILResultTypeRange = iterator_range<DirectSILResultTypeIter<_>>; |
| |
| /// Return a range of SILTypes for each result directly returned |
| /// by SIL value. |
| template <bool _ = false> |
| DirectSILResultTypeRange<_> |
| getDirectSILResultTypes(TypeExpansionContext context) const; |
| |
| //===--------------------------------------------------------------------===// |
| // SIL parameters types. |
| //===--------------------------------------------------------------------===// |
| |
| /// Returns the number of function parameters, not including any formally |
| /// indirect results. Provides convenient access to the underlying |
| /// SILFunctionType. |
| unsigned getNumParameters() const { return funcTy->getNumParameters(); } |
| |
| /// Returns an array of parameter info, not including indirect |
| /// results. Provides convenient access to the underlying SILFunctionType. |
| ArrayRef<SILParameterInfo> getParameters() const { |
| return funcTy->getParameters(); |
| } |
| |
| struct SILParameterTypeFunc; |
| |
| // Gratuitous template parameter is to delay instantiating `mapped_iterator` |
| // on the incomplete type SILParameterTypeFunc. |
| template<bool _ = false> |
| using SILParameterTypeIter = typename |
| delay_template_expansion<_, llvm::mapped_iterator, |
| const SILParameterInfo *, SILParameterTypeFunc>::type; |
| |
| template<bool _ = false> |
| using SILParameterTypeRange = iterator_range<SILParameterTypeIter<_>>; |
| |
| /// Return a range of SILTypes for each function parameter, not including |
| /// indirect results. |
| template <bool _ = false> |
| SILParameterTypeRange<_> |
| getParameterSILTypes(TypeExpansionContext context) const; |
| |
| //===--------------------------------------------------------------------===// |
| // SIL yield types. |
| //===--------------------------------------------------------------------===// |
| |
| unsigned getNumYields() const { return funcTy->getNumYields(); } |
| |
| ArrayRef<SILYieldInfo> getYields() const { |
| return funcTy->getYields(); |
| } |
| |
| template<bool _ = false> |
| using SILYieldTypeIter = typename |
| delay_template_expansion<_, llvm::mapped_iterator, |
| const SILYieldInfo *, SILParameterTypeFunc>::type; |
| template<bool _ = false> |
| using SILYieldTypeRange = iterator_range<SILYieldTypeIter<_>>; |
| |
| template<bool _ = false> |
| SILYieldTypeRange<_> getYieldSILTypes(TypeExpansionContext context) const; |
| |
| SILYieldInfo getYieldInfoForOperandIndex(unsigned opIndex) const { |
| return getYields()[opIndex]; |
| } |
| |
| //===--------------------------------------------------------------------===// |
| // SILArgument API, including indirect results and parameters. |
| // |
| // The argument indices below relate to full applies in which the caller and |
| // callee indices match. Partial apply indices are shifted on the caller |
| // side. See ApplySite::getCalleeArgIndexOfFirstAppliedArg(). |
| //===--------------------------------------------------------------------===// |
| |
| unsigned getSILArgIndexOfFirstIndirectResult() const { return 0; } |
| |
| unsigned getSILArgIndexOfFirstParam() const { |
| return getNumIndirectSILResults(); |
| } |
| |
| /// Get the index into formal indirect results corresponding to the given SIL |
| /// indirect result argument index. |
| unsigned getIndirectFormalResultIndexForSILArg(unsigned argIdx) const { |
| assert(argIdx <= getNumIndirectSILResults()); |
| unsigned curArgIdx = 0; |
| unsigned formalIdx = 0; |
| for (auto formalResult : funcTy->getIndirectFormalResults()) { |
| if (isSILIndirect(formalResult)) { |
| if (curArgIdx == argIdx) |
| return formalIdx; |
| ++curArgIdx; |
| } |
| ++formalIdx; |
| } |
| llvm_unreachable("missing indirect formal result for SIL argument."); |
| } |
| |
| /// Get the total number of arguments for a full apply in SIL of |
| /// this function type. This is also the total number of SILArguments |
| /// in the entry block. |
| unsigned getNumSILArguments() const { |
| return getNumIndirectSILResults() + funcTy->getNumParameters(); |
| } |
| |
| SILParameterInfo getParamInfoForSILArg(unsigned index) const { |
| assert(index >= getNumIndirectSILResults() |
| && index <= getNumSILArguments()); |
| return funcTy->getParameters()[index - getNumIndirectSILResults()]; |
| } |
| |
| /// Return the SIL argument convention of apply/entry argument at |
| /// the given argument index. |
| SILArgumentConvention getSILArgumentConvention(unsigned index) const; |
| // See SILArgument.h. |
| |
| /// Return the SIL type of the apply/entry argument at the given index. |
| SILType getSILArgumentType(unsigned index, |
| TypeExpansionContext context) const; |
| |
| /// Returns true if this function does not return to the caller. |
| bool isNoReturn(TypeExpansionContext context) const; |
| }; |
| |
| struct SILFunctionConventions::SILResultTypeFunc { |
| SILFunctionConventions silConv; |
| TypeExpansionContext context; |
| SILResultTypeFunc(const SILFunctionConventions &silConv, |
| TypeExpansionContext context) |
| : silConv(silConv), context(context) {} |
| |
| SILType operator()(SILResultInfo result) const { |
| return silConv.getSILType(result, context); |
| } |
| }; |
| |
| template <bool _> |
| SILFunctionConventions::IndirectSILResultTypeRange<_> |
| SILFunctionConventions::getIndirectSILResultTypes( |
| TypeExpansionContext context) const { |
| return llvm::map_range(getIndirectSILResults(), |
| SILResultTypeFunc(*this, context)); |
| } |
| |
| template <bool _> |
| SILFunctionConventions::DirectSILResultTypeRange<_> |
| SILFunctionConventions::getDirectSILResultTypes( |
| TypeExpansionContext context) const { |
| return llvm::map_range(getDirectSILResults(), |
| SILResultTypeFunc(*this, context)); |
| } |
| |
| struct SILFunctionConventions::SILParameterTypeFunc { |
| SILFunctionConventions silConv; |
| TypeExpansionContext context; |
| SILParameterTypeFunc(const SILFunctionConventions &silConv, |
| TypeExpansionContext context) |
| : silConv(silConv), context(context) {} |
| |
| SILType operator()(SILParameterInfo param) const { |
| return silConv.getSILType(param, context); |
| } |
| }; |
| |
| template <bool _> |
| SILFunctionConventions::SILParameterTypeRange<_> |
| SILFunctionConventions::getParameterSILTypes( |
| TypeExpansionContext context) const { |
| return llvm::map_range(funcTy->getParameters(), |
| SILParameterTypeFunc(*this, context)); |
| } |
| |
| template <bool _> |
| SILFunctionConventions::SILYieldTypeRange<_> |
| SILFunctionConventions::getYieldSILTypes(TypeExpansionContext context) const { |
| return llvm::map_range(funcTy->getYields(), |
| SILParameterTypeFunc(*this, context)); |
| } |
| |
| inline SILType |
| SILFunctionConventions::getSILArgumentType(unsigned index, |
| TypeExpansionContext context) const { |
| assert(index <= getNumSILArguments()); |
| if (index < getNumIndirectSILResults()) { |
| return *std::next(getIndirectSILResultTypes(context).begin(), index); |
| } |
| return getSILType( |
| funcTy->getParameters()[index - getNumIndirectSILResults()], context); |
| } |
| |
| inline bool |
| SILFunctionConventions::isNoReturn(TypeExpansionContext context) const { |
| return funcTy->isNoReturnFunction(silConv.getModule(), context); |
| } |
| |
| inline SILFunctionConventions |
| SILModuleConventions::getFunctionConventions(CanSILFunctionType funcTy) { |
| return SILFunctionConventions(funcTy, *this); |
| } |
| |
| inline bool SILModuleConventions::isIndirectSILParam(SILParameterInfo param, |
| bool loweredAddresses) { |
| switch (param.getConvention()) { |
| case ParameterConvention::Direct_Unowned: |
| case ParameterConvention::Direct_Guaranteed: |
| case ParameterConvention::Direct_Owned: |
| return false; |
| |
| case ParameterConvention::Indirect_In: |
| case ParameterConvention::Indirect_In_Constant: |
| case ParameterConvention::Indirect_In_Guaranteed: |
| return (loweredAddresses || |
| param.getInterfaceType()->isOpenedExistentialWithError()); |
| case ParameterConvention::Indirect_Inout: |
| case ParameterConvention::Indirect_InoutAliasable: |
| return true; |
| } |
| llvm_unreachable("covered switch isn't covered?!"); |
| } |
| |
| inline bool SILModuleConventions::isIndirectSILYield(SILYieldInfo yield, |
| bool loweredAddresses) { |
| return isIndirectSILParam(yield, loweredAddresses); |
| } |
| |
| inline bool SILModuleConventions::isIndirectSILResult(SILResultInfo result, |
| bool loweredAddresses) { |
| switch (result.getConvention()) { |
| case ResultConvention::Indirect: |
| return (loweredAddresses || |
| result.getInterfaceType()->isOpenedExistentialWithError()); |
| case ResultConvention::Owned: |
| case ResultConvention::Unowned: |
| case ResultConvention::UnownedInnerPointer: |
| case ResultConvention::Autoreleased: |
| return false; |
| } |
| |
| llvm_unreachable("Unhandled ResultConvention in switch."); |
| } |
| |
| inline SILType SILModuleConventions::getSILParamInterfaceType( |
| SILParameterInfo param, |
| bool loweredAddresses) { |
| return SILModuleConventions::isIndirectSILParam(param,loweredAddresses) |
| ? SILType::getPrimitiveAddressType(param.getInterfaceType()) |
| : SILType::getPrimitiveObjectType(param.getInterfaceType()); |
| } |
| |
| inline SILType SILModuleConventions::getSILYieldInterfaceType( |
| SILYieldInfo yield, |
| bool loweredAddresses) { |
| return getSILParamInterfaceType(yield, loweredAddresses); |
| } |
| |
| inline SILType SILModuleConventions::getSILResultInterfaceType( |
| SILResultInfo result, |
| bool loweredAddresses) { |
| return SILModuleConventions::isIndirectSILResult(result, loweredAddresses) |
| ? SILType::getPrimitiveAddressType(result.getInterfaceType()) |
| : SILType::getPrimitiveObjectType(result.getInterfaceType()); |
| } |
| |
| inline SILType |
| SILParameterInfo::getSILStorageInterfaceType() const { |
| return SILModuleConventions::getSILParamInterfaceType(*this, true); |
| } |
| |
| inline SILType |
| SILResultInfo::getSILStorageInterfaceType() const { |
| return SILModuleConventions::getSILResultInterfaceType(*this, true); |
| } |
| |
| inline SILType |
| SILParameterInfo::getSILStorageType(SILModule &M, |
| const SILFunctionType *funcTy, |
| TypeExpansionContext context) const { |
| return funcTy->substInterfaceType(M, getSILStorageInterfaceType(), |
| context); |
| } |
| |
| inline SILType |
| SILResultInfo::getSILStorageType(SILModule &M, const SILFunctionType *funcTy, |
| TypeExpansionContext context) const { |
| return funcTy->substInterfaceType(M, getSILStorageInterfaceType(), |
| context); |
| } |
| |
| } // end swift namespace |
| |
| #endif |