//===--- Builtins.cpp - Swift Language Builtin ASTs -----------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2022 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 implements the interface to the Builtin APIs. // //===----------------------------------------------------------------------===// #include "swift/AST/Builtins.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTSynthesis.h" #include "swift/AST/ConformanceLookup.h" #include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/Types.h" #include "swift/Basic/Assertions.h" #include "swift/Strings.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/Support/ManagedStatic.h" #include using namespace swift; struct BuiltinExtraInfoTy { const char *Attributes; }; static const BuiltinExtraInfoTy BuiltinExtraInfo[] = { {nullptr}, #define BUILTIN(Id, Name, Attrs) {Attrs}, #include "swift/AST/Builtins.def" }; bool BuiltinInfo::isReadNone() const { return strchr(BuiltinExtraInfo[(unsigned)ID].Attributes, 'n') != nullptr; } const llvm::AttributeList & IntrinsicInfo::getOrCreateAttributes(ASTContext &Ctx) const { using DenseMapInfo = llvm::DenseMapInfo; if (DenseMapInfo::isEqual(Attrs, DenseMapInfo::getEmptyKey())) { Attrs = llvm::Intrinsic::getAttributes(Ctx.getIntrinsicScratchContext(), ID); } return Attrs; } Type swift::getBuiltinType(ASTContext &Context, StringRef Name) { if (Name == "FixedArray") { return BuiltinUnboundGenericType::get(TypeKind::BuiltinFixedArray, Context); } // Vectors are VecNxT, where "N" is the number of elements and // T is the element type. if (Name.starts_with("Vec")) { Name = Name.substr(3); StringRef::size_type xPos = Name.find('x'); if (xPos == StringRef::npos) return Type(); unsigned numElements; if (Name.substr(0, xPos).getAsInteger(10, numElements) || numElements == 0 || numElements > 1024) return Type(); Type elementType = getBuiltinType(Context, Name.substr(xPos + 1)); if (!elementType) return Type(); return BuiltinVectorType::get(Context, elementType, numElements); } if (Name == "RawPointer") return Context.TheRawPointerType; if (Name == "RawUnsafeContinuation") return Context.TheRawUnsafeContinuationType; if (Name == "Job") return Context.TheJobType; if (Name == "DefaultActorStorage") return Context.TheDefaultActorStorageType; if (Name == "NonDefaultDistributedActorStorage") return Context.TheNonDefaultDistributedActorStorageType; if (Name == "Executor") return Context.TheExecutorType; if (Name == "NativeObject") return Context.TheNativeObjectType; if (Name == "BridgeObject") return Context.TheBridgeObjectType; if (Name == "SILToken") return Context.TheSILTokenType; if (Name == "UnsafeValueBuffer") return Context.TheUnsafeValueBufferType; if (Name == "PackIndex") return Context.ThePackIndexType; if (Name == "FPIEEE32") return Context.TheIEEE32Type; if (Name == "FPIEEE64") return Context.TheIEEE64Type; if (Name == "Word") return BuiltinIntegerType::getWordType(Context); if (Name == "IntLiteral") return Context.TheIntegerLiteralType; if (Name == "Int") { return BuiltinUnboundGenericType::get(TypeKind::BuiltinInteger, Context); } // Handle 'int8' and friends. if (Name.substr(0, 3) == "Int") { unsigned BitWidth; if (!Name.substr(3).getAsInteger(10, BitWidth) && BitWidth <= 2048 && BitWidth != 0) // Cap to prevent unsound things. return BuiltinIntegerType::get(BitWidth, Context); } // Target specific FP types. if (Name == "FPIEEE16") return Context.TheIEEE16Type; if (Name == "FPIEEE80") return Context.TheIEEE80Type; if (Name == "FPIEEE128") return Context.TheIEEE128Type; if (Name == "FPPPC128") return Context.ThePPC128Type; // AnyObject is the empty class-constrained existential. if (Name == "AnyObject") return CanType( ProtocolCompositionType::theAnyObjectType(Context)); return Type(); } /// getBuiltinBaseName - Decode the type list of a builtin (e.g. mul_Int32) and /// return the base name (e.g. "mul"). StringRef swift::getBuiltinBaseName(ASTContext &C, StringRef Name, SmallVectorImpl &Types) { // builtin-id ::= operation-id ('_' type-id)* for (StringRef::size_type Underscore = Name.find_last_of('_'); Underscore != StringRef::npos; Underscore = Name.find_last_of('_')) { // Check that the type parameter is well-formed and set it up for returning. // This allows operations with underscores in them, like "icmp_eq". Type Ty = getBuiltinType(C, Name.substr(Underscore + 1)); if (Ty.isNull()) break; Types.push_back(Ty); Name = Name.substr(0, Underscore); } std::reverse(Types.begin(), Types.end()); return Name; } namespace { /// AST synthesizers (see ASTSynthesis.h for the general pattern) /// for generics. enum UnrestrictedGenericParam { _unrestricted }; /// A synthesizer which generates a conformance requirement. template struct ConformsToSynthesizer { TypeS Type; ProtocolS Protocol; }; template constexpr ConformsToSynthesizer _conformsTo(TypeS type, ProtocolS protocol) { return {type, protocol}; } // Convenience macro to say that a type parameter has default // Copyable & Escapable requirements. #define _conformsToDefaults(INDEX) \ _conformsTo(_typeparam(INDEX), _copyable), \ _conformsTo(_typeparam(INDEX), _escapable) /// A synthesizer which generates a layout constraint requirement. template struct LayoutConstraintSynthesizer { TypeS Type; LayoutConstraint Constraint; }; template LayoutConstraintSynthesizer _layout(TypeS type, LayoutConstraint constraint) { return {type, constraint}; } static LayoutConstraint _classLayout() { return LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Class); } /// A synthesizer which generates a generic parameter list. template struct GenericParamListSynthesizer { VariadicSynthesizerStorage Params; }; template constexpr GenericParamListSynthesizer _generics(ParamS... params) { return {{params...}}; } struct CountGenericParameters { unsigned &Count; void operator()(UnrestrictedGenericParam _) const { Count++; } template void operator()(const ConformsToSynthesizer &_) const { // not a parameter } template void operator()(const LayoutConstraintSynthesizer &_) const { // not a parameter } }; } // end anonymous namespace static const char * const GenericParamNames[] = { "T", "U", "V", "W", "X", "Y", "Z" }; static GenericTypeParamDecl* createGenericParam(ASTContext &ctx, const char *name, unsigned index, bool isParameterPack = false) { ModuleDecl *M = ctx.TheBuiltinModule; Identifier ident = ctx.getIdentifier(name); auto paramKind = GenericTypeParamKind::Type; if (isParameterPack) { paramKind = GenericTypeParamKind::Pack; } return GenericTypeParamDecl::createImplicit( &M->getMainFile(FileUnitKind::Builtin), ident, /*depth*/ 0, index, paramKind); } /// Create a generic parameter list with multiple generic parameters. static GenericParamList *getGenericParams(ASTContext &ctx, unsigned numParameters, bool areParameterPacks = false) { assert(numParameters <= std::size(GenericParamNames)); SmallVector genericParams; for (unsigned i = 0; i != numParameters; ++i) genericParams.push_back(createGenericParam(ctx, GenericParamNames[i], i, areParameterPacks)); auto paramList = GenericParamList::create(ctx, SourceLoc(), genericParams, SourceLoc()); return paramList; } template static GenericParamList *synthesizeGenericParamList(SynthesisContext &SC, const GenericParamListSynthesizer ¶ms) { unsigned count = 0; params.Params.visit(CountGenericParameters{count}); auto paramList = getGenericParams(SC.Context, count); SC.GenericParams = paramList; return paramList; } namespace { struct CollectGenericParams { SynthesisContext &SC; SmallVector GenericParamTypes; SmallVector AddedRequirements; CollectGenericParams(SynthesisContext &SC) : SC(SC) { for (auto gp : SC.GenericParams->getParams()) { GenericParamTypes.push_back( gp->getDeclaredInterfaceType()->castTo()); } } void operator()(UnrestrictedGenericParam _) {} template void operator()(const ConformsToSynthesizer &conf) { auto type = synthesizeType(SC, conf.Type); auto protocolType = synthesizeType(SC, conf.Protocol); Requirement req = {RequirementKind::Conformance, type, protocolType}; AddedRequirements.push_back(req); } template void operator()(const LayoutConstraintSynthesizer &req) { auto type = synthesizeType(SC, req.Type); AddedRequirements.push_back({RequirementKind::Layout, type, req.Constraint}); } }; } // end anonymous namespace template static GenericSignature synthesizeGenericSignature(SynthesisContext &SC, const GenericParamListSynthesizer &list) { assert(SC.GenericParams && "synthesizeGenericParamList not called first"); CollectGenericParams collector(SC); list.Params.visit(collector); return buildGenericSignature(SC.Context, GenericSignature(), std::move(collector.GenericParamTypes), std::move(collector.AddedRequirements), /*allowInverses=*/false); } /// Build a builtin function declaration. /// /// This is a "legacy" interface; you should probably use one of /// the templated overloads below. static FuncDecl * getBuiltinFunction(Identifier Id, ArrayRef argTypes, Type ResType) { auto &Context = ResType->getASTContext(); ModuleDecl *M = Context.TheBuiltinModule; DeclContext *DC = &M->getMainFile(FileUnitKind::Builtin); SmallVector params; for (Type argType : argTypes) { auto PD = new (Context) ParamDecl(SourceLoc(), SourceLoc(), Identifier(), SourceLoc(), Identifier(), DC); PD->setSpecifier(ParamSpecifier::Default); PD->setInterfaceType(argType); PD->setImplicit(); params.push_back(PD); } auto *paramList = ParameterList::create(Context, params); DeclName Name(Context, Id, paramList); auto *const FD = FuncDecl::createImplicit( Context, StaticSpellingKind::None, Name, /*NameLoc=*/SourceLoc(), /*Async=*/false, /*Throws=*/false, /*thrownType=*/Type(), /*GenericParams=*/nullptr, paramList, ResType, DC); FD->setAccess(AccessLevel::Public); return FD; } template static FuncDecl * getBuiltinFunctionImpl(SynthesisContext &SC, Identifier id, GenericParamList *genericParams, GenericSignature signature, const ExtInfoS &extInfoS, const ParamsS ¶msS, const ResultS &resultS) { auto params = synthesizeParameterList(SC, paramsS); auto extInfo = synthesizeExtInfo(SC, extInfoS); auto resultType = synthesizeType(SC, resultS); DeclName name(SC.Context, id, params); auto *FD = FuncDecl::createImplicit( SC.Context, StaticSpellingKind::None, name, /*NameLoc=*/SourceLoc(), extInfo.isAsync(), extInfo.isThrowing(), /*thrownType=*/Type(), genericParams, params, resultType, SC.DC); FD->setAccess(AccessLevel::Public); FD->setGenericSignature(signature); return FD; } /// Synthesize a non-generic builtin function declaration. template static FuncDecl * getBuiltinFunction(ASTContext &ctx, Identifier id, const ExtInfoS &extInfoS, const ParamsS ¶msS, const ResultS &resultS) { ModuleDecl *M = ctx.TheBuiltinModule; DeclContext *DC = &M->getMainFile(FileUnitKind::Builtin); SynthesisContext SC(ctx, DC); return getBuiltinFunctionImpl(SC, id, nullptr, GenericSignature(), extInfoS, paramsS, resultS); } /// Synthesize a generic builtin function declaration. template static FuncDecl * getBuiltinFunction(ASTContext &ctx, Identifier id, const ExtInfoS &extInfoS, const GenericsS &genericsS, const ParamsS ¶msS, const ResultS &resultS) { ModuleDecl *M = ctx.TheBuiltinModule; DeclContext *DC = &M->getMainFile(FileUnitKind::Builtin); SynthesisContext SC(ctx, DC); auto genericParamList = synthesizeGenericParamList(SC, genericsS); auto genericSignature = synthesizeGenericSignature(SC, genericsS); return getBuiltinFunctionImpl(SC, id, genericParamList, genericSignature, extInfoS, paramsS, resultS); } namespace { enum class BuiltinThrowsKind : uint8_t { None, Throws, Rethrows }; } /// Build a builtin function declaration. static FuncDecl *getBuiltinGenericFunction( Identifier Id, ArrayRef ArgParamTypes, Type ResType, GenericParamList *GenericParams, GenericSignature Sig, bool Async, BuiltinThrowsKind Throws, Type ThrownError, bool SendingResult) { assert(GenericParams && "Missing generic parameters"); auto &Context = ResType->getASTContext(); ModuleDecl *M = Context.TheBuiltinModule; DeclContext *DC = &M->getMainFile(FileUnitKind::Builtin); SmallVector params; for (unsigned i = 0, e = ArgParamTypes.size(); i < e; ++i) { auto paramIfaceType = ArgParamTypes[i].getPlainType(); auto specifier = ParamDecl::getParameterSpecifierForValueOwnership( ArgParamTypes[i].getParameterFlags().getValueOwnership()); auto PD = new (Context) ParamDecl(SourceLoc(), SourceLoc(), Identifier(), SourceLoc(), Identifier(), DC); PD->setSpecifier(specifier); PD->setInterfaceType(paramIfaceType); PD->setImplicit(); params.push_back(PD); } auto *paramList = ParameterList::create(Context, params); DeclName Name(Context, Id, paramList); auto *const func = FuncDecl::createImplicit( Context, StaticSpellingKind::None, Name, /*NameLoc=*/SourceLoc(), Async, Throws != BuiltinThrowsKind::None, ThrownError, GenericParams, paramList, ResType, DC); func->setSendingResult(SendingResult); func->setAccess(AccessLevel::Public); func->setGenericSignature(Sig); if (Throws == BuiltinThrowsKind::Rethrows) func->getAttrs().add(new (Context) RethrowsAttr(/*ThrowsLoc*/ SourceLoc())); return func; } /// Build a getelementptr operation declaration. static ValueDecl *getGepRawOperation(ASTContext &ctx, Identifier id, Type argType) { // This is always "(i8*, IntTy) -> i8*" return getBuiltinFunction(ctx, id, _thin, _parameters(_rawPointer, argType), _rawPointer); } static ValueDecl *getStringObjectOrOperation(ASTContext &ctx, Identifier id, Type argType) { return getBuiltinFunction(ctx, id, _thin, _parameters(argType, argType), argType); } /// Build a binary operation declaration. static ValueDecl *getBinaryOperation(ASTContext &ctx, Identifier id, Type argType) { return getBuiltinFunction(ctx, id, _thin, _parameters(argType, argType), argType); } /// Build a declaration for a binary operation with overflow. static ValueDecl *getBinaryOperationWithOverflow(ASTContext &ctx, Identifier id, Type argType) { return getBuiltinFunction(ctx, id, _thin, _parameters(argType, argType, _int(1)), _tuple(argType, _int(1))); } static ValueDecl *getUnaryOperation(ASTContext &ctx, Identifier id, Type argType) { return getBuiltinFunction(ctx, id, _thin, _parameters(argType), argType); } /// Build a binary predicate declaration. static ValueDecl *getBinaryPredicate(ASTContext &ctx, Identifier id, Type argType) { if (auto vecType = argType->getAs()) { return getBuiltinFunction(ctx, id, _thin, _parameters(argType, argType), _vector(vecType->getNumElements(), _int(1))); } return getBuiltinFunction(ctx, id, _thin, _parameters(argType, argType), _int(1)); } /// Build a cast. There is some custom type checking here. static ValueDecl *getCastOperation(ASTContext &Context, Identifier Id, BuiltinValueKind VK, ArrayRef Types) { if (Types.empty() || Types.size() > 2) return nullptr; Type Input = Types[0]; Type Output = Types.size() == 2 ? Types[1] : Type(); // If both types are vectors, look through the vectors. Type CheckInput = Input; Type CheckOutput = Output; bool UnwrappedVector = false; auto InputVec = Input->getAs(); auto OutputVec = Output.isNull()? nullptr :Output->getAs(); if (InputVec && OutputVec && InputVec->getNumElements() == OutputVec->getNumElements()) { UnwrappedVector = true; CheckInput = InputVec->getElementType(); CheckOutput = OutputVec->getElementType(); } // Custom type checking. We know the one or two types have been subjected to // the "isBuiltinTypeOverloaded" predicate successfully. switch (VK) { default: llvm_unreachable("Not a cast operation"); case BuiltinValueKind::Trunc: if (CheckOutput.isNull() || !CheckInput->is() || !CheckOutput->is() || CheckInput->castTo()->getLeastWidth() <= CheckOutput->castTo()->getGreatestWidth()) return nullptr; break; case BuiltinValueKind::TruncOrBitCast: if (CheckOutput.isNull() || !CheckInput->is() || !CheckOutput->is() || CheckInput->castTo()->getLeastWidth() < CheckOutput->castTo()->getGreatestWidth()) return nullptr; break; case BuiltinValueKind::ZExt: case BuiltinValueKind::SExt: { if (CheckOutput.isNull() || !CheckInput->is() || !CheckOutput->is() || CheckInput->castTo()->getGreatestWidth() >= CheckOutput->castTo()->getLeastWidth()) return nullptr; break; } case BuiltinValueKind::ZExtOrBitCast: case BuiltinValueKind::SExtOrBitCast: { if (CheckOutput.isNull() || !CheckInput->is() || !CheckOutput->is() || CheckInput->castTo()->getGreatestWidth() > CheckOutput->castTo()->getLeastWidth()) return nullptr; break; } case BuiltinValueKind::FPToUI: case BuiltinValueKind::FPToSI: if (CheckOutput.isNull() || !CheckInput->is() || !CheckOutput->is()) return nullptr; break; case BuiltinValueKind::UIToFP: case BuiltinValueKind::SIToFP: if (CheckOutput.isNull() || !CheckInput->is() || !CheckOutput->is()) return nullptr; break; case BuiltinValueKind::FPTrunc: if (CheckOutput.isNull() || !CheckInput->is() || !CheckOutput->is() || CheckInput->castTo()->getFPKind() <= CheckOutput->castTo()->getFPKind()) return nullptr; break; case BuiltinValueKind::FPExt: if (CheckOutput.isNull() || !CheckInput->is() || !CheckOutput->is() || CheckInput->castTo()->getFPKind() >= CheckOutput->castTo()->getFPKind()) return nullptr; break; case BuiltinValueKind::PtrToInt: // FIXME: Do we care about vectors of pointers? if (!CheckOutput.isNull() || !CheckInput->is() || UnwrappedVector) return nullptr; Output = Input; Input = Context.TheRawPointerType; break; case BuiltinValueKind::IntToPtr: // FIXME: Do we care about vectors of pointers? if (!CheckOutput.isNull() || !CheckInput->is() || UnwrappedVector) return nullptr; Output = Context.TheRawPointerType; break; case BuiltinValueKind::BitCast: if (CheckOutput.isNull()) return nullptr; // Support float <-> int bitcast where the types are the same widths. if (auto *BIT = CheckInput->getAs()) if (auto *BFT = CheckOutput->getAs()) if (BIT->isFixedWidth() && BIT->getFixedWidth() == BFT->getBitWidth()) break; if (auto *BFT = CheckInput->getAs()) if (auto *BIT = CheckOutput->getAs()) if (BIT->isFixedWidth() && BIT->getFixedWidth() == BFT->getBitWidth()) break; // Support VecNxInt1 -> IntN bitcast for SIMD comparison results. if (auto *Vec = CheckInput->getAs()) if (auto *BIT = CheckOutput->getAs()) if (auto *Element = Vec->getElementType()->getAs()) if (Element->getFixedWidth() == 1 && BIT->isFixedWidth() && BIT->getFixedWidth() == Vec->getNumElements()) break; // And IntN -> VecNxInt1 for SIMDMask random generators. if (auto *Vec = CheckOutput->getAs()) if (auto *BIT = CheckInput->getAs()) if (auto *Element = Vec->getElementType()->getAs()) if (Element->getFixedWidth() == 1 && BIT->isFixedWidth() && BIT->getFixedWidth() == Vec->getNumElements()) break; // FIXME: Implement bitcast typechecking. llvm_unreachable("Bitcast not supported yet!"); return nullptr; } return getBuiltinFunction(Context, Id, _thin, _parameters(Input), Output); } namespace { class BuiltinFunctionBuilder { public: ASTContext &Context; private: GenericParamList *TheGenericParamList; SmallVector InterfaceParams; Type InterfaceResult; bool Async = false; BuiltinThrowsKind Throws = BuiltinThrowsKind::None; Type ThrownError; bool SendingResult = false; // Accumulate params and requirements here, so that we can call // `buildGenericSignature()` when `build()` is called. SmallVector genericParamTypes; SmallVector addedRequirements; public: BuiltinFunctionBuilder(ASTContext &ctx, unsigned numGenericParams = 1, bool wantsAdditionalAnyObjectRequirement = false, bool areParametersPacks = false) : Context(ctx) { TheGenericParamList = getGenericParams(ctx, numGenericParams, areParametersPacks); if (wantsAdditionalAnyObjectRequirement) { Requirement req(RequirementKind::Conformance, TheGenericParamList->getParams()[0]->getInterfaceType(), ctx.getAnyObjectConstraint()); addedRequirements.push_back(req); } for (auto gp : TheGenericParamList->getParams()) { genericParamTypes.push_back( gp->getDeclaredInterfaceType()->castTo()); } } template void addParameter(const G &generator, ParamSpecifier ownership = ParamSpecifier::Default, bool isSending = false) { Type gTyIface = generator.build(*this); auto flags = ParameterTypeFlags().withOwnershipSpecifier(ownership); auto p = AnyFunctionType::Param(gTyIface, Identifier(), flags); if (isSending) { p = p.withFlags(p.getParameterFlags().withSending(true)); } InterfaceParams.push_back(p); } template void setResult(const G &generator) { InterfaceResult = generator.build(*this); } template void setThrownError(const G &generator) { ThrownError = generator.build(*this); } template void addConformanceRequirement(const G &generator, KnownProtocolKind kp) { addConformanceRequirement(generator, Context.getProtocol(kp)); } template void addConformanceRequirement(const G &generator, ProtocolDecl *proto) { assert(proto && "missing protocol"); Requirement req(RequirementKind::Conformance, generator.build(*this), proto->getDeclaredInterfaceType()); addedRequirements.push_back(req); } void setAsync() { Async = true; } void setThrows() { Throws = BuiltinThrowsKind::Throws; } void setRethrows() { Throws = BuiltinThrowsKind::Rethrows; } void setSendingResult() { SendingResult = true; } FuncDecl *build(Identifier name) { auto GenericSig = buildGenericSignature( Context, GenericSignature(), std::move(genericParamTypes), std::move(addedRequirements), /*allowInverses=*/false); return getBuiltinGenericFunction(name, InterfaceParams, InterfaceResult, TheGenericParamList, GenericSig, Async, Throws, ThrownError, SendingResult); } // Don't use these generator classes directly; call the make{...} // functions which follow this class. struct ConcreteGenerator { Type TheType; Type build(BuiltinFunctionBuilder &builder) const { return TheType; } }; struct ParameterGenerator { unsigned Index; Type build(BuiltinFunctionBuilder &builder) const { return builder.TheGenericParamList->getParams()[Index] ->getDeclaredInterfaceType(); } }; struct LambdaGenerator { std::function TheFunction; Type build(BuiltinFunctionBuilder &builder) const { return TheFunction(builder); } }; template struct MetatypeGenerator { T Object; std::optional Repr; Type build(BuiltinFunctionBuilder &builder) const { return MetatypeType::get(Object.build(builder), Repr); } }; template struct PackExpansionGenerator { T Object; Type build(BuiltinFunctionBuilder &builder) const { auto patternTy = Object.build(builder); SmallVector packs; patternTy->getTypeParameterPacks(packs); return PackExpansionType::get(patternTy, packs[0]); } }; }; } // end anonymous namespace static BuiltinFunctionBuilder::ConcreteGenerator makeConcrete(Type type) { return { type }; } static BuiltinFunctionBuilder::ParameterGenerator makeGenericParam(unsigned index = 0) { return { index }; } template static BuiltinFunctionBuilder::LambdaGenerator makeTuple(const Gs & ...elementGenerators) { return { [=](BuiltinFunctionBuilder &builder) -> Type { TupleTypeElt elts[] = { elementGenerators.build(builder)... }; return TupleType::get(elts, builder.Context); } }; } template static BuiltinFunctionBuilder::LambdaGenerator makeBoundGenericType(NominalTypeDecl *decl, const Gs & ...argumentGenerators) { return { [=](BuiltinFunctionBuilder &builder) -> Type { Type args[] = { argumentGenerators.build(builder)... }; return BoundGenericType::get(decl, Type(), args); } }; } template static BuiltinFunctionBuilder::MetatypeGenerator makeMetatype(const T &object, std::optional repr = std::nullopt) { return { object, repr }; } template static BuiltinFunctionBuilder::PackExpansionGenerator makePackExpansion(const T &object) { return { object }; } /// Create a function with type T -> (). static ValueDecl *getRefCountingOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted, _conformsTo(_typeparam(0), _copyable)), _parameters(_typeparam(0)), _void); } static ValueDecl *getLoadOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted, _conformsTo(_typeparam(0), _copyable), _conformsTo(_typeparam(0), _escapable)), _parameters(_rawPointer), _typeparam(0)); } static ValueDecl *getTakeOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted, _conformsTo(_typeparam(0), _escapable)), _parameters(_rawPointer), _typeparam(0)); } static ValueDecl *getStoreOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted), _parameters(_owned(_typeparam(0)), _rawPointer), _void); } static ValueDecl *getDestroyOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted), _parameters(_metatype(_typeparam(0)), _rawPointer), _void); } static ValueDecl *getDestroyArrayOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted), _parameters(_metatype(_typeparam(0)), _rawPointer, _word), _void); } static ValueDecl *getAssumeAlignment(ASTContext &ctx, Identifier id) { // This is always "(Builtin.RawPointer, Builtin.Word) -> Builtin.RawPointer" return getBuiltinFunction(ctx, id, _thin, _parameters(_rawPointer, _word), _rawPointer); } static ValueDecl *getCopyArrayOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted, _conformsTo(_typeparam(0), _copyable)), _parameters(_metatype(_typeparam(0)), _rawPointer, _rawPointer, _word), _void); } static ValueDecl *getTransferArrayOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted), _parameters(_metatype(_typeparam(0)), _rawPointer, _rawPointer, _word), _void); } static ValueDecl *getIsUniqueOperation(ASTContext &ctx, Identifier id) { // (@inout T) -> Int1 return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted), _parameters(_inout(_typeparam(0))), _int(1)); } static ValueDecl *getEndCOWMutation(ASTContext &ctx, Identifier id) { // (@inout T) -> () return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted), _parameters(_inout(_typeparam(0))), _void); } static ValueDecl *getBindMemoryOperation(ASTContext &ctx, Identifier id) { FuncDecl *fd = getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted), _parameters(_rawPointer, _word, _metatype(_typeparam(0))), _word); fd->getAttrs().add(new (ctx) DiscardableResultAttr(/*implicit*/true)); return fd; } static ValueDecl *getRebindMemoryOperation(ASTContext &ctx, Identifier id) { FuncDecl *fd = getBuiltinFunction(ctx, id, _thin, _parameters(_rawPointer, _word), _word); fd->getAttrs().add(new (ctx) DiscardableResultAttr(/*implicit*/true)); return fd; } static ValueDecl *getAllocWithTailElemsOperation(ASTContext &Context, Identifier Id, int NumTailTypes) { if (NumTailTypes < 1 || 1 + NumTailTypes > (int)std::size(GenericParamNames)) return nullptr; BuiltinFunctionBuilder builder(Context, 1 + NumTailTypes); auto resultTy = makeGenericParam(0); builder.addConformanceRequirement(resultTy, KnownProtocolKind::Escapable); builder.addParameter(makeMetatype(resultTy)); for (int Idx = 0; Idx < NumTailTypes; ++Idx) { builder.addParameter(makeConcrete(BuiltinIntegerType::getWordType(Context))); builder.addParameter(makeMetatype(makeGenericParam(Idx + 1))); } builder.setResult(resultTy); return builder.build(Id); } static ValueDecl *getProjectTailElemsOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted, _unrestricted), _parameters(_typeparam(0), _metatype(_typeparam(1))), _rawPointer); } /// Build a getelementptr operation declaration. static ValueDecl *getGepOperation(ASTContext &ctx, Identifier id, Type argType) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted), _parameters(_rawPointer, argType, _metatype(_typeparam(0))), _rawPointer); } static ValueDecl *getGetTailAddrOperation(ASTContext &ctx, Identifier id, Type argType) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted, _unrestricted), _parameters(_rawPointer, argType, _metatype(_typeparam(0)), _metatype(_typeparam(1))), _rawPointer); } static ValueDecl *getBeginUnpairedAccessOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted), _parameters(_rawPointer, _rawPointer, _metatype(_typeparam(0))), _void); } static ValueDecl * getPerformInstantaneousReadAccessOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted), _parameters(_rawPointer, _metatype(_typeparam(0))), _void); } static ValueDecl *getEndUnpairedAccessOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _parameters(_rawPointer), _void); } static ValueDecl *getSizeOrAlignOfOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted), _parameters(_metatype(_typeparam(0))), _word); } static ValueDecl *getIsPODOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted), _parameters(_metatype(_typeparam(0))), _int(1)); } static ValueDecl *getIsConcrete(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted), _parameters(_metatype(_typeparam(0))), _int(1)); } static ValueDecl *getIsBitwiseTakable(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted), _parameters(_metatype(_typeparam(0))), _int(1)); } static ValueDecl *getIsOptionalOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted), _parameters(_metatype(_typeparam(0))), _int(1)); } static ValueDecl *getIsSameMetatypeOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _parameters(_existentialMetatype(_unconstrainedAny), _existentialMetatype(_unconstrainedAny)), _int(1)); } static ValueDecl *getAllocOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _parameters(_word, _word), _rawPointer); } static ValueDecl *getDeallocOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _parameters(_rawPointer, _word, _word), _void); } static ValueDecl *getStackAllocOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _parameters(_word, _word, _word), _rawPointer); } static ValueDecl *getStackDeallocOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _parameters(_rawPointer), _void); } // Obsolete: only there to be able to read old Swift.interface files which still // contain the builtin. static ValueDecl *getAllocVectorOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted), _parameters(_metatype(_typeparam(0)), _word), _rawPointer); } static ValueDecl *getFenceOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _parameters(), _void); } static ValueDecl *getIfdefOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _parameters(), _int(1)); } static ValueDecl *getVoidErrorOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _parameters(_error), _void); } static ValueDecl *getUnexpectedErrorOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _parameters(_error), _never); } static ValueDecl *getCmpXChgOperation(ASTContext &ctx, Identifier id, Type T) { return getBuiltinFunction(ctx, id, _thin, _parameters(_rawPointer, T, T), _tuple(T, _int(1))); } static ValueDecl *getAtomicRMWOperation(ASTContext &ctx, Identifier id, Type T) { return getBuiltinFunction(ctx, id, _thin, _parameters(_rawPointer, T), T); } static ValueDecl *getAtomicLoadOperation(ASTContext &ctx, Identifier id, Type T) { return getBuiltinFunction(ctx, id, _thin, _parameters(_rawPointer), T); } static ValueDecl *getAtomicStoreOperation(ASTContext &ctx, Identifier id, Type T) { return getBuiltinFunction(ctx, id, _thin, _parameters(_rawPointer, T), _void); } static ValueDecl *getNativeObjectCast(ASTContext &Context, Identifier Id, BuiltinValueKind BV) { ParamSpecifier ownership; Type builtinTy; switch (BV) { case BuiltinValueKind::CastToNativeObject: case BuiltinValueKind::UnsafeCastToNativeObject: case BuiltinValueKind::CastFromNativeObject: builtinTy = Context.TheNativeObjectType; ownership = ParamSpecifier::LegacyOwned; break; case BuiltinValueKind::BridgeToRawPointer: case BuiltinValueKind::BridgeFromRawPointer: builtinTy = Context.TheRawPointerType; ownership = ParamSpecifier::Default; break; default: llvm_unreachable("unexpected kind"); } BuiltinFunctionBuilder builder(Context); auto genParam = makeGenericParam(); // Add safety, unless requested. if (BV != BuiltinValueKind::UnsafeCastToNativeObject) { builder.addConformanceRequirement(genParam, KnownProtocolKind::Copyable); builder.addConformanceRequirement(genParam, KnownProtocolKind::Escapable); } if (BV == BuiltinValueKind::CastToNativeObject || BV == BuiltinValueKind::UnsafeCastToNativeObject || BV == BuiltinValueKind::BridgeToRawPointer) { builder.addParameter(genParam, ownership); builder.setResult(makeConcrete(builtinTy)); } else { builder.addParameter(makeConcrete(builtinTy), ownership); builder.setResult(genParam); } return builder.build(Id); } static ValueDecl *getCastToBridgeObjectOperation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted, _conformsToDefaults(0)), _parameters(_owned(_typeparam(0)), _word), _bridgeObject); } static ValueDecl *getCastFromBridgeObjectOperation(ASTContext &ctx, Identifier id, BuiltinValueKind BV) { switch (BV) { case BuiltinValueKind::CastReferenceFromBridgeObject: { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted, _conformsToDefaults(0)), _parameters(_owned(_bridgeObject)), _typeparam(0)); } case BuiltinValueKind::CastBitPatternFromBridgeObject: { return getBuiltinFunction(ctx, id, _thin, _parameters(_bridgeObject), _word); } default: llvm_unreachable("not a cast from bridge object op"); } } /// ClassifyBridgeObject has type: /// (Builtin.BridgeObject) -> (Builtin.Int1, Builtin.Int1). static ValueDecl *getClassifyBridgeObject(ASTContext &C, Identifier Id) { Type int1Ty = BuiltinIntegerType::get(1, C); Type resultTy = TupleType::get({ TupleTypeElt(int1Ty, C.getIdentifier("isObjCObject")), TupleTypeElt(int1Ty, C.getIdentifier("isObjCTaggedPointer")) }, C); return getBuiltinFunction(Id, { C.TheBridgeObjectType }, resultTy); } static ValueDecl *getValueToBridgeObject(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted, _conformsToDefaults(0)), _parameters(_typeparam(0)), _bridgeObject); } static ValueDecl *getCOWBufferForReading(ASTContext &C, Identifier Id) { // T -> T // BuiltinFunctionBuilder builder(C, 1, true); auto T = makeGenericParam(); builder.addConformanceRequirement(T, KnownProtocolKind::Escapable); builder.addParameter(T); builder.setResult(T); return builder.build(Id); } static ValueDecl *getTypePtrAuthDiscriminator(ASTContext &C, Identifier Id) { // (T.Type) -> Int64 BuiltinFunctionBuilder builder(C); builder.addParameter(makeMetatype(makeGenericParam())); Type Int64Ty = BuiltinIntegerType::get(64, C); builder.setResult(makeConcrete(Int64Ty)); return builder.build(Id); } static ValueDecl *getOnFastPath(ASTContext &Context, Identifier Id) { return getBuiltinFunction(Id, {}, TupleType::getEmpty(Context)); } static ValueDecl *getCastReferenceOperation(ASTContext &ctx, Identifier name) { // T -> U // SILGen and IRGen check additional constraints during lowering. BuiltinFunctionBuilder builder(ctx, 2); builder.addParameter(makeGenericParam(0), ParamSpecifier::LegacyOwned); auto resultTy = makeGenericParam(1); builder.addConformanceRequirement(resultTy, KnownProtocolKind::Escapable); builder.setResult(resultTy); return builder.build(name); } static ValueDecl *getReinterpretCastOperation(ASTContext &ctx, Identifier name) { // T -> U // SILGen and IRGen check additional constraints during lowering. BuiltinFunctionBuilder builder(ctx, 2); builder.addParameter(makeGenericParam(0), ParamSpecifier::LegacyOwned); auto resultTy = makeGenericParam(1); builder.addConformanceRequirement(resultTy, KnownProtocolKind::Escapable); builder.setResult(resultTy); return builder.build(name); } static ValueDecl *getZeroInitializerOperation(ASTContext &Context, Identifier Id) { // () -> T BuiltinFunctionBuilder builder(Context); auto genParam = makeGenericParam(); builder.addConformanceRequirement(genParam, KnownProtocolKind::Escapable); builder.setResult(genParam); return builder.build(Id); } static ValueDecl *getGetObjCTypeEncodingOperation(ASTContext &Context, Identifier Id) { // T.Type -> RawPointer BuiltinFunctionBuilder builder(Context); builder.addParameter(makeMetatype(makeGenericParam())); builder.setResult(makeConcrete(Context.TheRawPointerType)); return builder.build(Id); } static ValueDecl *getAutoDiffApplyDerivativeFunction( ASTContext &Context, Identifier Id, AutoDiffDerivativeFunctionKind kind, unsigned arity, bool throws, Type thrownType) { assert(arity >= 1); // JVP: // <...T...(arity), R> (@differentiable(_forward) (...T) throws -> R, ...T) // rethrows -> (R, (...T.TangentVector) -> R.TangentVector) // VJP: // <...T...(arity), R> (@differentiable(reverse) (...T) throws -> R, ...T) // rethrows -> (R, (R.TangentVector) -> ...T.TangentVector) unsigned numGenericParams = 1 + arity; BuiltinFunctionBuilder builder(Context, numGenericParams); // Get the `Differentiable` protocol. auto *diffableProto = Context.getProtocol(KnownProtocolKind::Differentiable); // Create type parameters and add conformance constraints. auto fnResultGen = makeGenericParam(arity); builder.addConformanceRequirement(fnResultGen, diffableProto); SmallVector fnParamGens; for (auto i : range(arity)) { auto T = makeGenericParam(i); builder.addConformanceRequirement(T, diffableProto); fnParamGens.push_back(T); } // Generator for the first argument, i.e. the `@differentiable` function. BuiltinFunctionBuilder::LambdaGenerator firstArgGen{ // Generator for the function type at the argument position, i.e. the // function being differentiated. [=, &fnParamGens](BuiltinFunctionBuilder &builder) -> Type { auto extInfo = FunctionType::ExtInfoBuilder() // TODO: Use `kind.getMinimalDifferentiabilityKind()`. .withDifferentiabilityKind(DifferentiabilityKind::Reverse) .withNoEscape() .withThrows(throws, thrownType) .build(); SmallVector params; for (auto ¶mGen : fnParamGens) params.push_back(FunctionType::Param(paramGen.build(builder))); return FunctionType::get(params, fnResultGen.build(builder), extInfo); }}; // Eagerly build the type of the first arg, then use that to compute the type // of the result. auto *diffFnType = firstArgGen.build(builder)->castTo(); diffFnType = diffFnType->getWithoutDifferentiability()->withExtInfo( diffFnType->getExtInfo().withNoEscape(false)); auto *paramIndices = IndexSubset::get( Context, SmallBitVector(diffFnType->getNumParams(), true)); // Generator for the resultant function type, i.e. the AD derivative function. BuiltinFunctionBuilder::LambdaGenerator resultGen{ [=](BuiltinFunctionBuilder &builder) -> Type { auto derivativeFnTy = diffFnType->getAutoDiffDerivativeFunctionType( paramIndices, kind, LookUpConformanceInModule()); return derivativeFnTy->getResult(); }}; builder.addParameter(firstArgGen); for (auto argGen : fnParamGens) builder.addParameter(argGen); if (throws) builder.setRethrows(); builder.setResult(resultGen); return builder.build(Id); } static ValueDecl *getAutoDiffApplyTransposeFunction( ASTContext &Context, Identifier Id, unsigned arity, bool throws, Type thrownType) { assert(arity >= 1); // <...T...(arity), R> // (@differentiable(_linear) (...T) throws -> R, ...R.TangentVector) // rethrows -> (...T.TangentVector) unsigned numGenericParams = 1 + arity; BuiltinFunctionBuilder builder(Context, numGenericParams); auto *diffableProto = Context.getProtocol(KnownProtocolKind::Differentiable); auto *addArithProto = Context.getProtocol(KnownProtocolKind::AdditiveArithmetic); // Create type parameters and add conformance constraints. auto linearFnResultGen = makeGenericParam(arity); builder.addConformanceRequirement(linearFnResultGen, diffableProto); builder.addConformanceRequirement(linearFnResultGen, addArithProto); SmallVector linearFnParamGens; for (auto i : range(arity)) { auto T = makeGenericParam(i); builder.addConformanceRequirement(T, diffableProto); builder.addConformanceRequirement(T, addArithProto); linearFnParamGens.push_back(T); } // Generator for the first argument, i.e. the `@differentiable(_linear)` // function. BuiltinFunctionBuilder::LambdaGenerator firstArgGen { // Generator for the function type at the argument position, i.e. the // function being differentiated. [=, &linearFnParamGens](BuiltinFunctionBuilder &builder) -> Type { FunctionType::ExtInfo ext; auto extInfo = FunctionType::ExtInfoBuilder() .withDifferentiabilityKind(DifferentiabilityKind::Linear) .withNoEscape() .withThrows(throws, thrownType) .build(); SmallVector params; for (auto ¶mGen : linearFnParamGens) params.push_back(FunctionType::Param(paramGen.build(builder))); // FIXME: Verify ExtInfo state is correct, not working by accident. FunctionType::ExtInfo info; auto innerFunction = FunctionType::get(params, linearFnResultGen.build(builder), info); return innerFunction->withExtInfo(extInfo); } }; builder.addParameter(firstArgGen); builder.addParameter(linearFnResultGen); if (throws) builder.setRethrows(); if (arity == 1) builder.setResult(linearFnParamGens.front()); else { BuiltinFunctionBuilder::LambdaGenerator tupleResultGen { [&](BuiltinFunctionBuilder &builder) -> Type { SmallVector tupleElts; for (auto linearFnParamGen : linearFnParamGens) tupleElts.push_back(linearFnParamGen.build(builder)); return TupleType::get(tupleElts, Context); } }; builder.setResult(tupleResultGen); } return builder.build(Id); } static ValueDecl *getGlobalStringTablePointer(ASTContext &Context, Identifier Id) { // String -> Builtin.RawPointer auto stringType = Context.getStringType(); return getBuiltinFunction(Id, {stringType}, Context.TheRawPointerType); } static ValueDecl *getConvertStrongToUnownedUnsafe(ASTContext &ctx, Identifier id) { // We actually want this: // // (T, inout unowned (unsafe) T) -> () // // But for simplicity, we actually accept T, U and do the checking // in the emission method that everything works up. This is a // builtin, so we can crash. BuiltinFunctionBuilder builder(ctx, 2); builder.addParameter(makeGenericParam(0)); builder.addParameter(makeGenericParam(1), ParamSpecifier::InOut); builder.setResult(makeConcrete(TupleType::getEmpty(ctx))); return builder.build(id); } static ValueDecl *getConvertUnownedUnsafeToGuaranteed(ASTContext &ctx, Identifier id) { // We actually want this: // /// (BaseT, @inout unowned(unsafe) T) -> T // // But for simplicity, we actually accept three generic params T, U and do the // checking in the emission method that everything works up. This is a // builtin, so we can crash. BuiltinFunctionBuilder builder(ctx, 3); builder.addParameter(makeGenericParam(0)); // Base builder.addParameter(makeGenericParam(1), ParamSpecifier::InOut); // Unmanaged auto resultTy = makeGenericParam(2); builder.addConformanceRequirement(resultTy, KnownProtocolKind::Escapable); builder.setResult(resultTy); // Guaranteed Result return builder.build(id); } static ValueDecl *getGetCurrentAsyncTask(ASTContext &ctx, Identifier id) { return getBuiltinFunction(id, { }, ctx.TheNativeObjectType); } static ValueDecl *getGetCurrentExecutor(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _async(_thin), _parameters(), _optional(_executor)); } static ValueDecl *getCancelAsyncTask(ASTContext &ctx, Identifier id) { return getBuiltinFunction( id, { ctx.TheNativeObjectType }, ctx.TheEmptyTupleType); } Type swift::getAsyncTaskAndContextType(ASTContext &ctx) { TupleTypeElt resultTupleElements[2] = { ctx.TheNativeObjectType, // task, ctx.TheRawPointerType // initial context }; return TupleType::get(resultTupleElements, ctx); } static ValueDecl *getCreateTask(ASTContext &ctx, Identifier id) { auto taskExecutorIsAvailable = ctx.getProtocol(swift::KnownProtocolKind::TaskExecutor) != nullptr; return getBuiltinFunction( ctx, id, _thin, _generics(_unrestricted, _conformsToDefaults(0)), _parameters( _label("flags", _swiftInt), _label("initialSerialExecutor", _defaulted(_optional(_executor), _nil)), _label("taskGroup", _defaulted(_optional(_rawPointer), _nil)), _label("initialTaskExecutor", _defaulted(_optional(_executor), _nil)), _label("initialTaskExecutorConsuming", _defaulted(_consuming(_optional(_bincompatType( /*if*/ taskExecutorIsAvailable, _existential(_taskExecutor), /*else*/ _executor))), _nil)), _label("taskName", _defaulted(_optional(_rawPointer), _nil)), _label("operation", _sending(_function(_async(_throws(_thick)), _typeparam(0), _parameters())))), _tuple(_nativeObject, _rawPointer)); } static ValueDecl *getCreateDiscardingTask(ASTContext &ctx, Identifier id) { auto taskExecutorIsAvailable = ctx.getProtocol(swift::KnownProtocolKind::TaskExecutor) != nullptr; return getBuiltinFunction( ctx, id, _thin, _parameters( _label("flags", _swiftInt), _label("initialSerialExecutor", _defaulted(_optional(_executor), _nil)), _label("taskGroup", _defaulted(_optional(_rawPointer), _nil)), _label("initialTaskExecutor", _defaulted(_optional(_executor), _nil)), _label("initialTaskExecutorConsuming", _defaulted(_consuming(_optional(_bincompatType( /*if*/ taskExecutorIsAvailable, _existential(_taskExecutor), /*else*/ _executor))), _nil)), _label("taskName", _defaulted(_optional(_rawPointer), _nil)), _label("operation", _sending(_function(_async(_throws(_thick)), _void, _parameters())))), _tuple(_nativeObject, _rawPointer)); } // Legacy entry point, prefer `createAsyncTask` static ValueDecl *getCreateAsyncTask(ASTContext &ctx, Identifier id, bool inGroup, bool withTaskExecutor, bool isDiscarding) { unsigned numGenericParams = isDiscarding ? 0 : 1; BuiltinFunctionBuilder builder(ctx, numGenericParams); builder.addParameter(makeConcrete(ctx.getIntType())); // 0 flags if (inGroup) { builder.addParameter(makeConcrete(ctx.TheRawPointerType)); // group } if (withTaskExecutor) { builder.addParameter(makeConcrete(ctx.TheExecutorType)); // executor } bool areSendingArgsEnabled = ctx.LangOpts.hasFeature(Feature::SendingArgsAndResults); auto extInfo = ASTExtInfoBuilder() .withAsync() .withThrows() .withSendable(!areSendingArgsEnabled) .build(); Type operationResultType; if (isDiscarding) { operationResultType = TupleType::getEmpty(ctx); // () } else { operationResultType = makeGenericParam().build(builder); // } builder.addParameter( makeConcrete(FunctionType::get({}, operationResultType, extInfo)), ParamSpecifier::Default, areSendingArgsEnabled /*isSending*/); // operation builder.setResult(makeConcrete(getAsyncTaskAndContextType(ctx))); return builder.build(id); } static ValueDecl *getTaskRunInline(ASTContext &ctx, Identifier id) { return getBuiltinFunction( ctx, id, _thin, _generics(_unrestricted, _conformsToDefaults(0)), _parameters( _function(_async(_noescape(_thick)), _typeparam(0), _parameters())), _typeparam(0)); } static ValueDecl *getConvertTaskToJob(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _parameters(_owned(_nativeObject)), _job); } static ValueDecl *getDefaultActorInitDestroy(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _parameters(_nativeObject), _void); } static ValueDecl *getDistributedActorInitializeRemote(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted, _conformsToDefaults(0)), // TODO(distributed): restrict to DistributedActor _parameters(_metatype(_typeparam(0))), _rawPointer); } static ValueDecl *getResumeContinuationReturning(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted, _conformsToDefaults(0)), _parameters(_rawUnsafeContinuation, _owned(_typeparam(0))), _void); } static ValueDecl *getResumeContinuationThrowing(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _parameters(_rawUnsafeContinuation, _owned(_error)), _void); } static ValueDecl *getStartAsyncLet(ASTContext &ctx, Identifier id) { ModuleDecl *M = ctx.TheBuiltinModule; DeclContext *DC = &M->getMainFile(FileUnitKind::Builtin); SynthesisContext SC(ctx, DC); BuiltinFunctionBuilder builder(ctx); auto genericParam = makeGenericParam().build(builder); // // AsyncLet* builder.addParameter(makeConcrete(OptionalType::get(ctx.TheRawPointerType))); // TaskOptionRecord* builder.addParameter(makeConcrete(OptionalType::get(ctx.TheRawPointerType))); // If sending results are enabled, make async let return a set // value. // // NOTE: If our actual returned function does not return something that is // sent, we will emit an error in Sema. In the case of SILGen, we just in such // a case want to thunk and not emit an error. So in such a case, we always // make this builtin take a sending result. bool hasSendingResult = ctx.LangOpts.hasFeature(Feature::RegionBasedIsolation); // operation async function pointer: () async throws -> sending T auto extInfo = ASTExtInfoBuilder() .withAsync() .withThrows() .withNoEscape() .withSendingResult(hasSendingResult) .build(); builder.addParameter( makeConcrete(FunctionType::get({ }, genericParam, extInfo))); // -> Builtin.RawPointer builder.setResult(makeConcrete(synthesizeType(SC, _rawPointer))); return builder.build(id); } static ValueDecl *getEndAsyncLet(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _parameters(_rawPointer), _void); } static ValueDecl *getCreateTaskGroup(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted, _conformsToDefaults(0)), _parameters(_metatype(_typeparam(0))), _rawPointer); } static ValueDecl *getCreateTaskGroupWithFlags(ASTContext &ctx, Identifier id) { ModuleDecl *M = ctx.TheBuiltinModule; DeclContext *DC = &M->getMainFile(FileUnitKind::Builtin); SynthesisContext SC(ctx, DC); BuiltinFunctionBuilder builder(ctx); // int builder.addParameter(makeConcrete(ctx.getIntType())); // 0 flags // T.self builder.addParameter(makeMetatype(makeGenericParam(0))); // 1 ChildTaskResult.Type // -> Builtin.RawPointer builder.setResult(makeConcrete(synthesizeType(SC, _rawPointer))); return builder.build(id); } static ValueDecl *getDestroyTaskGroup(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _parameters(_rawPointer), _void); } static ValueDecl *getBuildMainActorExecutorRef(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _parameters(), _executor); } static ValueDecl *getBuildDefaultActorExecutorRef(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted, _conformsToDefaults(0), _layout(_typeparam(0), _classLayout())), _parameters(_typeparam(0)), _executor); } static ValueDecl *getExtractFunctionIsolation(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted, _conformsToDefaults(0)), _parameters(_typeparam(0)), _optional(_existential(_actor))); } static ValueDecl *getTargetOSVersionAtLeast(ASTContext &Context, Identifier Id) { auto int32Type = BuiltinIntegerType::get(32, Context); return getBuiltinFunction(Id, {int32Type, int32Type, int32Type}, int32Type); } static ValueDecl *getTargetVariantOSVersionAtLeast(ASTContext &Context, Identifier Id) { auto int32Type = BuiltinIntegerType::get(32, Context); return getBuiltinFunction(Id, {int32Type, int32Type, int32Type}, int32Type); } static ValueDecl * getTargetOSVersionOrVariantOSVersionAtLeast(ASTContext &Context, Identifier Id) { auto int32Type = BuiltinIntegerType::get(32, Context); return getBuiltinFunction(Id, {int32Type, int32Type, int32Type, int32Type, int32Type, int32Type}, int32Type); } static ValueDecl *getBuildOrdinaryTaskExecutorRef(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted, _conformsTo(_typeparam(0), _taskExecutor)), _parameters(_typeparam(0)), _executor); } static ValueDecl *getBuildOrdinarySerialExecutorRef(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted, _conformsTo(_typeparam(0), _serialExecutor)), _parameters(_typeparam(0)), _executor); } static ValueDecl *getBuildComplexEqualitySerialExecutorRef(ASTContext &ctx, Identifier id) { return getBuiltinFunction(ctx, id, _thin, _generics(_unrestricted, _conformsTo(_typeparam(0), _serialExecutor)), _parameters(_typeparam(0)), _executor); } static ValueDecl *getAutoDiffCreateLinearMapContext(ASTContext &ctx, Identifier id) { return getBuiltinFunction( ctx, id, _thin, _generics(_unrestricted, _conformsToDefaults(0)), _parameters(_metatype(_typeparam(0))), _nativeObject); } static ValueDecl *getAutoDiffProjectTopLevelSubcontext(ASTContext &ctx, Identifier id) { return getBuiltinFunction( id, {ctx.TheNativeObjectType}, ctx.TheRawPointerType); } static ValueDecl *getAutoDiffAllocateSubcontext(ASTContext &ctx, Identifier id) { return getBuiltinFunction( ctx, id, _thin, _generics(_unrestricted, _conformsToDefaults(0)), _parameters(_nativeObject, _metatype(_typeparam(0))), _rawPointer); } static ValueDecl *getPoundAssert(ASTContext &Context, Identifier Id) { auto int1Type = BuiltinIntegerType::get(1, Context); auto optionalRawPointerType = BoundGenericEnumType::get( Context.getOptionalDecl(), Type(), {Context.TheRawPointerType}); return getBuiltinFunction(Id, {int1Type, optionalRawPointerType}, Context.TheEmptyTupleType); } static ValueDecl *getTSanInoutAccess(ASTContext &Context, Identifier Id) { // T -> () BuiltinFunctionBuilder builder(Context); builder.addParameter(makeGenericParam()); builder.setResult(makeConcrete(Context.TheEmptyTupleType)); return builder.build(Id); } static ValueDecl *getAddressOfOperation(ASTContext &Context, Identifier Id) { // (@inout T) -> RawPointer BuiltinFunctionBuilder builder(Context); builder.addParameter(makeGenericParam(), ParamSpecifier::InOut); builder.setResult(makeConcrete(Context.TheRawPointerType)); return builder.build(Id); } static ValueDecl *getAddressOfBorrowOperation(ASTContext &Context, Identifier Id) { // (T) -> RawPointer BuiltinFunctionBuilder builder(Context); builder.addParameter(makeGenericParam()); builder.setResult(makeConcrete(Context.TheRawPointerType)); return builder.build(Id); } static ValueDecl *getTypeJoinOperation(ASTContext &Context, Identifier Id) { // (T.Type, U.Type) -> V.Type BuiltinFunctionBuilder builder(Context, 3); builder.addParameter(makeMetatype(makeGenericParam(0))); builder.addParameter(makeMetatype(makeGenericParam(1))); builder.setResult(makeMetatype(makeGenericParam(2))); return builder.build(Id); } static ValueDecl *getTypeJoinInoutOperation(ASTContext &Context, Identifier Id) { // (inout T, U.Type) -> V.Type BuiltinFunctionBuilder builder(Context, 3); builder.addParameter(makeGenericParam(0), ParamSpecifier::InOut); builder.addParameter(makeMetatype(makeGenericParam(1))); builder.setResult(makeMetatype(makeGenericParam(2))); return builder.build(Id); } static ValueDecl *getTypeJoinMetaOperation(ASTContext &Context, Identifier Id) { // (T.Type, U.Type) -> V.Type BuiltinFunctionBuilder builder(Context, 3); builder.addParameter(makeMetatype(makeGenericParam(0))); builder.addParameter(makeMetatype(makeGenericParam(1))); builder.setResult(makeMetatype(makeGenericParam(2))); return builder.build(Id); } static ValueDecl *getTriggerFallbackDiagnosticOperation(ASTContext &Context, Identifier Id) { // () -> Void return getBuiltinFunction(Id, {}, Context.TheEmptyTupleType); } static ValueDecl *getCanBeObjCClassOperation(ASTContext &Context, Identifier Id) { // T.Type -> Builtin.Int8 BuiltinFunctionBuilder builder(Context); builder.addParameter(makeMetatype(makeGenericParam())); builder.setResult(makeConcrete(BuiltinIntegerType::get(8, Context))); return builder.build(Id); } static ValueDecl *getLegacyCondFailOperation(ASTContext &C, Identifier Id) { // Int1 -> () auto CondTy = BuiltinIntegerType::get(1, C); auto VoidTy = TupleType::getEmpty(C); return getBuiltinFunction(Id, {CondTy}, VoidTy); } static ValueDecl *getCondFailOperation(ASTContext &C, Identifier Id) { // Int1 -> () auto CondTy = BuiltinIntegerType::get(1, C); auto MsgTy = C.TheRawPointerType; auto VoidTy = TupleType::getEmpty(C); return getBuiltinFunction(Id, {CondTy, MsgTy}, VoidTy); } static ValueDecl *getAssertConfOperation(ASTContext &C, Identifier Id) { // () -> Int32 auto Int32Ty = BuiltinIntegerType::get(32, C); return getBuiltinFunction(Id, {}, Int32Ty); } static ValueDecl *getFixLifetimeOperation(ASTContext &C, Identifier Id) { // T -> () BuiltinFunctionBuilder builder(C); builder.addParameter(makeGenericParam()); builder.setResult(makeConcrete(TupleType::getEmpty(C))); return builder.build(Id); } static ValueDecl *getExtractElementOperation(ASTContext &Context, Identifier Id, Type FirstTy, Type SecondTy) { // (Vector, Int32) -> T auto VecTy = FirstTy->getAs(); if (!VecTy) return nullptr; auto IndexTy = SecondTy->getAs(); if (!IndexTy || !IndexTy->isFixedWidth() || IndexTy->getFixedWidth() != 32) return nullptr; Type ResultTy = VecTy->getElementType(); return getBuiltinFunction(Id, { VecTy, IndexTy }, ResultTy); } static ValueDecl *getInsertElementOperation(ASTContext &Context, Identifier Id, Type FirstTy, Type SecondTy, Type ThirdTy) { // (Vector, T, Int32) -> Vector auto VecTy = FirstTy->getAs(); if (!VecTy) return nullptr; auto ElementTy = VecTy->getElementType(); if (!SecondTy->isEqual(ElementTy)) return nullptr; auto IndexTy = ThirdTy->getAs(); if (!IndexTy || !IndexTy->isFixedWidth() || IndexTy->getFixedWidth() != 32) return nullptr; Type ArgElts[] = { VecTy, ElementTy, IndexTy }; return getBuiltinFunction(Id, ArgElts, VecTy); } static ValueDecl *getSelectOperation(ASTContext &Context, Identifier Id, Type PredTy, Type ValueTy) { // Check for (NxInt1, NxTy, NxTy) -> NxTy auto VecPredTy = PredTy->getAs(); if (VecPredTy) { // ValueTy must also be vector type with matching element count. auto VecValueTy = ValueTy->getAs(); if (!VecValueTy || VecPredTy->getNumElements() != VecValueTy->getNumElements()) return nullptr; } else { // Type is (Int1, Ty, Ty) -> Ty auto IntTy = PredTy->getAs(); if (!IntTy || !IntTy->isFixedWidth() || IntTy->getFixedWidth() != 1) return nullptr; } Type ArgElts[] = { PredTy, ValueTy, ValueTy }; return getBuiltinFunction(Id, ArgElts, ValueTy); } static ValueDecl *getShuffleVectorOperation(ASTContext &Context, Identifier Id, Type FirstTy, Type SecondTy) { // (Vector, Vector, Vector Vector auto VecTy = FirstTy->getAs(); if (!VecTy) return nullptr; auto ElementTy = VecTy->getElementType(); auto IndexTy = SecondTy->getAs(); if (!IndexTy) return nullptr; auto IdxElTy = IndexTy->getElementType()->getAs(); if (!IdxElTy || !IdxElTy->isFixedWidth() || IdxElTy->getFixedWidth() != 32) return nullptr; Type ArgElts[] = { VecTy, VecTy, IndexTy }; Type ResultTy = BuiltinVectorType::get(Context, ElementTy, IndexTy->getNumElements()); return getBuiltinFunction(Id, ArgElts, ResultTy); } static ValueDecl *getStaticReportOperation(ASTContext &Context, Identifier Id) { auto BoolTy = BuiltinIntegerType::get(1, Context); auto MessageTy = Context.TheRawPointerType; Type ArgElts[] = { BoolTy, BoolTy, MessageTy }; Type ResultTy = TupleType::getEmpty(Context); return getBuiltinFunction(Id, ArgElts, ResultTy); } static ValueDecl *getCheckedTruncOperation(ASTContext &Context, Identifier Id, Type InputTy, Type OutputTy, bool AllowLiteral) { auto InTy = InputTy->getAs(); auto OutTy = OutputTy->getAs(); if (!InTy || !OutTy) return nullptr; if (isa(InTy)) { if (!AllowLiteral) return nullptr; } else if (cast(InTy)->getLeastWidth() < OutTy->getGreatestWidth()) { return nullptr; } Type OverflowBitTy = BuiltinIntegerType::get(1, Context); TupleTypeElt ResultElts[] = { Type(OutTy), OverflowBitTy }; Type ResultTy = TupleType::get(ResultElts, Context); return getBuiltinFunction(Id, { InTy }, ResultTy); } static ValueDecl *getIntToFPWithOverflowOperation(ASTContext &Context, Identifier Id, Type InputTy, Type OutputTy) { auto InTy = InputTy->getAs(); auto OutTy = OutputTy->getAs(); if (!InTy || !OutTy) return nullptr; return getBuiltinFunction(Id, { InTy }, OutTy); } static ValueDecl *getBitWidthOperation( ASTContext &ctx, Identifier id, Type valueTy ) { if (!valueTy->getAs()) return nullptr; return getBuiltinFunction(ctx, id, _thin, _parameters(valueTy), _word); } static ValueDecl *getIsNegativeOperation( ASTContext &ctx, Identifier id, Type valueTy ) { if (!valueTy->getAs()) return nullptr; return getBuiltinFunction(ctx, id, _thin, _parameters(valueTy), _int(1)); } static ValueDecl *getWordAtIndexOperation( ASTContext &ctx, Identifier id, Type valueTy ) { if (!valueTy->getAs()) return nullptr; return getBuiltinFunction(ctx, id, _thin, _parameters(valueTy, _word), _word); } static ValueDecl *getUnreachableOperation(ASTContext &Context, Identifier Id) { auto NeverTy = Context.getNeverType(); if (!NeverTy) return nullptr; // () -> Never return getBuiltinFunction(Id, {}, NeverTy); } static ValueDecl *getOnceOperation(ASTContext &Context, Identifier Id, bool withContext) { // (RawPointer, @convention(c) (Context) -> ()[, Context]) -> () auto HandleTy = Context.TheRawPointerType; auto VoidTy = Context.TheEmptyTupleType; SmallVector CFuncParams; swift::CanType ContextTy = Context.TheRawPointerType; auto ContextArg = FunctionType::Param(ContextTy); CFuncParams.push_back(ContextArg); auto Rep = FunctionTypeRepresentation::CFunctionPointer; auto ClangType = Context.getClangFunctionType(CFuncParams, VoidTy, Rep); auto Thin = FunctionType::ExtInfoBuilder(FunctionTypeRepresentation::CFunctionPointer, /*throws*/ false, Type()) .withClangFunctionType(ClangType) .build(); auto BlockTy = FunctionType::get(CFuncParams, VoidTy, Thin); SmallVector ArgTypes = {HandleTy, BlockTy}; if (withContext) { ArgTypes.push_back(ContextTy); return getBuiltinFunction(Id, ArgTypes, VoidTy); } return getBuiltinFunction(Id, ArgTypes, Context.TheSILTokenType); } static ValueDecl *getPolymorphicBinaryOperation(ASTContext &ctx, Identifier id) { BuiltinFunctionBuilder builder(ctx); // Builtins of the form: func binOp(_ t: T, _ t: T) -> T auto genericParam = makeGenericParam(); builder.addConformanceRequirement(genericParam, KnownProtocolKind::Escapable); builder.addParameter(genericParam); builder.addParameter(genericParam); builder.setResult(genericParam); return builder.build(id); } static ValueDecl *getWithUnsafeContinuation(ASTContext &ctx, Identifier id, bool throws) { BuiltinFunctionBuilder builder(ctx); auto contTy = ctx.TheRawUnsafeContinuationType; SmallVector params; params.emplace_back(contTy); auto voidTy = ctx.TheEmptyTupleType; auto extInfo = FunctionType::ExtInfoBuilder().withNoEscape().build(); auto *fnTy = FunctionType::get(params, voidTy, extInfo); builder.addParameter(makeConcrete(fnTy)); auto resultTy = makeGenericParam(); builder.addConformanceRequirement(resultTy, KnownProtocolKind::Escapable); builder.setResult(resultTy); builder.setAsync(); if (throws) builder.setThrows(); builder.setSendingResult(); return builder.build(id); } static ValueDecl *getHopToActor(ASTContext &ctx, Identifier id) { BuiltinFunctionBuilder builder(ctx); auto *actorProto = ctx.getProtocol(KnownProtocolKind::Actor); // Create type parameters and add conformance constraints. auto actorParam = makeGenericParam(); builder.addParameter(actorParam); builder.addConformanceRequirement(actorParam, actorProto); builder.setResult(makeConcrete(TupleType::getEmpty(ctx))); return builder.build(id); } static ValueDecl *getFlowSensitiveSelfIsolation( ASTContext &ctx, Identifier id, bool isDistributed ) { BuiltinFunctionBuilder builder(ctx); return getBuiltinFunction( ctx, id, _thin, _generics(_unrestricted, _conformsToDefaults(0), _conformsTo(_typeparam(0), isDistributed ? _distributedActor : _actor)), _parameters(_typeparam(0)), _optional(_existential(_actor))); } static ValueDecl *getDistributedActorAsAnyActor(ASTContext &ctx, Identifier id) { BuiltinFunctionBuilder builder(ctx); auto *distributedActorProto = ctx.getProtocol(KnownProtocolKind::DistributedActor); auto *actorProto = ctx.getProtocol(KnownProtocolKind::Actor); // Create type parameters and add conformance constraints. auto actorParam = makeGenericParam(); builder.addParameter(actorParam); builder.addConformanceRequirement(actorParam, distributedActorProto); builder.setResult(makeConcrete(actorProto->getDeclaredExistentialType())); return builder.build(id); } static ValueDecl *getPackLength(ASTContext &ctx, Identifier id) { BuiltinFunctionBuilder builder(ctx, /* genericParamCount */ 1, /* anyObject */ false, /* areParametersPack */ true); auto paramTy = makeMetatype(makeTuple(makePackExpansion(makeGenericParam()))); builder.addParameter(paramTy); builder.setResult(makeConcrete(BuiltinIntegerType::getWordType(ctx))); return builder.build(id); } static ValueDecl *getGetEnumTag(ASTContext &ctx, Identifier id) { BuiltinFunctionBuilder builder(ctx, /* genericParamCount */ 1); auto paramTy = makeGenericParam(); builder.addParameter(paramTy); builder.setResult(makeConcrete(BuiltinIntegerType::get(32, ctx))); return builder.build(id); } static ValueDecl *getInjectEnumTag(ASTContext &ctx, Identifier id) { BuiltinFunctionBuilder builder(ctx, /* genericParamCount */ 1); builder.addParameter(makeGenericParam(), ParamSpecifier::InOut); builder.addParameter(makeConcrete(BuiltinIntegerType::get(32, ctx))); builder.setResult(makeConcrete(TupleType::getEmpty(ctx))); return builder.build(id); } static ValueDecl *getAddressOfRawLayout(ASTContext &ctx, Identifier id) { BuiltinFunctionBuilder builder(ctx, /* genericParamCount */ 1); builder.addParameter(makeGenericParam(), ParamSpecifier::Borrowing); builder.setResult(makeConcrete(ctx.TheRawPointerType)); return builder.build(id); } static ValueDecl *getEmplace(ASTContext &ctx, Identifier id) { BuiltinFunctionBuilder builder(ctx, /* genericParamCount */ 2); // ( // _: (Builtin.RawPointer) throws(E) -> () // ) throws(E) -> T auto T = makeGenericParam(0); builder.addConformanceRequirement(T, KnownProtocolKind::Escapable); auto E = makeGenericParam(1); builder.addConformanceRequirement(E, KnownProtocolKind::Error); auto extInfo = ASTExtInfoBuilder() .withNoEscape() .withThrows(/* throws */ true, E.build(builder)) .build(); auto fnParamTy = FunctionType::get(FunctionType::Param(ctx.TheRawPointerType), ctx.TheEmptyTupleType, extInfo); builder.addParameter(makeConcrete(fnParamTy), ParamSpecifier::Borrowing); builder.setResult(T); builder.setThrows(); builder.setThrownError(E); return builder.build(id); } /// An array of the overloaded builtin kinds. static const OverloadedBuiltinKind OverloadedBuiltinKinds[] = { OverloadedBuiltinKind::None, // There's deliberately no BUILTIN clause here so that we'll blow up // if new builtin categories are added there and not here. #define BUILTIN_CAST_OPERATION(id, attrs, name) \ OverloadedBuiltinKind::Special, #define BUILTIN_CAST_OR_BITCAST_OPERATION(id, attrs, name) \ OverloadedBuiltinKind::Special, #define BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(id, name, attrs, overload) \ OverloadedBuiltinKind::overload, #define BUILTIN_BINARY_OPERATION_POLYMORPHIC(id, name) \ OverloadedBuiltinKind::Special, #define BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(id, name, _, attrs, overload) \ OverloadedBuiltinKind::overload, #define BUILTIN_BINARY_PREDICATE(id, name, attrs, overload) \ OverloadedBuiltinKind::overload, #define BUILTIN_UNARY_OPERATION(id, name, attrs, overload) \ OverloadedBuiltinKind::overload, #define BUILTIN_SIL_OPERATION(id, name, overload) \ OverloadedBuiltinKind::overload, #define BUILTIN_MISC_OPERATION(id, name, attrs, overload) \ OverloadedBuiltinKind::overload, #define BUILTIN_SANITIZER_OPERATION(id, name, attrs) \ OverloadedBuiltinKind::None, #define BUILTIN_TYPE_CHECKER_OPERATION(id, name) OverloadedBuiltinKind::Special, #define BUILTIN_TYPE_TRAIT_OPERATION(id, name) \ OverloadedBuiltinKind::Special, #define BUILTIN_RUNTIME_CALL(id, attrs, name) \ OverloadedBuiltinKind::Special, #include "swift/AST/Builtins.def" }; /// Determines if a builtin type falls within the given category. inline bool isBuiltinTypeOverloaded(Type T, OverloadedBuiltinKind OK) { switch (OK) { case OverloadedBuiltinKind::None: return false; // always fail. case OverloadedBuiltinKind::Integer: return T->is(); case OverloadedBuiltinKind::IntegerOrVector: return T->is() || (T->is() && T->castTo()->getElementType() ->is()); case OverloadedBuiltinKind::IntegerOrRawPointer: return T->is() || T->is(); case OverloadedBuiltinKind::IntegerOrRawPointerOrVector: return T->is() || T->is() || (T->is() && T->castTo()->getElementType() ->is()); case OverloadedBuiltinKind::Float: return T->is(); case OverloadedBuiltinKind::FloatOrVector: return T->is() || (T->is() && T->castTo()->getElementType() ->is()); case OverloadedBuiltinKind::Special: return true; } llvm_unreachable("bad overloaded builtin kind"); } bool swift::canBuiltinBeOverloadedForType(BuiltinValueKind ID, Type Ty) { if (ID == BuiltinValueKind::None) return false; return isBuiltinTypeOverloaded(Ty, OverloadedBuiltinKinds[unsigned(ID)]); } /// Table of string intrinsic names indexed by enum value. static const char *const IntrinsicNameTable[] = { "not_intrinsic", #define GET_INTRINSIC_NAME_TABLE #include "llvm/IR/IntrinsicImpl.inc" #undef GET_INTRINSIC_NAME_TABLE }; #define GET_INTRINSIC_TARGET_DATA #include "llvm/IR/IntrinsicImpl.inc" #undef GET_INTRINSIC_TARGET_DATA llvm::Intrinsic::ID swift::getLLVMIntrinsicID(StringRef InName) { using namespace llvm; // Swift intrinsic names start with int_. if (!InName.starts_with("int_")) return llvm::Intrinsic::not_intrinsic; InName = InName.drop_front(strlen("int_")); // Prepend "llvm." and change _ to . in name. SmallString<128> NameS; NameS.append("llvm."); for (char C : InName) NameS.push_back(C == '_' ? '.' : C); const char *Name = NameS.c_str(); ArrayRef NameTable(&IntrinsicNameTable[1], TargetInfos[1].Offset); int Idx = Intrinsic::lookupLLVMIntrinsicByName(NameTable, Name); return static_cast(Idx + 1); } llvm::Intrinsic::ID swift::getLLVMIntrinsicIDForBuiltinWithOverflow(BuiltinValueKind ID) { switch (ID) { default: break; case BuiltinValueKind::SAddOver: return llvm::Intrinsic::sadd_with_overflow; case BuiltinValueKind::UAddOver: return llvm::Intrinsic::uadd_with_overflow; case BuiltinValueKind::SSubOver: return llvm::Intrinsic::ssub_with_overflow; case BuiltinValueKind::USubOver: return llvm::Intrinsic::usub_with_overflow; case BuiltinValueKind::SMulOver: return llvm::Intrinsic::smul_with_overflow; case BuiltinValueKind::UMulOver: return llvm::Intrinsic::umul_with_overflow; } llvm_unreachable("Cannot convert the overflow builtin to llvm intrinsic."); } namespace { class IntrinsicTypeDecoder { ArrayRef &Table; ArrayRef TypeArguments; ASTContext &Context; public: IntrinsicTypeDecoder(ArrayRef &table, ArrayRef typeArguments, ASTContext &ctx) : Table(table), TypeArguments(typeArguments), Context(ctx) {} Type decodeImmediate(); /// Return the type argument at the given index. Type getTypeArgument(unsigned index) { if (index >= TypeArguments.size()) return Type(); return TypeArguments[index]; } /// Create a pointer type. Type makePointer(Type eltType, unsigned addrspace) { // Reject non-default address space pointers. if (addrspace) return Type(); // For now, always ignore the element type and use RawPointer. return Context.TheRawPointerType; } /// Create a vector type. Type makeVector(Type eltType, unsigned width) { return BuiltinVectorType::get(Context, eltType, width); } /// Return the first type or, if the second type is a vector type, a vector /// of the first type of the same length as the second type. Type maybeMakeVectorized(Type eltType, Type maybeVectorType) { if (auto vectorType = maybeVectorType->getAs()) { return makeVector(eltType, vectorType->getNumElements()); } return eltType; } }; } // end anonymous namespace static Type DecodeIntrinsicType(ArrayRef &table, ArrayRef typeArguments, ASTContext &ctx) { return IntrinsicTypeDecoder(table, typeArguments, ctx).decodeImmediate(); } Type IntrinsicTypeDecoder::decodeImmediate() { typedef llvm::Intrinsic::IITDescriptor IITDescriptor; IITDescriptor D = Table.front(); Table = Table.slice(1); switch (D.Kind) { case IITDescriptor::BFloat: case IITDescriptor::MMX: case IITDescriptor::AMX: case IITDescriptor::Metadata: case IITDescriptor::ExtendArgument: case IITDescriptor::TruncArgument: case IITDescriptor::HalfVecArgument: case IITDescriptor::VarArg: case IITDescriptor::Token: case IITDescriptor::VecOfAnyPtrsToElt: case IITDescriptor::VecOfBitcastsToInt: case IITDescriptor::Subdivide2Argument: case IITDescriptor::Subdivide4Argument: case IITDescriptor::PPCQuad: case IITDescriptor::AArch64Svcount: // These types cannot be expressed in swift yet. return Type(); // Fundamental types. case IITDescriptor::Void: return TupleType::getEmpty(Context); case IITDescriptor::Half: return Context.TheIEEE16Type; case IITDescriptor::Float: return Context.TheIEEE32Type; case IITDescriptor::Double: return Context.TheIEEE64Type; case IITDescriptor::Quad: return Context.TheIEEE128Type; case IITDescriptor::Integer: return BuiltinIntegerType::get(D.Integer_Width, Context); // A vector of an immediate type. case IITDescriptor::Vector: { Type eltType = decodeImmediate(); if (!eltType) return Type(); return makeVector(eltType, D.Vector_Width.getKnownMinValue()); } // The element type of a vector type. case IITDescriptor::VecElementArgument: { Type argType = getTypeArgument(D.getArgumentNumber()); if (!argType) return Type(); auto vecType = argType->getAs(); if (!vecType) return Type(); return vecType->getElementType(); } // A pointer to an immediate type. case IITDescriptor::Pointer: { Type pointeeType = decodeImmediate(); if (!pointeeType) return Type(); return makePointer(pointeeType, D.Pointer_AddressSpace); } // A type argument. case IITDescriptor::Argument: return getTypeArgument(D.getArgumentNumber()); // A vector of the same width as a type argument. case IITDescriptor::SameVecWidthArgument: { Type maybeVectorType = getTypeArgument(D.getArgumentNumber()); if (!maybeVectorType) return Type(); Type eltType = decodeImmediate(); if (!eltType) return Type(); return maybeMakeVectorized(eltType, maybeVectorType); } // A struct, which we translate as a tuple. case IITDescriptor::Struct: { SmallVector Elts; for (unsigned i = 0; i != D.Struct_NumElements; ++i) { Type T = decodeImmediate(); if (!T) return Type(); Elts.push_back(T); } return TupleType::get(Elts, Context); } } llvm_unreachable("unhandled"); } /// \returns true on success, false on failure. static bool getSwiftFunctionTypeForIntrinsic(llvm::Intrinsic::ID ID, ArrayRef TypeArgs, ASTContext &Context, SmallVectorImpl &ArgElts, Type &ResultTy) { typedef llvm::Intrinsic::IITDescriptor IITDescriptor; SmallVector Table; getIntrinsicInfoTableEntries(ID, Table); ArrayRef TableRef = Table; // Decode the intrinsic's LLVM IR type, and map it to swift builtin types. ResultTy = DecodeIntrinsicType(TableRef, TypeArgs, Context); if (!ResultTy) return false; while (!TableRef.empty()) { Type ArgTy = DecodeIntrinsicType(TableRef, TypeArgs, Context); if (!ArgTy) return false; ArgElts.push_back(ArgTy); } // Translate LLVM function attributes to Swift function attributes. IntrinsicInfo II; II.ID = ID; auto attrs = II.getOrCreateAttributes(Context); if (attrs.hasFnAttr(llvm::Attribute::NoReturn)) { ResultTy = Context.getNeverType(); if (!ResultTy) return false; } return true; } static bool isValidFenceOrdering(StringRef Ordering) { return Ordering == "acquire" || Ordering == "release" || Ordering == "acqrel" || Ordering == "seqcst"; } static bool isValidRMWOrdering(StringRef Ordering) { return Ordering == "unordered" || Ordering == "monotonic" || Ordering == "acquire" || Ordering == "release" || Ordering == "acqrel" || Ordering == "seqcst"; } static bool isValidLoadOrdering(StringRef Ordering) { return Ordering == "unordered" || Ordering == "monotonic" || Ordering == "acquire" || Ordering == "seqcst"; } static bool isValidStoreOrdering(StringRef Ordering) { return Ordering == "unordered" || Ordering == "monotonic" || Ordering == "release" || Ordering == "seqcst"; } llvm::AtomicOrdering swift::decodeLLVMAtomicOrdering(StringRef O) { using namespace llvm; return StringSwitch(O) .Case("unordered", AtomicOrdering::Unordered) .Case("monotonic", AtomicOrdering::Monotonic) .Case("acquire", AtomicOrdering::Acquire) .Case("release", AtomicOrdering::Release) .Case("acqrel", AtomicOrdering::AcquireRelease) .Case("seqcst", AtomicOrdering::SequentiallyConsistent) .Default(AtomicOrdering::NotAtomic); } static bool isUnknownOrUnordered(llvm::AtomicOrdering ordering) { using namespace llvm; switch (ordering) { case AtomicOrdering::NotAtomic: case AtomicOrdering::Unordered: return true; case AtomicOrdering::Monotonic: case AtomicOrdering::Acquire: case AtomicOrdering::Release: case AtomicOrdering::AcquireRelease: case AtomicOrdering::SequentiallyConsistent: return false; } llvm_unreachable("Unhandled AtomicOrdering in switch."); } static bool isValidCmpXChgOrdering(StringRef SuccessString, StringRef FailureString) { using namespace llvm; AtomicOrdering SuccessOrdering = decodeLLVMAtomicOrdering(SuccessString); AtomicOrdering FailureOrdering = decodeLLVMAtomicOrdering(FailureString); // Unordered and unknown values are not allowed. if (isUnknownOrUnordered(SuccessOrdering) || isUnknownOrUnordered(FailureOrdering)) return false; // Success must be at least as strong as failure. if (!isAtLeastOrStrongerThan(SuccessOrdering, FailureOrdering)) return false; // Failure may not release because no store occurred. if (FailureOrdering == AtomicOrdering::Release || FailureOrdering == AtomicOrdering::AcquireRelease) return false; return true; } ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { // Builtin.TheTupleType resolves to the singleton instance of BuiltinTupleDecl. if (Id == Context.Id_TheTupleType) return Context.getBuiltinTupleDecl(); if (Id == Context.Id_Copyable) return Context.synthesizeInvertibleProtocolDecl(InvertibleProtocolKind::Copyable); if (Id == Context.Id_Escapable) return Context.synthesizeInvertibleProtocolDecl(InvertibleProtocolKind::Escapable); SmallVector Types; StringRef OperationName = getBuiltinBaseName(Context, Id.str(), Types); // If this is the name of an LLVM intrinsic, cons up a swift function with a // type that matches the IR types. if (llvm::Intrinsic::ID ID = getLLVMIntrinsicID(OperationName)) { SmallVector ArgElts; Type ResultTy; if (getSwiftFunctionTypeForIntrinsic(ID, Types, Context, ArgElts, ResultTy)) return getBuiltinFunction(Id, ArgElts, ResultTy); } // If this starts with fence, we have special suffixes to handle. if (OperationName.starts_with("ifdef_")) { OperationName = OperationName.drop_front(strlen("ifdef_")); if (!Types.empty()) return nullptr; if (OperationName.empty()) return nullptr; return getIfdefOperation(Context, Id); } // If this starts with fence, we have special suffixes to handle. if (OperationName.starts_with("fence_")) { OperationName = OperationName.drop_front(strlen("fence_")); // Verify we have a single integer, floating point, or pointer type. if (!Types.empty()) return nullptr; // Get and validate the ordering argument, which is required. auto Underscore = OperationName.find('_'); if (!isValidFenceOrdering(OperationName.substr(0, Underscore))) return nullptr; OperationName = OperationName.substr(Underscore); // Accept singlethread if present. if (OperationName.starts_with("_singlethread")) OperationName = OperationName.drop_front(strlen("_singlethread")); // Nothing else is allowed in the name. if (!OperationName.empty()) return nullptr; return getFenceOperation(Context, Id); } // If this starts with cmpxchg, we have special suffixes to handle. if (OperationName.starts_with("cmpxchg_")) { OperationName = OperationName.drop_front(strlen("cmpxchg_")); // Verify we have a single integer, floating point, or pointer type. if (Types.size() != 1) return nullptr; Type T = Types[0]; if (!T->is() && !T->is() && !T->is()) return nullptr; // Get and validate the ordering arguments, which are both required. SmallVector Parts; OperationName.split(Parts, "_"); if (Parts.size() < 2) return nullptr; if (!isValidCmpXChgOrdering(Parts[0], Parts[1])) return nullptr; auto NextPart = Parts.begin() + 2; // Accept weak, volatile, and singlethread if present. if (NextPart != Parts.end() && *NextPart == "weak") ++NextPart; if (NextPart != Parts.end() && *NextPart == "volatile") ++NextPart; if (NextPart != Parts.end() && *NextPart == "singlethread") ++NextPart; // Nothing else is allowed in the name. if (NextPart != Parts.end()) return nullptr; return getCmpXChgOperation(Context, Id, T); } // If this starts with atomicrmw, we have special suffixes to handle. if (OperationName.starts_with("atomicrmw_")) { OperationName = OperationName.drop_front(strlen("atomicrmw_")); // Verify we have a single integer or pointer type. if (Types.size() != 1) return nullptr; Type Ty = Types[0]; if (!Ty->is() && !Ty->is()) return nullptr; // Get and validate the suboperation name, which is required. auto Underscore = OperationName.find('_'); if (Underscore == StringRef::npos) return nullptr; StringRef SubOp = OperationName.substr(0, Underscore); if (SubOp != "xchg" && SubOp != "add" && SubOp != "sub" && SubOp != "and" && SubOp != "nand" && SubOp != "or" && SubOp != "xor" && SubOp != "max" && SubOp != "min" && SubOp != "umax" && SubOp != "umin") return nullptr; OperationName = OperationName.drop_front(Underscore+1); // Get and validate the ordering argument, which is required. Underscore = OperationName.find('_'); if (!isValidRMWOrdering(OperationName.substr(0, Underscore))) return nullptr; OperationName = OperationName.substr(Underscore); // Accept volatile and singlethread if present. if (OperationName.starts_with("_volatile")) OperationName = OperationName.drop_front(strlen("_volatile")); if (OperationName.starts_with("_singlethread")) OperationName = OperationName.drop_front(strlen("_singlethread")); // Nothing else is allowed in the name. if (!OperationName.empty()) return nullptr; return getAtomicRMWOperation(Context, Id, Ty); } // If this starts with atomicload or atomicstore, we have special suffixes to // handle. if (OperationName.starts_with("atomicload_")) { OperationName = OperationName.drop_front(strlen("atomicload_")); // Verify we have a single integer, floating point, or pointer type. if (Types.size() != 1) return nullptr; Type T = Types[0]; if (!T->is() && !T->is() && !T->is()) return nullptr; // Get and validate the ordering argument, which is required. auto Underscore = OperationName.find('_'); if (!isValidLoadOrdering(OperationName.substr(0, Underscore))) return nullptr; OperationName = OperationName.substr(Underscore); // Accept volatile and singlethread if present. if (OperationName.starts_with("_volatile")) OperationName = OperationName.drop_front(strlen("_volatile")); if (OperationName.starts_with("_singlethread")) OperationName = OperationName.drop_front(strlen("_singlethread")); // Nothing else is allowed in the name. if (!OperationName.empty()) return nullptr; return getAtomicLoadOperation(Context, Id, T); } if (OperationName.starts_with("atomicstore_")) { OperationName = OperationName.drop_front(strlen("atomicstore_")); // Verify we have a single integer, floating point, or pointer type. if (Types.size() != 1) return nullptr; Type T = Types[0]; if (!T->is() && !T->is() && !T->is()) return nullptr; // Get and validate the ordering argument, which is required. auto Underscore = OperationName.find('_'); if (!isValidStoreOrdering(OperationName.substr(0, Underscore))) return nullptr; OperationName = OperationName.substr(Underscore); // Accept volatile and singlethread if present. if (OperationName.starts_with("_volatile")) OperationName = OperationName.drop_front(strlen("_volatile")); if (OperationName.starts_with("_singlethread")) OperationName = OperationName.drop_front(strlen("_singlethread")); // Nothing else is allowed in the name. if (!OperationName.empty()) return nullptr; return getAtomicStoreOperation(Context, Id, T); } if (OperationName.starts_with("allocWithTailElems_")) { OperationName = OperationName.drop_front(strlen("allocWithTailElems_")); int NumTailTypes = 0; if (OperationName.getAsInteger(10, NumTailTypes)) return nullptr; return getAllocWithTailElemsOperation(Context, Id, NumTailTypes); } if (OperationName.starts_with("applyDerivative_")) { AutoDiffDerivativeFunctionKind kind; unsigned arity; bool throws; if (!autodiff::getBuiltinApplyDerivativeConfig( OperationName, kind, arity, throws)) return nullptr; return getAutoDiffApplyDerivativeFunction(Context, Id, kind, arity, throws, /*thrownType=*/Type()); } if (OperationName.starts_with("applyTranspose_")) { unsigned arity; bool throws; if (!autodiff::getBuiltinApplyTransposeConfig( OperationName, arity, throws)) return nullptr; return getAutoDiffApplyTransposeFunction(Context, Id, arity, throws, /*thrownType=*/Type()); } auto BV = llvm::StringSwitch(OperationName) #define BUILTIN(id, name, Attrs) .Case(name, BuiltinValueKind::id) #include "swift/AST/Builtins.def" .Default(BuiltinValueKind::None); // Filter out inappropriate overloads. OverloadedBuiltinKind OBK = OverloadedBuiltinKinds[unsigned(BV)]; // Verify that all types match the overload filter. for (Type T : Types) if (!isBuiltinTypeOverloaded(T, OBK)) return nullptr; switch (BV) { case BuiltinValueKind::Fence: case BuiltinValueKind::Ifdef: case BuiltinValueKind::CmpXChg: case BuiltinValueKind::AtomicRMW: case BuiltinValueKind::AtomicLoad: case BuiltinValueKind::AtomicStore: case BuiltinValueKind::AllocWithTailElems: llvm_unreachable("Handled above"); case BuiltinValueKind::None: return nullptr; case BuiltinValueKind::GepRaw: if (Types.size() != 1) return nullptr; return getGepRawOperation(Context, Id, Types[0]); case BuiltinValueKind::StringObjectOr: if (Types.size() != 1) return nullptr; return getStringObjectOrOperation(Context, Id, Types[0]); case BuiltinValueKind::Gep: if (Types.size() != 1) return nullptr; return getGepOperation(Context, Id, Types[0]); case BuiltinValueKind::GetTailAddr: if (Types.size() != 1) return nullptr; return getGetTailAddrOperation(Context, Id, Types[0]); case BuiltinValueKind::PerformInstantaneousReadAccess: if (!Types.empty()) return nullptr; return getPerformInstantaneousReadAccessOperation(Context, Id); case BuiltinValueKind::BeginUnpairedModifyAccess: if (!Types.empty()) return nullptr; return getBeginUnpairedAccessOperation(Context, Id); case BuiltinValueKind::EndUnpairedAccess: if (!Types.empty()) return nullptr; return getEndUnpairedAccessOperation(Context, Id); case BuiltinValueKind::AssumeAlignment: if (!Types.empty()) return nullptr; return getAssumeAlignment(Context, Id); #define BUILTIN(id, name, Attrs) #define BUILTIN_BINARY_OPERATION(id, name, attrs) #define BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(id, name, attrs, overload) \ case BuiltinValueKind::id: #include "swift/AST/Builtins.def" if (Types.size() != 1) return nullptr; return getBinaryOperation(Context, Id, Types[0]); #define BUILTIN(id, name, attrs) #define BUILTIN_BINARY_OPERATION(id, name, attrs) #define BUILTIN_BINARY_OPERATION_POLYMORPHIC(id, name) \ case BuiltinValueKind::id: #include "swift/AST/Builtins.def" if (!Types.empty()) return nullptr; return getPolymorphicBinaryOperation(Context, Id); #define BUILTIN(id, name, Attrs) #define BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(id, name, _, attrs, overload) case BuiltinValueKind::id: #include "swift/AST/Builtins.def" if (Types.size() != 1) return nullptr; return getBinaryOperationWithOverflow(Context, Id, Types[0]); #define BUILTIN(id, name, Attrs) #define BUILTIN_BINARY_PREDICATE(id, name, attrs, overload) case BuiltinValueKind::id: #include "swift/AST/Builtins.def" if (Types.size() != 1) return nullptr; return getBinaryPredicate(Context, Id, Types[0]); #define BUILTIN(id, name, Attrs) #define BUILTIN_UNARY_OPERATION(id, name, attrs, overload) case BuiltinValueKind::id: #include "swift/AST/Builtins.def" if (Types.size() != 1) return nullptr; return getUnaryOperation(Context, Id, Types[0]); #define BUILTIN(id, name, Attrs) #define BUILTIN_CAST_OPERATION(id, name, attrs) case BuiltinValueKind::id: #define BUILTIN_CAST_OR_BITCAST_OPERATION(id, name, attrs) case BuiltinValueKind::id: #include "swift/AST/Builtins.def" return getCastOperation(Context, Id, BV, Types); case BuiltinValueKind::Retain: case BuiltinValueKind::Release: case BuiltinValueKind::Autorelease: if (!Types.empty()) return nullptr; return getRefCountingOperation(Context, Id); case BuiltinValueKind::Load: case BuiltinValueKind::LoadRaw: case BuiltinValueKind::LoadInvariant: if (!Types.empty()) return nullptr; return getLoadOperation(Context, Id); case BuiltinValueKind::Take: if (!Types.empty()) return nullptr; return getTakeOperation(Context, Id); case BuiltinValueKind::Destroy: if (!Types.empty()) return nullptr; return getDestroyOperation(Context, Id); case BuiltinValueKind::Assign: case BuiltinValueKind::Init: case BuiltinValueKind::StoreRaw: if (!Types.empty()) return nullptr; return getStoreOperation(Context, Id); case BuiltinValueKind::DestroyArray: if (!Types.empty()) return nullptr; return getDestroyArrayOperation(Context, Id); case BuiltinValueKind::CopyArray: case BuiltinValueKind::AssignCopyArrayNoAlias: case BuiltinValueKind::AssignCopyArrayFrontToBack: case BuiltinValueKind::AssignCopyArrayBackToFront: if (!Types.empty()) return nullptr; return getCopyArrayOperation(Context, Id); case BuiltinValueKind::TakeArrayNoAlias: case BuiltinValueKind::TakeArrayFrontToBack: case BuiltinValueKind::TakeArrayBackToFront: case BuiltinValueKind::AssignTakeArray: if (!Types.empty()) return nullptr; return getTransferArrayOperation(Context, Id); case BuiltinValueKind::IsUnique: case BuiltinValueKind::IsUnique_native: case BuiltinValueKind::BeginCOWMutation: case BuiltinValueKind::BeginCOWMutation_native: if (!Types.empty()) return nullptr; // BeginCOWMutation has the same signature as IsUnique. return getIsUniqueOperation(Context, Id); case BuiltinValueKind::EndCOWMutation: if (!Types.empty()) return nullptr; return getEndCOWMutation(Context, Id); case BuiltinValueKind::BindMemory: if (!Types.empty()) return nullptr; return getBindMemoryOperation(Context, Id); case BuiltinValueKind::RebindMemory: if (!Types.empty()) return nullptr; return getRebindMemoryOperation(Context, Id); case BuiltinValueKind::ProjectTailElems: if (!Types.empty()) return nullptr; return getProjectTailElemsOperation(Context, Id); case BuiltinValueKind::Sizeof: case BuiltinValueKind::Strideof: case BuiltinValueKind::Alignof: return getSizeOrAlignOfOperation(Context, Id); case BuiltinValueKind::IsPOD: return getIsPODOperation(Context, Id); case BuiltinValueKind::IsConcrete: return getIsConcrete(Context, Id); case BuiltinValueKind::IsBitwiseTakable: return getIsBitwiseTakable(Context, Id); case BuiltinValueKind::IsOptionalType: return getIsOptionalOperation(Context, Id); case BuiltinValueKind::IsSameMetatype: return getIsSameMetatypeOperation(Context, Id); case BuiltinValueKind::AllocRaw: return getAllocOperation(Context, Id); case BuiltinValueKind::DeallocRaw: return getDeallocOperation(Context, Id); case BuiltinValueKind::StackAlloc: case BuiltinValueKind::UnprotectedStackAlloc: return getStackAllocOperation(Context, Id); case BuiltinValueKind::StackDealloc: return getStackDeallocOperation(Context, Id); case BuiltinValueKind::AllocVector: return getAllocVectorOperation(Context, Id); case BuiltinValueKind::CastToNativeObject: case BuiltinValueKind::UnsafeCastToNativeObject: case BuiltinValueKind::CastFromNativeObject: case BuiltinValueKind::BridgeToRawPointer: case BuiltinValueKind::BridgeFromRawPointer: if (!Types.empty()) return nullptr; return getNativeObjectCast(Context, Id, BV); case BuiltinValueKind::CastToBridgeObject: if (!Types.empty()) return nullptr; return getCastToBridgeObjectOperation(Context, Id); case BuiltinValueKind::CastReferenceFromBridgeObject: case BuiltinValueKind::CastBitPatternFromBridgeObject: if (!Types.empty()) return nullptr; return getCastFromBridgeObjectOperation(Context, Id, BV); case BuiltinValueKind::CastReference: if (!Types.empty()) return nullptr; return getCastReferenceOperation(Context, Id); case BuiltinValueKind::ReinterpretCast: if (!Types.empty()) return nullptr; return getReinterpretCastOperation(Context, Id); case BuiltinValueKind::AddressOf: case BuiltinValueKind::UnprotectedAddressOf: if (!Types.empty()) return nullptr; return getAddressOfOperation(Context, Id); case BuiltinValueKind::LegacyCondFail: return getLegacyCondFailOperation(Context, Id); case BuiltinValueKind::AddressOfBorrow: case BuiltinValueKind::AddressOfBorrowOpaque: case BuiltinValueKind::UnprotectedAddressOfBorrow: case BuiltinValueKind::UnprotectedAddressOfBorrowOpaque: if (!Types.empty()) return nullptr; return getAddressOfBorrowOperation(Context, Id); case BuiltinValueKind::CondFailMessage: return getCondFailOperation(Context, Id); case BuiltinValueKind::AssertConf: return getAssertConfOperation(Context, Id); case BuiltinValueKind::FixLifetime: return getFixLifetimeOperation(Context, Id); case BuiltinValueKind::CanBeObjCClass: return getCanBeObjCClassOperation(Context, Id); case BuiltinValueKind::CondUnreachable: case BuiltinValueKind::Unreachable: return getUnreachableOperation(Context, Id); case BuiltinValueKind::ZeroInitializer: return getZeroInitializerOperation(Context, Id); case BuiltinValueKind::Once: case BuiltinValueKind::OnceWithContext: return getOnceOperation(Context, Id, BV == BuiltinValueKind::OnceWithContext); case BuiltinValueKind::WillThrow: case BuiltinValueKind::ErrorInMain: return getVoidErrorOperation(Context, Id); case BuiltinValueKind::UnexpectedError: return getUnexpectedErrorOperation(Context, Id); case BuiltinValueKind::ExtractElement: if (Types.size() != 2) return nullptr; return getExtractElementOperation(Context, Id, Types[0], Types[1]); case BuiltinValueKind::InsertElement: if (Types.size() != 3) return nullptr; return getInsertElementOperation(Context, Id, Types[0], Types[1], Types[2]); case BuiltinValueKind::Select: if (Types.size() != 2) return nullptr; return getSelectOperation(Context, Id, Types[0], Types[1]); case BuiltinValueKind::ShuffleVector: if (Types.size() != 2) return nullptr; return getShuffleVectorOperation(Context, Id, Types[0], Types[1]); case BuiltinValueKind::StaticReport: if (!Types.empty()) return nullptr; return getStaticReportOperation(Context, Id); case BuiltinValueKind::SToSCheckedTrunc: case BuiltinValueKind::SToUCheckedTrunc: if (Types.size() != 2) return nullptr; return getCheckedTruncOperation(Context, Id, Types[0], Types[1], true); case BuiltinValueKind::UToSCheckedTrunc: case BuiltinValueKind::UToUCheckedTrunc: if (Types.size() != 2) return nullptr; return getCheckedTruncOperation(Context, Id, Types[0], Types[1], false); case BuiltinValueKind::ClassifyBridgeObject: if (!Types.empty()) return nullptr; return getClassifyBridgeObject(Context, Id); case BuiltinValueKind::ValueToBridgeObject: if (!Types.empty()) return nullptr; return getValueToBridgeObject(Context, Id); case BuiltinValueKind::COWBufferForReading: return getCOWBufferForReading(Context, Id); case BuiltinValueKind::ApplyDerivative: case BuiltinValueKind::ApplyTranspose: llvm_unreachable("Handled above"); case BuiltinValueKind::OnFastPath: return getOnFastPath(Context, Id); case BuiltinValueKind::IntToFPWithOverflow: if (Types.size() != 2) return nullptr; return getIntToFPWithOverflowOperation(Context, Id, Types[0], Types[1]); case BuiltinValueKind::BitWidth: if (Types.size() != 1) return nullptr; return getBitWidthOperation(Context, Id, Types[0]); case BuiltinValueKind::IsNegative: if (Types.size() != 1) return nullptr; return getIsNegativeOperation(Context, Id, Types[0]); case BuiltinValueKind::WordAtIndex: if (Types.size() != 1) return nullptr; return getWordAtIndexOperation(Context, Id, Types[0]); case BuiltinValueKind::GetObjCTypeEncoding: return getGetObjCTypeEncodingOperation(Context, Id); case BuiltinValueKind::GlobalStringTablePointer: return getGlobalStringTablePointer(Context, Id); case BuiltinValueKind::ConvertStrongToUnownedUnsafe: return getConvertStrongToUnownedUnsafe(Context, Id); case BuiltinValueKind::ConvertUnownedUnsafeToGuaranteed: return getConvertUnownedUnsafeToGuaranteed(Context, Id); case BuiltinValueKind::GetCurrentAsyncTask: return getGetCurrentAsyncTask(Context, Id); case BuiltinValueKind::GetCurrentExecutor: return getGetCurrentExecutor(Context, Id); case BuiltinValueKind::CancelAsyncTask: return getCancelAsyncTask(Context, Id); case BuiltinValueKind::CreateTask: return getCreateTask(Context, Id); case BuiltinValueKind::CreateDiscardingTask: return getCreateDiscardingTask(Context, Id); case BuiltinValueKind::CreateAsyncTask: return getCreateAsyncTask(Context, Id, /*inGroup=*/false, /*withExecutor=*/false, /*isDiscarding=*/false); case BuiltinValueKind::CreateAsyncTaskInGroup: return getCreateAsyncTask(Context, Id, /*inGroup=*/true, /*withExecutor=*/false, /*isDiscarding=*/false); case BuiltinValueKind::CreateAsyncDiscardingTaskInGroup: return getCreateAsyncTask(Context, Id, /*inGroup=*/true, /*withExecutor=*/false, /*isDiscarding=*/true); case BuiltinValueKind::CreateAsyncTaskWithExecutor: return getCreateAsyncTask(Context, Id, /*inGroup=*/false, /*withExecutor=*/true, /*isDiscarding=*/false); case BuiltinValueKind::CreateAsyncTaskInGroupWithExecutor: return getCreateAsyncTask(Context, Id, /*inGroup=*/true, /*withExecutor=*/true, /*isDiscarding=*/false); case BuiltinValueKind::CreateAsyncDiscardingTaskInGroupWithExecutor: return getCreateAsyncTask(Context, Id, /*inGroup=*/true, /*withExecutor=*/true, /*isDiscarding=*/true); case BuiltinValueKind::TaskRunInline: return getTaskRunInline(Context, Id); case BuiltinValueKind::TargetOSVersionAtLeast: return getTargetOSVersionAtLeast(Context, Id); case BuiltinValueKind::TargetVariantOSVersionAtLeast: return getTargetVariantOSVersionAtLeast(Context, Id); case BuiltinValueKind::TargetOSVersionOrVariantOSVersionAtLeast: return getTargetOSVersionOrVariantOSVersionAtLeast(Context, Id); case BuiltinValueKind::ConvertTaskToJob: return getConvertTaskToJob(Context, Id); case BuiltinValueKind::BuildMainActorExecutorRef: return getBuildMainActorExecutorRef(Context, Id); case BuiltinValueKind::BuildDefaultActorExecutorRef: return getBuildDefaultActorExecutorRef(Context, Id); case BuiltinValueKind::BuildOrdinaryTaskExecutorRef: return getBuildOrdinaryTaskExecutorRef(Context, Id); case BuiltinValueKind::BuildOrdinarySerialExecutorRef: return getBuildOrdinarySerialExecutorRef(Context, Id); case BuiltinValueKind::BuildComplexEqualitySerialExecutorRef: return getBuildComplexEqualitySerialExecutorRef(Context, Id); case BuiltinValueKind::ExtractFunctionIsolation: return getExtractFunctionIsolation(Context, Id); case BuiltinValueKind::PoundAssert: return getPoundAssert(Context, Id); case BuiltinValueKind::TSanInoutAccess: return getTSanInoutAccess(Context, Id); case BuiltinValueKind::TypePtrAuthDiscriminator: return getTypePtrAuthDiscriminator(Context, Id); case BuiltinValueKind::TypeJoin: return getTypeJoinOperation(Context, Id); case BuiltinValueKind::TypeJoinInout: return getTypeJoinInoutOperation(Context, Id); case BuiltinValueKind::TypeJoinMeta: return getTypeJoinMetaOperation(Context, Id); case BuiltinValueKind::TriggerFallbackDiagnostic: return getTriggerFallbackDiagnosticOperation(Context, Id); case BuiltinValueKind::InitializeDefaultActor: case BuiltinValueKind::InitializeNonDefaultDistributedActor: case BuiltinValueKind::DestroyDefaultActor: return getDefaultActorInitDestroy(Context, Id); case BuiltinValueKind::InitializeDistributedRemoteActor: return getDistributedActorInitializeRemote(Context, Id); case BuiltinValueKind::StartAsyncLet: case BuiltinValueKind::StartAsyncLetWithLocalBuffer: return getStartAsyncLet(Context, Id); case BuiltinValueKind::EndAsyncLet: case BuiltinValueKind::EndAsyncLetLifetime: return getEndAsyncLet(Context, Id); case BuiltinValueKind::CreateTaskGroup: return getCreateTaskGroup(Context, Id); case BuiltinValueKind::CreateTaskGroupWithFlags: return getCreateTaskGroupWithFlags(Context, Id); case BuiltinValueKind::DestroyTaskGroup: return getDestroyTaskGroup(Context, Id); case BuiltinValueKind::ResumeNonThrowingContinuationReturning: case BuiltinValueKind::ResumeThrowingContinuationReturning: return getResumeContinuationReturning(Context, Id); case BuiltinValueKind::ResumeThrowingContinuationThrowing: return getResumeContinuationThrowing(Context, Id); case BuiltinValueKind::WithUnsafeContinuation: return getWithUnsafeContinuation(Context, Id, /*throws=*/false); case BuiltinValueKind::WithUnsafeThrowingContinuation: return getWithUnsafeContinuation(Context, Id, /*throws=*/true); case BuiltinValueKind::HopToActor: return getHopToActor(Context, Id); case BuiltinValueKind::FlowSensitiveSelfIsolation: return getFlowSensitiveSelfIsolation(Context, Id, false); case BuiltinValueKind::FlowSensitiveDistributedSelfIsolation: return getFlowSensitiveSelfIsolation(Context, Id, true); case BuiltinValueKind::AutoDiffCreateLinearMapContextWithType: return getAutoDiffCreateLinearMapContext(Context, Id); case BuiltinValueKind::AutoDiffProjectTopLevelSubcontext: return getAutoDiffProjectTopLevelSubcontext(Context, Id); case BuiltinValueKind::AutoDiffAllocateSubcontextWithType: return getAutoDiffAllocateSubcontext(Context, Id); case BuiltinValueKind::PackLength: return getPackLength(Context, Id); case BuiltinValueKind::GetEnumTag: return getGetEnumTag(Context, Id); case BuiltinValueKind::InjectEnumTag: return getInjectEnumTag(Context, Id); case BuiltinValueKind::DistributedActorAsAnyActor: return getDistributedActorAsAnyActor(Context, Id); case BuiltinValueKind::AddressOfRawLayout: return getAddressOfRawLayout(Context, Id); case BuiltinValueKind::Emplace: return getEmplace(Context, Id); } llvm_unreachable("bad builtin value!"); } StringRef swift::getBuiltinName(BuiltinValueKind ID) { switch (ID) { case BuiltinValueKind::None: llvm_unreachable("no builtin kind"); #define BUILTIN(Id, Name, Attrs) \ case BuiltinValueKind::Id: \ return Name; #include "swift/AST/Builtins.def" } llvm_unreachable("bad BuiltinValueKind"); } bool swift::isPolymorphicBuiltin(BuiltinValueKind id) { switch (id) { case BuiltinValueKind::None: llvm_unreachable("no builtin kind"); #define BUILTIN(Id, Name, Attrs) \ case BuiltinValueKind::Id: \ return false; #define BUILTIN_BINARY_OPERATION_POLYMORPHIC(Id, Name) \ case BuiltinValueKind::Id: \ return true; #include "swift/AST/Builtins.def" } llvm_unreachable("bad BuiltinValueKind"); } BuiltinTypeKind BuiltinType::getBuiltinTypeKind() const { // If we do not have a vector or an integer our job is easy. return BuiltinTypeKind(std::underlying_type::type(getKind())); } bool BuiltinType::isBitwiseCopyable() const { switch (getBuiltinTypeKind()) { case BuiltinTypeKind::BuiltinInteger: case BuiltinTypeKind::BuiltinIntegerLiteral: case BuiltinTypeKind::BuiltinFloat: case BuiltinTypeKind::BuiltinPackIndex: case BuiltinTypeKind::BuiltinRawPointer: case BuiltinTypeKind::BuiltinVector: case BuiltinTypeKind::BuiltinExecutor: case BuiltinTypeKind::BuiltinJob: case BuiltinTypeKind::BuiltinRawUnsafeContinuation: return true; case BuiltinTypeKind::BuiltinNativeObject: case BuiltinTypeKind::BuiltinBridgeObject: case BuiltinTypeKind::BuiltinUnsafeValueBuffer: case BuiltinTypeKind::BuiltinDefaultActorStorage: case BuiltinTypeKind::BuiltinNonDefaultDistributedActorStorage: case BuiltinTypeKind::BuiltinUnboundGeneric: return false; case BuiltinTypeKind::BuiltinFixedArray: { // FixedArray : BitwiseCopyable whenever X : BitwiseCopyable auto bfa = cast(this); auto &C = bfa->getASTContext(); return (bool)checkConformance( bfa->getElementType(), C.getProtocol(KnownProtocolKind::BitwiseCopyable)); } } } StringRef BuiltinType::getTypeName(SmallVectorImpl &result, bool prependBuiltinNamespace) const { #ifdef MAYBE_GET_NAMESPACED_BUILTIN #error \ "We define MAYBE_GET_NAMESPACED_BUILTIN here. Do not define before this?!" #endif #define MAYBE_GET_NAMESPACED_BUILTIN(NAME) \ ((prependBuiltinNamespace) ? NAME : NAME.getWithoutPrefix()) llvm::raw_svector_ostream printer(result); switch (getBuiltinTypeKind()) { case BuiltinTypeKind::BuiltinRawPointer: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_RAWPOINTER); break; case BuiltinTypeKind::BuiltinRawUnsafeContinuation: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_RAWUNSAFECONTINUATION); break; case BuiltinTypeKind::BuiltinJob: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_JOB); break; case BuiltinTypeKind::BuiltinExecutor: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_EXECUTOR); break; case BuiltinTypeKind::BuiltinDefaultActorStorage: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_DEFAULTACTORSTORAGE); break; case BuiltinTypeKind::BuiltinNonDefaultDistributedActorStorage: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_NONDEFAULTDISTRIBUTEDACTORSTORAGE); break; case BuiltinTypeKind::BuiltinPackIndex: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_PACKINDEX); break; case BuiltinTypeKind::BuiltinNativeObject: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_NATIVEOBJECT); break; case BuiltinTypeKind::BuiltinBridgeObject: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_BRIDGEOBJECT); break; case BuiltinTypeKind::BuiltinUnsafeValueBuffer: printer << MAYBE_GET_NAMESPACED_BUILTIN( BUILTIN_TYPE_NAME_UNSAFEVALUEBUFFER); break; case BuiltinTypeKind::BuiltinIntegerLiteral: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_INTLITERAL); break; case BuiltinTypeKind::BuiltinVector: { const auto *t = cast(this); llvm::SmallString<32> UnderlyingStrVec; StringRef UnderlyingStr; { // FIXME: Ugly hack: remove the .Builtin from the element type. { llvm::raw_svector_ostream UnderlyingOS(UnderlyingStrVec); t->getElementType().print(UnderlyingOS); } if (UnderlyingStrVec.str().starts_with(BUILTIN_TYPE_NAME_PREFIX)) UnderlyingStr = UnderlyingStrVec.substr(8); else UnderlyingStr = UnderlyingStrVec; } printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_VEC) << t->getNumElements() << "x" << UnderlyingStr; break; } case BuiltinTypeKind::BuiltinInteger: { auto width = cast(this)->getWidth(); if (width.isFixedWidth()) { printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_INT) << width.getFixedWidth(); break; } if (width.isPointerWidth()) { printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_WORD); break; } llvm_unreachable("impossible bit width"); } case BuiltinTypeKind::BuiltinFloat: { switch (cast(this)->getFPKind()) { case BuiltinFloatType::IEEE16: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_FLOAT) << "16"; break; case BuiltinFloatType::IEEE32: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_FLOAT) << "32"; break; case BuiltinFloatType::IEEE64: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_FLOAT) << "64"; break; case BuiltinFloatType::IEEE80: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_FLOAT) << "80"; break; case BuiltinFloatType::IEEE128: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_FLOAT) << "128"; break; case BuiltinFloatType::PPC128: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_FLOAT_PPC) << "128"; break; } break; } case BuiltinTypeKind::BuiltinFixedArray: { auto bfa = cast(this); printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_FIXEDARRAY) << '<'; bfa->getSize()->print(printer); printer << ", "; bfa->getElementType()->print(printer); printer << '>'; break; } case BuiltinTypeKind::BuiltinUnboundGeneric: { auto bug = cast(this); printer << MAYBE_GET_NAMESPACED_BUILTIN(bug->getBuiltinTypeName()); break; } } #undef MAYBE_GET_NAMESPACED_BUILTIN return printer.str(); } BuiltinNameStringLiteral BuiltinUnboundGenericType::getBuiltinTypeName() const { switch (BoundGenericTypeKind) { case TypeKind::BuiltinFixedArray: return BUILTIN_TYPE_NAME_FIXEDARRAY; case TypeKind::BuiltinInteger: return BUILTIN_TYPE_NAME_INT; default: llvm_unreachable("not a generic builtin kind"); } } StringRef BuiltinUnboundGenericType::getBuiltinTypeNameString() const { return getBuiltinTypeName(); } GenericSignature BuiltinUnboundGenericType::getGenericSignature() const { auto &C = getASTContext(); switch (BoundGenericTypeKind) { case TypeKind::BuiltinFixedArray: { auto Count = GenericTypeParamType::get(C.getIdentifier("Count"), GenericTypeParamKind::Value, 0, 0, C.getIntType(), C); auto Element = GenericTypeParamType::get(C.getIdentifier("Element"), GenericTypeParamKind::Type, 0, 1, Type(), C); return GenericSignature::get({Count, Element}, {}); } case TypeKind::BuiltinInteger: { auto bits = GenericTypeParamType::get(C.getIdentifier("Bits"), GenericTypeParamKind::Type, 0, 0, C.getIntType(), C); return GenericSignature::get(bits, {}); } default: llvm_unreachable("not a generic builtin"); } } Type BuiltinUnboundGenericType::getBound(SubstitutionMap subs) const { if (!subs.getGenericSignature()->isEqual(getGenericSignature())) { return ErrorType::get(const_cast(this)); } switch (BoundGenericTypeKind) { case TypeKind::BuiltinFixedArray: { auto types = subs.getReplacementTypes(); auto size = types[0]->getCanonicalType(); if (size->getMatchingParamKind() != GenericTypeParamKind::Value) { return ErrorType::get(const_cast(this)); } auto element = types[1]->getCanonicalType(); if (element->getMatchingParamKind() != GenericTypeParamKind::Type) { return ErrorType::get(const_cast(this)); } return BuiltinFixedArrayType::get(size, element); } case TypeKind::BuiltinInteger: { auto size = subs.getReplacementTypes()[0]; if (size->getMatchingParamKind() != GenericTypeParamKind::Value) { return ErrorType::get(const_cast(this)); } // TODO: support actual generic parameters auto literalSize = size->getAs(); if (!literalSize) { return ErrorType::get(const_cast(this)); } return BuiltinIntegerType::get(literalSize->getValue().getLimitedValue(), getASTContext()); } default: llvm_unreachable("not a generic builtin kind"); } } std::optional BuiltinFixedArrayType::getFixedInhabitedSize() const { if (auto intSize = getSize()->getAs()) { if (intSize->getValue().isNegative()) { return std::nullopt; } return intSize->getValue().getLimitedValue(); } return std::nullopt; } bool BuiltinFixedArrayType::isFixedNegativeSize() const { if (auto intSize = getSize()->getAs()) { return intSize->getValue().isNegative(); } return false; }