| //===--- TypeSubstCloner.h - Clones code and substitutes types --*- 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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines TypeSubstCloner, which derives from SILCloner and |
| // has support for type substitution while cloning code that uses generics. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_SIL_TYPESUBSTCLONER_H |
| #define SWIFT_SIL_TYPESUBSTCLONER_H |
| |
| #include "swift/AST/GenericEnvironment.h" |
| #include "swift/AST/ProtocolConformance.h" |
| #include "swift/AST/Type.h" |
| #include "swift/SIL/SILCloner.h" |
| #include "swift/SIL/DynamicCasts.h" |
| #include "swift/SILOptimizer/Utils/Local.h" |
| #include "llvm/Support/Debug.h" |
| |
| namespace swift { |
| |
| /// TypeSubstCloner - a utility class for cloning code while remapping types. |
| template<typename ImplClass> |
| class TypeSubstCloner : public SILClonerWithScopes<ImplClass> { |
| friend class SILVisitor<ImplClass>; |
| friend class SILCloner<ImplClass>; |
| |
| typedef SILClonerWithScopes<ImplClass> super; |
| |
| void postProcess(SILInstruction *Orig, SILInstruction *Cloned) { |
| llvm_unreachable("Clients need to explicitly call a base class impl!"); |
| } |
| |
| void computeSubsMap() { |
| if (auto genericSig = Original.getLoweredFunctionType() |
| ->getGenericSignature()) { |
| SubsMap = genericSig->getSubstitutionMap(ApplySubs); |
| } |
| } |
| |
| public: |
| using SILClonerWithScopes<ImplClass>::asImpl; |
| using SILClonerWithScopes<ImplClass>::getBuilder; |
| using SILClonerWithScopes<ImplClass>::getOpLocation; |
| using SILClonerWithScopes<ImplClass>::getOpValue; |
| using SILClonerWithScopes<ImplClass>::getASTTypeInClonedContext; |
| using SILClonerWithScopes<ImplClass>::getOpASTType; |
| using SILClonerWithScopes<ImplClass>::getTypeInClonedContext; |
| using SILClonerWithScopes<ImplClass>::getOpType; |
| using SILClonerWithScopes<ImplClass>::getOpBasicBlock; |
| using SILClonerWithScopes<ImplClass>::doPostProcess; |
| using SILClonerWithScopes<ImplClass>::ValueMap; |
| using SILClonerWithScopes<ImplClass>::addBlockWithUnreachable; |
| using SILClonerWithScopes<ImplClass>::OpenedArchetypesTracker; |
| |
| TypeSubstCloner(SILFunction &To, |
| SILFunction &From, |
| SubstitutionList ApplySubs, |
| SILOpenedArchetypesTracker &OpenedArchetypesTracker, |
| bool Inlining = false) |
| : SILClonerWithScopes<ImplClass>(To, OpenedArchetypesTracker, Inlining), |
| SwiftMod(From.getModule().getSwiftModule()), |
| Original(From), |
| ApplySubs(ApplySubs), |
| Inlining(Inlining) { |
| computeSubsMap(); |
| } |
| |
| TypeSubstCloner(SILFunction &To, |
| SILFunction &From, |
| SubstitutionList ApplySubs, |
| bool Inlining = false) |
| : SILClonerWithScopes<ImplClass>(To, Inlining), |
| SwiftMod(From.getModule().getSwiftModule()), |
| Original(From), |
| ApplySubs(ApplySubs), |
| Inlining(Inlining) { |
| computeSubsMap(); |
| } |
| |
| |
| protected: |
| SILType remapType(SILType Ty) { |
| return Ty.subst(Original.getModule(), SubsMap); |
| } |
| |
| CanType remapASTType(CanType ty) { |
| return ty.subst(SubsMap)->getCanonicalType(); |
| } |
| |
| ProtocolConformanceRef remapConformance(Type type, |
| ProtocolConformanceRef conf) { |
| return conf.subst(type, |
| QuerySubstitutionMap{SubsMap}, |
| LookUpConformanceInSubstitutionMap(SubsMap)); |
| } |
| |
| void visitApplyInst(ApplyInst *Inst) { |
| auto Args = this->template getOpValueArray<8>(Inst->getArguments()); |
| |
| // Handle recursions by replacing the apply to the callee with an apply to |
| // the newly specialized function, but only if substitutions are the same. |
| SILBuilder &Builder = getBuilder(); |
| Builder.setCurrentDebugScope(super::getOpScope(Inst->getDebugScope())); |
| SILValue CalleeVal = Inst->getCallee(); |
| if (!Inlining) { |
| FunctionRefInst *FRI = dyn_cast<FunctionRefInst>(CalleeVal); |
| if (FRI && FRI->getReferencedFunction() == Inst->getFunction() && |
| Inst->getSubstitutions() == this->ApplySubs) { |
| FRI = Builder.createFunctionRef(getOpLocation(Inst->getLoc()), |
| &Builder.getFunction()); |
| ApplyInst *NAI = |
| Builder.createApply(getOpLocation(Inst->getLoc()), FRI, Args, Inst->isNonThrowing()); |
| doPostProcess(Inst, NAI); |
| return; |
| } |
| } |
| |
| SmallVector<Substitution, 16> TempSubstList; |
| for (auto &Sub : Inst->getSubstitutions()) { |
| TempSubstList.push_back(asImpl().getOpSubstitution(Sub)); |
| } |
| |
| ApplyInst *N = Builder.createApply( |
| getOpLocation(Inst->getLoc()), getOpValue(CalleeVal), |
| getOpType(Inst->getSubstCalleeSILType()), getOpType(Inst->getType()), |
| TempSubstList, Args, Inst->isNonThrowing()); |
| doPostProcess(Inst, N); |
| } |
| |
| void visitPartialApplyInst(PartialApplyInst *Inst) { |
| auto Args = this->template getOpValueArray<8>(Inst->getArguments()); |
| |
| // Handle recursions by replacing the apply to the callee with an apply to |
| // the newly specialized function. |
| SILValue CalleeVal = Inst->getCallee(); |
| SILBuilderWithPostProcess<TypeSubstCloner, 4> Builder(this, Inst); |
| Builder.setCurrentDebugScope(super::getOpScope(Inst->getDebugScope())); |
| SmallVector<Substitution, 16> TempSubstList; |
| if (!Inlining) { |
| FunctionRefInst *FRI = dyn_cast<FunctionRefInst>(CalleeVal); |
| if (FRI && FRI->getReferencedFunction() == Inst->getFunction()) { |
| auto LoweredFnTy = Builder.getFunction().getLoweredFunctionType(); |
| auto GenSig = LoweredFnTy->getGenericSignature(); |
| if (GenSig) { |
| GenSig->getSubstitutions( |
| Inst->getFunction() |
| ->getLoweredFunctionType() |
| ->getGenericSignature() |
| ->getSubstitutionMap(Inst->getSubstitutions()), |
| TempSubstList); |
| } |
| for (auto &Sub : TempSubstList) { |
| Sub = asImpl().getOpSubstitution(Sub); |
| } |
| SubstitutionList Subs = TempSubstList; |
| FRI = Builder.createFunctionRef(getOpLocation(Inst->getLoc()), |
| &Builder.getFunction()); |
| Builder.createPartialApply(getOpLocation(Inst->getLoc()), FRI, |
| getOpType(Inst->getSubstCalleeSILType()), |
| Subs, |
| Args, |
| getOpType(Inst->getType())); |
| return; |
| } |
| } |
| |
| for (auto &Sub : Inst->getSubstitutions()) { |
| TempSubstList.push_back(asImpl().getOpSubstitution(Sub)); |
| } |
| |
| Builder.createPartialApply( |
| getOpLocation(Inst->getLoc()), getOpValue(CalleeVal), |
| getOpType(Inst->getSubstCalleeSILType()), TempSubstList, Args, |
| getOpType(Inst->getType())); |
| } |
| |
| /// Attempt to simplify a conditional checked cast. |
| void visitCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *inst) { |
| SILLocation loc = getOpLocation(inst->getLoc()); |
| SILValue src = getOpValue(inst->getSrc()); |
| SILValue dest = getOpValue(inst->getDest()); |
| CanType sourceType = getOpASTType(inst->getSourceType()); |
| CanType targetType = getOpASTType(inst->getTargetType()); |
| SILBasicBlock *succBB = getOpBasicBlock(inst->getSuccessBB()); |
| SILBasicBlock *failBB = getOpBasicBlock(inst->getFailureBB()); |
| |
| SILBuilderWithPostProcess<TypeSubstCloner, 16> B(this, inst); |
| B.setCurrentDebugScope(super::getOpScope(inst->getDebugScope())); |
| |
| // Try to use the scalar cast instruction. |
| if (canUseScalarCheckedCastInstructions(B.getModule(), |
| sourceType, targetType)) { |
| emitIndirectConditionalCastWithScalar(B, SwiftMod, loc, |
| inst->getConsumptionKind(), |
| src, sourceType, |
| dest, targetType, |
| succBB, failBB); |
| return; |
| } |
| |
| // Otherwise, use the indirect cast. |
| B.createCheckedCastAddrBranch(loc, inst->getConsumptionKind(), |
| src, sourceType, |
| dest, targetType, |
| succBB, failBB); |
| return; |
| } |
| |
| void visitUpcastInst(UpcastInst *Upcast) { |
| // If the type substituted type of the operand type and result types match |
| // there is no need for an upcast and we can just use the operand. |
| if (getOpType(Upcast->getType()) == |
| getOpValue(Upcast->getOperand())->getType()) { |
| ValueMap.insert({SILValue(Upcast), getOpValue(Upcast->getOperand())}); |
| return; |
| } |
| super::visitUpcastInst(Upcast); |
| } |
| |
| /// The Swift module that the cloned function belongs to. |
| ModuleDecl *SwiftMod; |
| /// The substitutions list for the specialization. |
| SubstitutionMap SubsMap; |
| /// The original function to specialize. |
| SILFunction &Original; |
| /// The substitutions used at the call site. |
| SubstitutionList ApplySubs; |
| /// True, if used for inlining. |
| bool Inlining; |
| }; |
| |
| } // end namespace swift |
| |
| #endif |