SubstitutionMap GenericEnvironment:: getSubstitutionMap(SubstitutionList subs) const { SubstitutionMap result; for (auto depTy : getGenericSignature()->getAllDependentTypes()) { // Map the interface type to a context type. auto contextTy = depTy.subst(QueryInterfaceTypeSubstitutions(this), MakeAbstractConformanceForGenericType()); auto sub = subs.front(); subs = subs.slice(1); // Record the replacement type and its conformances. if (auto *archetype = contextTy->getAs<ArchetypeType>()) { result.addSubstitution(CanArchetypeType(archetype), sub.getReplacement()); for (auto conformance : sub.getConformances()) result.addConformance(CanType(archetype), conformance); continue; } // FIXME: getAllDependentTypes() includes generic type parameters that // have been made concrete. assert(contextTy->hasError() || depTy->is<GenericTypeParamType>()); } assert(subs.empty() && "did not use all substitutions?!"); populateParentMap(result); return result; }
static ManagedValue emitBuiltinAllocWithTailElems(SILGenFunction &SGF, SILLocation loc, SubstitutionMap subs, ArrayRef<ManagedValue> args, SGFContext C) { unsigned NumTailTypes = subs.getReplacementTypes().size() - 1; assert(args.size() == NumTailTypes * 2 + 1 && "wrong number of substitutions for allocWithTailElems"); // The substitution determines the element type for bound memory. auto replacementTypes = subs.getReplacementTypes(); SILType RefType = SGF.getLoweredType(replacementTypes[0]-> getCanonicalType()).getObjectType(); SmallVector<ManagedValue, 4> Counts; SmallVector<SILType, 4> ElemTypes; for (unsigned Idx = 0; Idx < NumTailTypes; ++Idx) { Counts.push_back(args[Idx * 2 + 1]); ElemTypes.push_back(SGF.getLoweredType(replacementTypes[Idx+1]-> getCanonicalType()).getObjectType()); } ManagedValue Metatype = args[0]; if (isa<MetatypeInst>(Metatype)) { auto InstanceType = Metatype.getType().castTo<MetatypeType>().getInstanceType(); assert(InstanceType == RefType.getASTType() && "substituted type does not match operand metatype"); (void) InstanceType; return SGF.B.createAllocRef(loc, RefType, false, false, ElemTypes, Counts); } else { return SGF.B.createAllocRefDynamic(loc, Metatype, RefType, false, ElemTypes, Counts); } }
SubstitutionMap SubstitutionMap::combineSubstitutionMaps(const SubstitutionMap &baseSubMap, const SubstitutionMap &origSubMap, unsigned baseDepth, unsigned origDepth, GenericSignature *baseSig) { auto replaceGenericParameter = [&](Type type) -> Type { if (auto gp = type->getAs<GenericTypeParamType>()) { if (gp->getDepth() < baseDepth) return Type(); return GenericTypeParamType::get(gp->getDepth() + origDepth - baseDepth, gp->getIndex(), baseSig->getASTContext()); } return type; }; return baseSig->getSubstitutionMap( [&](SubstitutableType *type) { auto replacement = replaceGenericParameter(type); if (replacement) return Type(replacement).subst(origSubMap); return Type(type).subst(baseSubMap); }, [&](CanType type, Type substType, ProtocolType *conformedProtocol) { auto replacement = type.transform(replaceGenericParameter); if (replacement) return origSubMap.lookupConformance(replacement->getCanonicalType(), conformedProtocol->getDecl()); return baseSubMap.lookupConformance(type, conformedProtocol->getDecl()); }); }
/// Specialized emitter for Builtin.castToBridgeObject. static ManagedValue emitBuiltinCastToBridgeObject(SILGenFunction &SGF, SILLocation loc, SubstitutionMap subs, ArrayRef<ManagedValue> args, SGFContext C) { assert(args.size() == 2 && "cast should have two arguments"); assert(subs.getReplacementTypes().size() == 1 && "cast should have a type substitution"); // Take the reference type argument and cast it to BridgeObject. SILType objPointerType = SILType::getBridgeObjectType(SGF.F.getASTContext()); // Bail if the source type is not a class reference of some kind. auto sourceType = subs.getReplacementTypes()[0]; if (!sourceType->mayHaveSuperclass() && !sourceType->isClassExistentialType()) { SGF.SGM.diagnose(loc, diag::invalid_sil_builtin, "castToBridgeObject source must be a class"); return SGF.emitUndef(objPointerType); } ManagedValue ref = args[0]; SILValue bits = args[1].getUnmanagedValue(); // If the argument is existential, open it. if (sourceType->isClassExistentialType()) { auto openedTy = OpenedArchetypeType::get(sourceType); SILType loweredOpenedTy = SGF.getLoweredLoadableType(openedTy); ref = SGF.B.createOpenExistentialRef(loc, ref, loweredOpenedTy); } return SGF.B.createRefToBridgeObject(loc, ref, bits); }
void SILLinkerVisitor::visitApplySubstitutions(const SubstitutionMap &subs) { for (auto &reqt : subs.getGenericSignature()->getRequirements()) { switch (reqt.getKind()) { case RequirementKind::Conformance: { auto conformance = subs.lookupConformance( reqt.getFirstType()->getCanonicalType(), cast<ProtocolDecl>(reqt.getSecondType()->getAnyNominal())) .getValue(); // Formally all conformances referenced in a function application are // used. However, eagerly visiting them all at this point leads to a // large blowup in the amount of SIL we read in, and we aren't very // systematic about laziness. For optimization purposes we can defer // reading in most conformances until we need them for devirtualization. // However, we *must* pull in shared clang-importer-derived conformances // we potentially use, since we may not otherwise have a local definition. if (mustDeserializeProtocolConformance(Mod, conformance)) { visitProtocolConformance(conformance, None); } break; } case RequirementKind::Layout: case RequirementKind::SameType: case RequirementKind::Superclass: break; } } }
/// Specialized emitter for Builtin.beginUnpairedModifyAccess. static ManagedValue emitBuiltinBeginUnpairedModifyAccess(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C) { assert(substitutions.getReplacementTypes().size() == 1 && "Builtin.beginUnpairedModifyAccess should have one substitution"); assert(args.size() == 3 && "beginUnpairedModifyAccess should be given three arguments"); SILType elemTy = SGF.getLoweredType(substitutions.getReplacementTypes()[0]); SILValue addr = SGF.B.createPointerToAddress(loc, args[0].getUnmanagedValue(), elemTy.getAddressType(), /*strict*/ true, /*invariant*/ false); SILType valueBufferTy = SGF.getLoweredType(SGF.getASTContext().TheUnsafeValueBufferType); SILValue buffer = SGF.B.createPointerToAddress(loc, args[1].getUnmanagedValue(), valueBufferTy.getAddressType(), /*strict*/ true, /*invariant*/ false); SGF.B.createBeginUnpairedAccess(loc, addr, buffer, SILAccessKind::Modify, SILAccessEnforcement::Dynamic, /*noNestedConflict*/ false, /*fromBuiltin*/ true); return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); }
/// Specialized emitter for Builtin.load and Builtin.take. static ManagedValue emitBuiltinLoadOrTake(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C, IsTake_t isTake, bool isStrict, bool isInvariant) { assert(substitutions.getReplacementTypes().size() == 1 && "load should have single substitution"); assert(args.size() == 1 && "load should have a single argument"); // The substitution gives the type of the load. This is always a // first-class type; there is no way to e.g. produce a @weak load // with this builtin. auto &rvalueTL = SGF.getTypeLowering(substitutions.getReplacementTypes()[0]); SILType loadedType = rvalueTL.getLoweredType(); // Convert the pointer argument to a SIL address. SILValue addr = SGF.B.createPointerToAddress(loc, args[0].getUnmanagedValue(), loadedType.getAddressType(), isStrict, isInvariant); // Perform the load. return SGF.emitLoad(loc, addr, rvalueTL, C, isTake); }
static ManagedValue emitCastToReferenceType(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C, SILType objPointerType) { assert(args.size() == 1 && "cast should have a single argument"); assert(substitutions.getReplacementTypes().size() == 1 && "cast should have a type substitution"); // Bail if the source type is not a class reference of some kind. Type argTy = substitutions.getReplacementTypes()[0]; if (!argTy->mayHaveSuperclass() && !argTy->isClassExistentialType()) { SGF.SGM.diagnose(loc, diag::invalid_sil_builtin, "castToNativeObject source must be a class"); return SGF.emitUndef(objPointerType); } // Grab the argument. ManagedValue arg = args[0]; // If the argument is existential, open it. if (argTy->isClassExistentialType()) { auto openedTy = OpenedArchetypeType::get(argTy); SILType loweredOpenedTy = SGF.getLoweredLoadableType(openedTy); arg = SGF.B.createOpenExistentialRef(loc, arg, loweredOpenedTy); } // Return the cast result. return SGF.B.createUncheckedRefCast(loc, arg, objPointerType); }
static ManagedValue emitBuiltinAssign(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C) { assert(args.size() >= 2 && "assign should have two arguments"); assert(substitutions.getReplacementTypes().size() == 1 && "assign should have a single substitution"); // The substitution determines the type of the thing we're destroying. CanType assignFormalType = substitutions.getReplacementTypes()[0]->getCanonicalType(); SILType assignType = SGF.getLoweredType(assignFormalType); // Convert the destination pointer argument to a SIL address. SILValue addr = SGF.B.createPointerToAddress(loc, args.back().getUnmanagedValue(), assignType.getAddressType(), /*isStrict*/ true, /*isInvariant*/ false); // Build the value to be assigned, reconstructing tuples if needed. auto src = RValue(SGF, args.slice(0, args.size() - 1), assignFormalType); std::move(src).ensurePlusOne(SGF, loc).assignInto(SGF, loc, addr); return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); }
/// Specialized emitter for Builtin.destroy. static ManagedValue emitBuiltinDestroy(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C) { assert(args.size() == 2 && "destroy should have two arguments"); assert(substitutions.getReplacementTypes().size() == 1 && "destroy should have a single substitution"); // The substitution determines the type of the thing we're destroying. auto &ti = SGF.getTypeLowering(substitutions.getReplacementTypes()[0]); // Destroy is a no-op for trivial types. if (ti.isTrivial()) return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); SILType destroyType = ti.getLoweredType(); // Convert the pointer argument to a SIL address. SILValue addr = SGF.B.createPointerToAddress(loc, args[1].getUnmanagedValue(), destroyType.getAddressType(), /*isStrict*/ true, /*isInvariant*/ false); // Destroy the value indirectly. Canonicalization will promote to loads // and releases if appropriate. SGF.B.createDestroyAddr(loc, addr); return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); }
/// Specialized emitter for Builtin.reinterpretCast. static ManagedValue emitBuiltinReinterpretCast(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C) { assert(args.size() == 1 && "reinterpretCast should be given one argument"); assert(substitutions.getReplacementTypes().size() == 2 && "reinterpretCast should have two subs"); auto &fromTL = SGF.getTypeLowering(substitutions.getReplacementTypes()[0]); auto &toTL = SGF.getTypeLowering(substitutions.getReplacementTypes()[1]); // If casting between address types, cast the address. if (fromTL.isAddress() || toTL.isAddress()) { SILValue fromAddr; // If the from value is not an address, move it to a buffer. if (!fromTL.isAddress()) { fromAddr = SGF.emitTemporaryAllocation(loc, args[0].getValue()->getType()); fromTL.emitStore(SGF.B, loc, args[0].getValue(), fromAddr, StoreOwnershipQualifier::Init); } else { fromAddr = args[0].getValue(); } auto toAddr = SGF.B.createUncheckedAddrCast(loc, fromAddr, toTL.getLoweredType().getAddressType()); // Load and retain the destination value if it's loadable. Leave the cleanup // on the original value since we don't know anything about it's type. if (!toTL.isAddress()) { return SGF.emitManagedLoadCopy(loc, toAddr, toTL); } // Leave the cleanup on the original value. if (toTL.isTrivial()) return ManagedValue::forUnmanaged(toAddr); // Initialize the +1 result buffer without taking the incoming value. The // source and destination cleanups will be independent. return SGF.B.bufferForExpr( loc, toTL.getLoweredType(), toTL, C, [&](SILValue bufferAddr) { SGF.B.createCopyAddr(loc, toAddr, bufferAddr, IsNotTake, IsInitialization); }); } // Create the appropriate bitcast based on the source and dest types. ManagedValue in = args[0]; SILType resultTy = toTL.getLoweredType(); if (resultTy.isTrivial(SGF.F)) return SGF.B.createUncheckedTrivialBitCast(loc, in, resultTy); // If we can perform a ref cast, just return. if (auto refCast = SGF.B.tryCreateUncheckedRefCast(loc, in, resultTy)) return refCast; // Otherwise leave the original cleanup and retain the cast value. SILValue out = SGF.B.createUncheckedBitwiseCast(loc, in.getValue(), resultTy); return SGF.emitManagedRetain(loc, out, toTL); }
void GenericEnvironment:: getSubstitutionMap(ModuleDecl *mod, GenericSignature *sig, ArrayRef<Substitution> subs, SubstitutionMap &result) const { for (auto depTy : sig->getAllDependentTypes()) { // Map the interface type to a context type. auto contextTy = depTy.subst(mod, InterfaceToArchetypeMap, SubstOptions()); auto *archetype = contextTy->castTo<ArchetypeType>(); auto sub = subs.front(); subs = subs.slice(1); // Record the replacement type and its conformances. result.addSubstitution(CanType(archetype), sub.getReplacement()); result.addConformances(CanType(archetype), sub.getConformances()); } for (auto reqt : sig->getRequirements()) { if (reqt.getKind() != RequirementKind::SameType) continue; auto first = reqt.getFirstType()->getAs<DependentMemberType>(); auto second = reqt.getSecondType()->getAs<DependentMemberType>(); if (!first || !second) continue; auto archetype = mapTypeIntoContext(mod, first)->getAs<ArchetypeType>(); if (!archetype) continue; auto firstBase = first->getBase(); auto secondBase = second->getBase(); auto firstBaseArchetype = mapTypeIntoContext(mod, firstBase)->getAs<ArchetypeType>(); auto secondBaseArchetype = mapTypeIntoContext(mod, secondBase)->getAs<ArchetypeType>(); if (!firstBaseArchetype || !secondBaseArchetype) continue; if (archetype->getParent() != firstBaseArchetype) result.addParent(CanType(archetype), CanType(firstBaseArchetype), first->getAssocType()); if (archetype->getParent() != secondBaseArchetype) result.addParent(CanType(archetype), CanType(secondBaseArchetype), second->getAssocType()); } assert(subs.empty() && "did not use all substitutions?!"); }
SubstitutionMap SubstitutionMap::get(GenericSignature *genericSig, SubstitutionMap substitutions) { if (!genericSig) { assert(!substitutions.hasAnySubstitutableParams() && "Shouldn't have substitutions here"); return SubstitutionMap(); } return SubstitutionMap::get(genericSig, [&](SubstitutableType *type) -> Type { return substitutions.lookupSubstitution( CanSubstitutableType(type)); }, LookUpConformanceInSubstitutionMap(substitutions)); }
void SubstitutionMap::addSubstitutions(SubstitutionMap& subMap, bool invalidateCache) { SubstitutionMap::NodeMap::const_iterator it = subMap.begin(); SubstitutionMap::NodeMap::const_iterator it_end = subMap.end(); for (; it != it_end; ++ it) { Assert(d_substitutions.find((*it).first) == d_substitutions.end()); d_substitutions[(*it).first] = (*it).second; if (!invalidateCache) { d_substitutionCache[(*it).first] = d_substitutions[(*it).first]; } } if (invalidateCache) { d_cacheInvalidated = true; } }
SubstitutionMap SubstitutionMap::combineSubstitutionMaps(SubstitutionMap firstSubMap, SubstitutionMap secondSubMap, CombineSubstitutionMaps how, unsigned firstDepthOrIndex, unsigned secondDepthOrIndex, GenericSignature *genericSig) { auto &ctx = genericSig->getASTContext(); auto replaceGenericParameter = [&](Type type) -> Type { if (auto gp = type->getAs<GenericTypeParamType>()) { if (how == CombineSubstitutionMaps::AtDepth) { if (gp->getDepth() < firstDepthOrIndex) return Type(); return GenericTypeParamType::get( gp->getDepth() + secondDepthOrIndex - firstDepthOrIndex, gp->getIndex(), ctx); } assert(how == CombineSubstitutionMaps::AtIndex); if (gp->getIndex() < firstDepthOrIndex) return Type(); return GenericTypeParamType::get( gp->getDepth(), gp->getIndex() + secondDepthOrIndex - firstDepthOrIndex, ctx); } return type; }; return get( genericSig, [&](SubstitutableType *type) { auto replacement = replaceGenericParameter(type); if (replacement) return Type(replacement).subst(secondSubMap); return Type(type).subst(firstSubMap); }, [&](CanType type, Type substType, ProtocolDecl *conformedProtocol) { auto replacement = type.transform(replaceGenericParameter); if (replacement) return secondSubMap.lookupConformance(replacement->getCanonicalType(), conformedProtocol); return firstSubMap.lookupConformance(type, conformedProtocol); }); }
void GenericEnvironment::populateParentMap(SubstitutionMap &subMap) const { for (auto reqt : getGenericSignature()->getRequirements()) { if (reqt.getKind() != RequirementKind::SameType) continue; auto first = reqt.getFirstType(); auto second = reqt.getSecondType(); auto archetype = first.subst( QueryInterfaceTypeSubstitutions(this), MakeAbstractConformanceForGenericType()) ->getAs<ArchetypeType>(); if (!archetype) continue; #ifndef NDEBUG auto secondArchetype = second.subst( QueryInterfaceTypeSubstitutions(this), MakeAbstractConformanceForGenericType()) ->getAs<ArchetypeType>(); assert(secondArchetype == archetype); #endif if (auto *firstMemTy = first->getAs<DependentMemberType>()) { auto parent = firstMemTy->getBase().subst( QueryInterfaceTypeSubstitutions(this), MakeAbstractConformanceForGenericType()) ->getAs<ArchetypeType>(); if (parent && archetype->getParent() != parent) { subMap.addParent(CanType(archetype), CanType(parent), firstMemTy->getAssocType()); } } if (auto *secondMemTy = second->getAs<DependentMemberType>()) { auto parent = secondMemTy->getBase().subst( QueryInterfaceTypeSubstitutions(this), MakeAbstractConformanceForGenericType()) ->getAs<ArchetypeType>(); if (parent && archetype->getParent() != parent) { subMap.addParent(CanType(archetype), CanType(parent), secondMemTy->getAssocType()); } } } }
/// Emit Builtin.initialize by evaluating the operand directly into /// the address. static ManagedValue emitBuiltinInit(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, PreparedArguments &&preparedArgs, SGFContext C) { auto argsOrError = decomposeArguments(SGF, loc, std::move(preparedArgs), 2); if (!argsOrError) return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); auto args = *argsOrError; CanType formalType = substitutions.getReplacementTypes()[0]->getCanonicalType(); auto &formalTL = SGF.getTypeLowering(formalType); SILValue addr = SGF.emitRValueAsSingleValue(args[1]).getUnmanagedValue(); addr = SGF.B.createPointerToAddress( loc, addr, formalTL.getLoweredType().getAddressType(), /*isStrict*/ true, /*isInvariant*/ false); TemporaryInitialization init(addr, CleanupHandle::invalid()); SGF.emitExprInto(args[0], &init); return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); }
static ManagedValue emitBuiltinBindMemory(SILGenFunction &SGF, SILLocation loc, SubstitutionMap subs, ArrayRef<ManagedValue> args, SGFContext C) { assert(subs.getReplacementTypes().size() == 1 && "bindMemory should have a single substitution"); assert(args.size() == 3 && "bindMemory should have three argument"); // The substitution determines the element type for bound memory. CanType boundFormalType = subs.getReplacementTypes()[0]->getCanonicalType(); SILType boundType = SGF.getLoweredType(boundFormalType); SGF.B.createBindMemory(loc, args[0].getValue(), args[1].getValue(), boundType); return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); }
void AbstractionModule::makeFreshSkolems(TNode node, SubstitutionMap& map, SubstitutionMap& reverse_map) { if (map.hasSubstitution(node)) { return; } if (node.getMetaKind() == kind::metakind::VARIABLE) { Node skolem = utils::mkVar(utils::getSize(node)); map.addSubstitution(node, skolem); reverse_map.addSubstitution(skolem, node); return; } if (node.isConst()) return; for (unsigned i = 0; i < node.getNumChildren(); ++i) { makeFreshSkolems(node[i], map, reverse_map); } }
Witness::Witness(ValueDecl *decl, SubstitutionMap substitutions, GenericEnvironment *syntheticEnv, SubstitutionMap reqToSynthesizedEnvSubs) { if (!syntheticEnv && substitutions.empty() && reqToSynthesizedEnvSubs.empty()) { storage = decl; return; } auto &ctx = decl->getASTContext(); auto declRef = ConcreteDeclRef(decl, substitutions); auto storedMem = ctx.Allocate(sizeof(StoredWitness), alignof(StoredWitness)); auto stored = new (storedMem) StoredWitness{declRef, syntheticEnv, reqToSynthesizedEnvSubs}; storage = stored; }
static ManagedValue emitBuiltinTypeTrait(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C) { assert(substitutions.getReplacementTypes().size() == 1 && "type trait should take a single type parameter"); assert(args.size() == 1 && "type trait should take a single argument"); unsigned result; auto traitTy = substitutions.getReplacementTypes()[0]->getCanonicalType(); switch ((traitTy.getPointer()->*Trait)()) { // If the type obviously has or lacks the trait, emit a constant result. case TypeTraitResult::IsNot: result = 0; break; case TypeTraitResult::Is: result = 1; break; // If not, emit the builtin call normally. Specialization may be able to // eliminate it later, or we'll lower it away at IRGen time. case TypeTraitResult::CanBe: { auto &C = SGF.getASTContext(); auto int8Ty = BuiltinIntegerType::get(8, C)->getCanonicalType(); auto apply = SGF.B.createBuiltin(loc, C.getIdentifier(getBuiltinName(Kind)), SILType::getPrimitiveObjectType(int8Ty), substitutions, args[0].getValue()); return ManagedValue::forUnmanaged(apply); } } // Produce the result as an integer literal constant. auto val = SGF.B.createIntegerLiteral( loc, SILType::getBuiltinIntegerType(8, SGF.getASTContext()), (uintmax_t)result); return ManagedValue::forUnmanaged(val); }
static std::pair<ManagedValue, SILDeclRef> getNextUncurryLevelRef(SILGenFunction &SGF, SILLocation loc, SILDeclRef thunk, ManagedValue selfArg, SubstitutionMap curriedSubs) { auto *vd = thunk.getDecl(); // Reference the next uncurrying level of the function. SILDeclRef next = SILDeclRef(vd, thunk.kind); assert(!next.isCurried); auto constantInfo = SGF.SGM.Types.getConstantInfo(next); // If the function is natively foreign, reference its foreign entry point. if (requiresForeignToNativeThunk(vd)) return {ManagedValue::forUnmanaged(SGF.emitGlobalFunctionRef(loc, next)), next}; // If the thunk is a curry thunk for a direct method reference, we are // doing a direct dispatch (eg, a fragile 'super.foo()' call). if (thunk.isDirectReference) return {ManagedValue::forUnmanaged(SGF.emitGlobalFunctionRef(loc, next)), next}; if (auto *func = dyn_cast<AbstractFunctionDecl>(vd)) { if (getMethodDispatch(func) == MethodDispatch::Class) { // Use the dynamic thunk if dynamic. if (vd->isObjCDynamic()) { return {SGF.emitDynamicMethodRef(loc, next, constantInfo.SILFnType), next}; } auto methodTy = SGF.SGM.Types.getConstantOverrideType(next); SILValue result = SGF.emitClassMethodRef(loc, selfArg.getValue(), next, methodTy); return {ManagedValue::forUnmanaged(result), next.getOverriddenVTableEntry()}; } // If the fully-uncurried reference is to a generic method, look up the // witness. if (constantInfo.SILFnType->getRepresentation() == SILFunctionTypeRepresentation::WitnessMethod) { auto protocol = func->getDeclContext()->getSelfProtocolDecl(); auto origSelfType = protocol->getSelfInterfaceType()->getCanonicalType(); auto substSelfType = origSelfType.subst(curriedSubs)->getCanonicalType(); auto conformance = curriedSubs.lookupConformance(origSelfType, protocol); auto result = SGF.B.createWitnessMethod(loc, substSelfType, *conformance, next, constantInfo.getSILType()); return {ManagedValue::forUnmanaged(result), next}; } } // Otherwise, emit a direct call. return {ManagedValue::forUnmanaged(SGF.emitGlobalFunctionRef(loc, next)), next}; }
// Initialize SpecializedType iff the specialization is allowed. ReabstractionInfo::ReabstractionInfo(SILFunction *OrigF, ArrayRef<Substitution> ParamSubs) { if (!OrigF->shouldOptimize()) { DEBUG(llvm::dbgs() << " Cannot specialize function " << OrigF->getName() << " marked to be excluded from optimizations.\n"); return; } SubstitutionMap InterfaceSubs; if (OrigF->getLoweredFunctionType()->getGenericSignature()) InterfaceSubs = OrigF->getLoweredFunctionType()->getGenericSignature() ->getSubstitutionMap(ParamSubs); // We do not support partial specialization. if (hasUnboundGenericTypes(InterfaceSubs.getMap())) { DEBUG(llvm::dbgs() << " Cannot specialize with unbound interface substitutions.\n"); DEBUG(for (auto Sub : ParamSubs) { Sub.dump(); });
static ManagedValue emitBuiltinClassifyBridgeObject(SILGenFunction &SGF, SILLocation loc, SubstitutionMap subs, ArrayRef<ManagedValue> args, SGFContext C) { assert(args.size() == 1 && "classify should have one argument"); assert(subs.empty() && "classify should not have subs"); SILValue result = SGF.B.createClassifyBridgeObject(loc, args[0].getValue()); return ManagedValue::forUnmanaged(result); }
static ManagedValue emitBuiltinValueToBridgeObject(SILGenFunction &SGF, SILLocation loc, SubstitutionMap subs, ArrayRef<ManagedValue> args, SGFContext C) { assert(args.size() == 1 && "ValueToBridgeObject should have one argument"); assert(subs.getReplacementTypes().size() == 1 && "ValueToBridgeObject should have one sub"); Type argTy = subs.getReplacementTypes()[0]; if (!argTy->is<BuiltinIntegerType>()) { SGF.SGM.diagnose(loc, diag::invalid_sil_builtin, "argument to builtin should be a builtin integer"); SILType objPointerType = SILType::getBridgeObjectType(SGF.F.getASTContext()); return SGF.emitUndef(objPointerType); } SILValue result = SGF.B.createValueToBridgeObject(loc, args[0].getValue()); return SGF.emitManagedRetain(loc, result); }
static ManagedValue emitBuiltinProjectTailElems(SILGenFunction &SGF, SILLocation loc, SubstitutionMap subs, ArrayRef<ManagedValue> args, SGFContext C) { assert(subs.getReplacementTypes().size() == 2 && "allocWithTailElems should have two substitutions"); assert(args.size() == 2 && "allocWithTailElems should have three arguments"); // The substitution determines the element type for bound memory. SILType ElemType = SGF.getLoweredType(subs.getReplacementTypes()[1]-> getCanonicalType()).getObjectType(); SILValue result = SGF.B.createRefTailAddr(loc, args[0].getValue(), ElemType.getAddressType()); SILType rawPointerType = SILType::getRawPointerType(SGF.F.getASTContext()); result = SGF.B.createAddressToPointer(loc, result, rawPointerType); return ManagedValue::forUnmanaged(result); }
/// Specialized emitter for Builtin.gep. static ManagedValue emitBuiltinGep(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C) { assert(substitutions.getReplacementTypes().size() == 1 && "gep should have two substitutions"); assert(args.size() == 3 && "gep should be given three arguments"); SILType ElemTy = SGF.getLoweredType(substitutions.getReplacementTypes()[0]); SILType RawPtrType = args[0].getUnmanagedValue()->getType(); SILValue addr = SGF.B.createPointerToAddress(loc, args[0].getUnmanagedValue(), ElemTy.getAddressType(), /*strict*/ true, /*invariant*/ false); addr = SGF.B.createIndexAddr(loc, addr, args[1].getUnmanagedValue()); addr = SGF.B.createAddressToPointer(loc, addr, RawPtrType); return ManagedValue::forUnmanaged(addr); }
/// Specialized emitter for Builtin.bridgeFromRawPointer. static ManagedValue emitBuiltinBridgeFromRawPointer(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C) { assert(substitutions.getReplacementTypes().size() == 1 && "bridge should have a single substitution"); assert(args.size() == 1 && "bridge should have a single argument"); // The substitution determines the destination type. // FIXME: Archetype destination type? auto &destLowering = SGF.getTypeLowering(substitutions.getReplacementTypes()[0]); assert(destLowering.isLoadable()); SILType destType = destLowering.getLoweredType(); // Take the raw pointer argument and cast it to the destination type. SILValue result = SGF.B.createRawPointerToRef(loc, args[0].getUnmanagedValue(), destType); // The result has ownership semantics, so retain it with a cleanup. return SGF.emitManagedRetain(loc, result, destLowering); }
SubstitutionMap ProtocolConformance::getSubstitutions(ModuleDecl *M) const { // Walk down to the base NormalProtocolConformance. SubstitutionMap subMap; const ProtocolConformance *parent = this; while (!isa<NormalProtocolConformance>(parent)) { switch (parent->getKind()) { case ProtocolConformanceKind::Normal: llvm_unreachable("should have exited the loop?!"); case ProtocolConformanceKind::Inherited: parent = cast<InheritedProtocolConformance>(parent)->getInheritedConformance(); break; case ProtocolConformanceKind::Specialized: { auto SC = cast<SpecializedProtocolConformance>(parent); parent = SC->getGenericConformance(); assert(subMap.empty() && "multiple conformance specializations?!"); subMap = SC->getSubstitutionMap(); break; } } } // Found something; we're done! if (!subMap.empty()) return subMap; // If the normal conformance is for a generic type, and we didn't hit a // specialized conformance, collect the substitutions from the generic type. // FIXME: The AST should do this for us. const NormalProtocolConformance *normalC = cast<NormalProtocolConformance>(parent); if (!normalC->getType()->isSpecialized()) return SubstitutionMap(); auto *DC = normalC->getDeclContext(); return normalC->getType()->getContextSubstitutionMap(M, DC); }
SubstitutionMap GenericEnvironment:: getSubstitutionMap(TypeSubstitutionFn subs, GenericSignature::LookupConformanceFn lookupConformance) const { SubstitutionMap subMap; getGenericSignature()->enumeratePairedRequirements( [&](Type depTy, ArrayRef<Requirement> reqs) -> bool { // Map the interface type to a context type. auto contextTy = depTy.subst(QueryInterfaceTypeSubstitutions(this), MakeAbstractConformanceForGenericType()); // Compute the replacement type. Type currentReplacement = contextTy.subst(subs, lookupConformance, SubstFlags::UseErrorType); if (auto archetypeTy = contextTy->getAs<ArchetypeType>()) { subMap.addSubstitution(CanArchetypeType(archetypeTy), currentReplacement); // Collect the conformances. for (auto req: reqs) { assert(req.getKind() == RequirementKind::Conformance); auto protoType = req.getSecondType()->castTo<ProtocolType>(); auto conformance = lookupConformance(CanArchetypeType(archetypeTy), currentReplacement, protoType); if (conformance) subMap.addConformance(CanArchetypeType(archetypeTy), *conformance); } } return false; }); populateParentMap(subMap); return subMap; }