blob: 2451f6f7e6085b3261ac3a448f9fcef40101a056 [file] [log] [blame]
//===--- 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