mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Ideally we'd be able to use the llvm interleave2 and deinterleave2 intrinsics instead of adding these, but deinterleave currently isn't available from Swift, and even if you hack that in, the codegen from LLVM is worse than what shufflevector produces for both x86 and arm. So in the medium-term we'll use these builtins, and hope to remove them in favor of [de]interleave2 at some future point.
3724 lines
135 KiB
C++
3724 lines
135 KiB
C++
//===--- 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 <tuple>
|
|
|
|
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<llvm::AttributeList>;
|
|
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<Type> &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 <class TypeS, class ProtocolS>
|
|
struct ConformsToSynthesizer {
|
|
TypeS Type;
|
|
ProtocolS Protocol;
|
|
};
|
|
template <class TypeS, class ProtocolS>
|
|
constexpr ConformsToSynthesizer<TypeS, ProtocolS>
|
|
_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 <class TypeS>
|
|
struct LayoutConstraintSynthesizer {
|
|
TypeS Type;
|
|
LayoutConstraint Constraint;
|
|
};
|
|
template <class TypeS>
|
|
LayoutConstraintSynthesizer<TypeS>
|
|
_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 <class... ParamS>
|
|
struct GenericParamListSynthesizer {
|
|
VariadicSynthesizerStorage<ParamS...> Params;
|
|
};
|
|
template <class... ParamS>
|
|
constexpr GenericParamListSynthesizer<ParamS...>
|
|
_generics(ParamS... params) {
|
|
return {{params...}};
|
|
}
|
|
|
|
struct CountGenericParameters {
|
|
unsigned &Count;
|
|
|
|
void operator()(UnrestrictedGenericParam _) const {
|
|
Count++;
|
|
}
|
|
|
|
template <class TypeS, class ProtoS>
|
|
void operator()(const ConformsToSynthesizer<TypeS, ProtoS> &_) const {
|
|
// not a parameter
|
|
}
|
|
|
|
template <class TypeS>
|
|
void operator()(const LayoutConstraintSynthesizer<TypeS> &_) 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<GenericTypeParamDecl *, 2> 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 <class... ParamsS>
|
|
static GenericParamList *synthesizeGenericParamList(SynthesisContext &SC,
|
|
const GenericParamListSynthesizer<ParamsS...> ¶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<GenericTypeParamType *, 2> GenericParamTypes;
|
|
SmallVector<Requirement, 2> AddedRequirements;
|
|
|
|
CollectGenericParams(SynthesisContext &SC) : SC(SC) {
|
|
for (auto gp : SC.GenericParams->getParams()) {
|
|
GenericParamTypes.push_back(
|
|
gp->getDeclaredInterfaceType()->castTo<GenericTypeParamType>());
|
|
}
|
|
}
|
|
|
|
void operator()(UnrestrictedGenericParam _) {}
|
|
|
|
template <class TypeS, class ProtoS>
|
|
void operator()(const ConformsToSynthesizer<TypeS, ProtoS> &conf) {
|
|
auto type = synthesizeType(SC, conf.Type);
|
|
auto protocolType = synthesizeType(SC, conf.Protocol);
|
|
Requirement req = {RequirementKind::Conformance, type, protocolType};
|
|
|
|
AddedRequirements.push_back(req);
|
|
}
|
|
|
|
template <class TypeS>
|
|
void operator()(const LayoutConstraintSynthesizer<TypeS> &req) {
|
|
auto type = synthesizeType(SC, req.Type);
|
|
AddedRequirements.push_back({RequirementKind::Layout,
|
|
type, req.Constraint});
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
template <class... ParamsS>
|
|
static GenericSignature
|
|
synthesizeGenericSignature(SynthesisContext &SC,
|
|
const GenericParamListSynthesizer<ParamsS...> &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<Type> argTypes, Type ResType) {
|
|
auto &Context = ResType->getASTContext();
|
|
|
|
ModuleDecl *M = Context.TheBuiltinModule;
|
|
DeclContext *DC = &M->getMainFile(FileUnitKind::Builtin);
|
|
|
|
SmallVector<ParamDecl*, 4> 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 <class ExtInfoS, class ParamsS, class ResultS>
|
|
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 <class ExtInfoS, class ParamsS, class ResultS>
|
|
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 <class ExtInfoS, class GenericsS, class ParamsS, class ResultS>
|
|
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<AnyFunctionType::Param> 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<ParamDecl*, 4> 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<BuiltinVectorType>()) {
|
|
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<Type> 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<BuiltinVectorType>();
|
|
auto OutputVec = Output.isNull()? nullptr :Output->getAs<BuiltinVectorType>();
|
|
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<BuiltinIntegerType>() ||
|
|
!CheckOutput->is<BuiltinIntegerType>() ||
|
|
CheckInput->castTo<BuiltinIntegerType>()->getLeastWidth() <=
|
|
CheckOutput->castTo<BuiltinIntegerType>()->getGreatestWidth())
|
|
return nullptr;
|
|
break;
|
|
case BuiltinValueKind::TruncOrBitCast:
|
|
if (CheckOutput.isNull() ||
|
|
!CheckInput->is<BuiltinIntegerType>() ||
|
|
!CheckOutput->is<BuiltinIntegerType>() ||
|
|
CheckInput->castTo<BuiltinIntegerType>()->getLeastWidth() <
|
|
CheckOutput->castTo<BuiltinIntegerType>()->getGreatestWidth())
|
|
return nullptr;
|
|
break;
|
|
|
|
case BuiltinValueKind::ZExt:
|
|
case BuiltinValueKind::SExt: {
|
|
if (CheckOutput.isNull() ||
|
|
!CheckInput->is<BuiltinIntegerType>() ||
|
|
!CheckOutput->is<BuiltinIntegerType>() ||
|
|
CheckInput->castTo<BuiltinIntegerType>()->getGreatestWidth() >=
|
|
CheckOutput->castTo<BuiltinIntegerType>()->getLeastWidth())
|
|
return nullptr;
|
|
break;
|
|
}
|
|
case BuiltinValueKind::ZExtOrBitCast:
|
|
case BuiltinValueKind::SExtOrBitCast: {
|
|
if (CheckOutput.isNull() ||
|
|
!CheckInput->is<BuiltinIntegerType>() ||
|
|
!CheckOutput->is<BuiltinIntegerType>() ||
|
|
CheckInput->castTo<BuiltinIntegerType>()->getGreatestWidth() >
|
|
CheckOutput->castTo<BuiltinIntegerType>()->getLeastWidth())
|
|
return nullptr;
|
|
break;
|
|
}
|
|
|
|
case BuiltinValueKind::FPToUI:
|
|
case BuiltinValueKind::FPToSI:
|
|
if (CheckOutput.isNull() || !CheckInput->is<BuiltinFloatType>() ||
|
|
!CheckOutput->is<BuiltinIntegerType>())
|
|
return nullptr;
|
|
break;
|
|
|
|
case BuiltinValueKind::UIToFP:
|
|
case BuiltinValueKind::SIToFP:
|
|
if (CheckOutput.isNull() || !CheckInput->is<BuiltinIntegerType>() ||
|
|
!CheckOutput->is<BuiltinFloatType>())
|
|
return nullptr;
|
|
break;
|
|
|
|
case BuiltinValueKind::FPTrunc:
|
|
if (CheckOutput.isNull() ||
|
|
!CheckInput->is<BuiltinFloatType>() ||
|
|
!CheckOutput->is<BuiltinFloatType>() ||
|
|
CheckInput->castTo<BuiltinFloatType>()->getFPKind() <=
|
|
CheckOutput->castTo<BuiltinFloatType>()->getFPKind())
|
|
return nullptr;
|
|
break;
|
|
case BuiltinValueKind::FPExt:
|
|
if (CheckOutput.isNull() ||
|
|
!CheckInput->is<BuiltinFloatType>() ||
|
|
!CheckOutput->is<BuiltinFloatType>() ||
|
|
CheckInput->castTo<BuiltinFloatType>()->getFPKind() >=
|
|
CheckOutput->castTo<BuiltinFloatType>()->getFPKind())
|
|
return nullptr;
|
|
break;
|
|
|
|
case BuiltinValueKind::PtrToInt:
|
|
// FIXME: Do we care about vectors of pointers?
|
|
if (!CheckOutput.isNull() || !CheckInput->is<BuiltinIntegerType>() ||
|
|
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<BuiltinIntegerType>() ||
|
|
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<BuiltinIntegerType>())
|
|
if (auto *BFT = CheckOutput->getAs<BuiltinFloatType>())
|
|
if (BIT->isFixedWidth() && BIT->getFixedWidth() == BFT->getBitWidth())
|
|
break;
|
|
if (auto *BFT = CheckInput->getAs<BuiltinFloatType>())
|
|
if (auto *BIT = CheckOutput->getAs<BuiltinIntegerType>())
|
|
if (BIT->isFixedWidth() && BIT->getFixedWidth() == BFT->getBitWidth())
|
|
break;
|
|
|
|
// Support VecNxInt1 -> IntN bitcast for SIMD comparison results.
|
|
if (auto *Vec = CheckInput->getAs<BuiltinVectorType>())
|
|
if (auto *BIT = CheckOutput->getAs<BuiltinIntegerType>())
|
|
if (auto *Element = Vec->getElementType()->getAs<BuiltinIntegerType>())
|
|
if (Element->getFixedWidth() == 1 &&
|
|
BIT->isFixedWidth() &&
|
|
BIT->getFixedWidth() == Vec->getNumElements())
|
|
break;
|
|
// And IntN -> VecNxInt1 for SIMDMask random generators.
|
|
if (auto *Vec = CheckOutput->getAs<BuiltinVectorType>())
|
|
if (auto *BIT = CheckInput->getAs<BuiltinIntegerType>())
|
|
if (auto *Element = Vec->getElementType()->getAs<BuiltinIntegerType>())
|
|
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<AnyFunctionType::Param, 4> 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<GenericTypeParamType *, 2> genericParamTypes;
|
|
SmallVector<Requirement, 2> 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<GenericTypeParamType>());
|
|
}
|
|
}
|
|
|
|
template <class G>
|
|
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 <class G>
|
|
void setResult(const G &generator) {
|
|
InterfaceResult = generator.build(*this);
|
|
}
|
|
|
|
template <class G>
|
|
void setThrownError(const G &generator) {
|
|
ThrownError = generator.build(*this);
|
|
}
|
|
|
|
template <class G>
|
|
void addConformanceRequirement(const G &generator, KnownProtocolKind kp) {
|
|
addConformanceRequirement(generator, Context.getProtocol(kp));
|
|
}
|
|
|
|
template <class G>
|
|
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<Type(BuiltinFunctionBuilder &)> TheFunction;
|
|
Type build(BuiltinFunctionBuilder &builder) const {
|
|
return TheFunction(builder);
|
|
}
|
|
};
|
|
template <class T>
|
|
struct MetatypeGenerator {
|
|
T Object;
|
|
std::optional<MetatypeRepresentation> Repr;
|
|
Type build(BuiltinFunctionBuilder &builder) const {
|
|
return MetatypeType::get(Object.build(builder), Repr);
|
|
}
|
|
};
|
|
template <class T>
|
|
struct PackExpansionGenerator {
|
|
T Object;
|
|
Type build(BuiltinFunctionBuilder &builder) const {
|
|
auto patternTy = Object.build(builder);
|
|
SmallVector<Type, 2> 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 <class... Gs>
|
|
static BuiltinFunctionBuilder::LambdaGenerator
|
|
makeTuple(const Gs & ...elementGenerators) {
|
|
return {
|
|
[=](BuiltinFunctionBuilder &builder) -> Type {
|
|
TupleTypeElt elts[] = {
|
|
elementGenerators.build(builder)...
|
|
};
|
|
return TupleType::get(elts, builder.Context);
|
|
}
|
|
};
|
|
}
|
|
|
|
template <class... Gs>
|
|
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 <class T>
|
|
static BuiltinFunctionBuilder::MetatypeGenerator<T>
|
|
makeMetatype(const T &object,
|
|
std::optional<MetatypeRepresentation> repr = std::nullopt) {
|
|
return { object, repr };
|
|
}
|
|
|
|
template <class T>
|
|
static BuiltinFunctionBuilder::PackExpansionGenerator<T>
|
|
makePackExpansion(const T &object) {
|
|
return { object };
|
|
}
|
|
|
|
/// Create a function with type <T> 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) {
|
|
// <T> (@inout T) -> Int1
|
|
return getBuiltinFunction(ctx, id, _thin,
|
|
_generics(_unrestricted),
|
|
_parameters(_inout(_typeparam(0))),
|
|
_int(1));
|
|
}
|
|
|
|
static ValueDecl *getEndCOWMutation(ASTContext &ctx, Identifier id) {
|
|
// <T> (@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 : AnyObject> 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 : AnyObject> (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> 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> 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> () -> 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> 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<decltype(fnResultGen), 2> 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<FunctionType::Param, 2> 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<AnyFunctionType>();
|
|
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<decltype(linearFnResultGen), 2> 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<FunctionType::Param, 2> 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<TupleTypeElt, 2> 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, T> (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); // <T>
|
|
}
|
|
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); // <T>
|
|
|
|
// 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> T -> ()
|
|
BuiltinFunctionBuilder builder(Context);
|
|
builder.addParameter(makeGenericParam());
|
|
builder.setResult(makeConcrete(Context.TheEmptyTupleType));
|
|
return builder.build(Id);
|
|
}
|
|
|
|
static ValueDecl *getAddressOfOperation(ASTContext &Context, Identifier Id) {
|
|
// <T> (@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> (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,U,V> (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) {
|
|
// <T,U,V> (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,U,V> (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> 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> 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<N, T>, Int32) -> T
|
|
auto VecTy = FirstTy->getAs<BuiltinVectorType>();
|
|
if (!VecTy)
|
|
return nullptr;
|
|
|
|
auto IndexTy = SecondTy->getAs<BuiltinIntegerType>();
|
|
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<N, T>, T, Int32) -> Vector<N, T>
|
|
auto VecTy = FirstTy->getAs<BuiltinVectorType>();
|
|
if (!VecTy)
|
|
return nullptr;
|
|
auto ElementTy = VecTy->getElementType();
|
|
|
|
if (!SecondTy->isEqual(ElementTy))
|
|
return nullptr;
|
|
|
|
auto IndexTy = ThirdTy->getAs<BuiltinIntegerType>();
|
|
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<BuiltinVectorType>();
|
|
if (VecPredTy) {
|
|
// ValueTy must also be vector type with matching element count.
|
|
auto VecValueTy = ValueTy->getAs<BuiltinVectorType>();
|
|
if (!VecValueTy ||
|
|
VecPredTy->getNumElements() != VecValueTy->getNumElements())
|
|
return nullptr;
|
|
} else {
|
|
// Type is (Int1, Ty, Ty) -> Ty
|
|
auto IntTy = PredTy->getAs<BuiltinIntegerType>();
|
|
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<N, T>, Vector<N, T>, Vector<M, Int32) -> Vector<M, T>
|
|
auto VecTy = FirstTy->getAs<BuiltinVectorType>();
|
|
if (!VecTy)
|
|
return nullptr;
|
|
auto ElementTy = VecTy->getElementType();
|
|
|
|
auto IndexTy = SecondTy->getAs<BuiltinVectorType>();
|
|
if (!IndexTy)
|
|
return nullptr;
|
|
auto IdxElTy = IndexTy->getElementType()->getAs<BuiltinIntegerType>();
|
|
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 *getInterleaveOperation(ASTContext &Context, Identifier Id,
|
|
Type FirstTy) {
|
|
// (Vector<N,T>, Vector<N,T>) -> (Vector<N,T>, Vector<N,T>)
|
|
auto VecTy = FirstTy->getAs<BuiltinVectorType>();
|
|
// Require even length because we don't need anything else to support Swift's
|
|
// SIMD types and it saves us from having to define what happens for odd
|
|
// lengths until we actually need to care about them.
|
|
if (!VecTy || VecTy->getNumElements() % 2 != 0)
|
|
return nullptr;
|
|
|
|
Type ArgElts[] = { VecTy, VecTy };
|
|
TupleTypeElt ResultElts[] = { FirstTy, FirstTy };
|
|
Type ResultTy = TupleType::get(ResultElts, Context);
|
|
return getBuiltinFunction(Id, ArgElts, ResultTy);
|
|
}
|
|
|
|
static ValueDecl *getDeinterleaveOperation(ASTContext &Context, Identifier Id,
|
|
Type FirstTy) {
|
|
// (Vector<N,T>, Vector<N,T>) -> (Vector<N,T>, Vector<N,T>)
|
|
auto VecTy = FirstTy->getAs<BuiltinVectorType>();
|
|
// Require even length because we don't need anything else to support Swift's
|
|
// SIMD types and it saves us from having to define what happens for odd
|
|
// lengths until we actually need to care about them.
|
|
if (!VecTy || VecTy->getNumElements() % 2 != 0)
|
|
return nullptr;
|
|
|
|
Type ArgElts[] = { VecTy, VecTy };
|
|
TupleTypeElt ResultElts[] = { FirstTy, FirstTy };
|
|
Type ResultTy = TupleType::get(ResultElts, Context);
|
|
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<AnyBuiltinIntegerType>();
|
|
auto OutTy = OutputTy->getAs<BuiltinIntegerType>();
|
|
if (!InTy || !OutTy)
|
|
return nullptr;
|
|
if (isa<BuiltinIntegerLiteralType>(InTy)) {
|
|
if (!AllowLiteral)
|
|
return nullptr;
|
|
} else if (cast<BuiltinIntegerType>(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<BuiltinIntegerLiteralType>();
|
|
auto OutTy = OutputTy->getAs<BuiltinFloatType>();
|
|
if (!InTy || !OutTy)
|
|
return nullptr;
|
|
|
|
return getBuiltinFunction(Id, { InTy }, OutTy);
|
|
}
|
|
|
|
static ValueDecl *getBitWidthOperation(
|
|
ASTContext &ctx,
|
|
Identifier id,
|
|
Type valueTy
|
|
) {
|
|
if (!valueTy->getAs<BuiltinIntegerLiteralType>()) return nullptr;
|
|
return getBuiltinFunction(ctx, id, _thin, _parameters(valueTy), _word);
|
|
}
|
|
|
|
static ValueDecl *getIsNegativeOperation(
|
|
ASTContext &ctx,
|
|
Identifier id,
|
|
Type valueTy
|
|
) {
|
|
if (!valueTy->getAs<BuiltinIntegerLiteralType>()) return nullptr;
|
|
return getBuiltinFunction(ctx, id, _thin, _parameters(valueTy), _int(1));
|
|
}
|
|
|
|
static ValueDecl *getWordAtIndexOperation(
|
|
ASTContext &ctx,
|
|
Identifier id,
|
|
Type valueTy
|
|
) {
|
|
if (!valueTy->getAs<BuiltinIntegerLiteralType>()) 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<AnyFunctionType::Param, 1> 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<swift::Type, 3> 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) -> 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<AnyFunctionType::Param, 1> 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);
|
|
|
|
// <T: ~Copyable, E: Error>(
|
|
// _: (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<BuiltinIntegerType>();
|
|
case OverloadedBuiltinKind::IntegerOrVector:
|
|
return T->is<BuiltinIntegerType>() ||
|
|
(T->is<BuiltinVectorType>() &&
|
|
T->castTo<BuiltinVectorType>()->getElementType()
|
|
->is<BuiltinIntegerType>());
|
|
case OverloadedBuiltinKind::IntegerOrRawPointer:
|
|
return T->is<BuiltinIntegerType>() || T->is<BuiltinRawPointerType>();
|
|
case OverloadedBuiltinKind::IntegerOrRawPointerOrVector:
|
|
return T->is<BuiltinIntegerType>() || T->is<BuiltinRawPointerType>() ||
|
|
(T->is<BuiltinVectorType>() &&
|
|
T->castTo<BuiltinVectorType>()->getElementType()
|
|
->is<BuiltinIntegerType>());
|
|
case OverloadedBuiltinKind::Float:
|
|
return T->is<BuiltinFloatType>();
|
|
case OverloadedBuiltinKind::FloatOrVector:
|
|
return T->is<BuiltinFloatType>() ||
|
|
(T->is<BuiltinVectorType>() &&
|
|
T->castTo<BuiltinVectorType>()->getElementType()
|
|
->is<BuiltinFloatType>());
|
|
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<const char *> NameTable(&IntrinsicNameTable[1],
|
|
TargetInfos[1].Offset);
|
|
int Idx = Intrinsic::lookupLLVMIntrinsicByName(NameTable, Name);
|
|
return static_cast<Intrinsic::ID>(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<llvm::Intrinsic::IITDescriptor> &Table;
|
|
ArrayRef<Type> TypeArguments;
|
|
ASTContext &Context;
|
|
public:
|
|
IntrinsicTypeDecoder(ArrayRef<llvm::Intrinsic::IITDescriptor> &table,
|
|
ArrayRef<Type> 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<BuiltinVectorType>()) {
|
|
return makeVector(eltType, vectorType->getNumElements());
|
|
}
|
|
return eltType;
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
static Type DecodeIntrinsicType(ArrayRef<llvm::Intrinsic::IITDescriptor> &table,
|
|
ArrayRef<Type> 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<BuiltinVectorType>();
|
|
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<TupleTypeElt, 5> 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<Type> TypeArgs,
|
|
ASTContext &Context,
|
|
SmallVectorImpl<Type> &ArgElts,
|
|
Type &ResultTy) {
|
|
typedef llvm::Intrinsic::IITDescriptor IITDescriptor;
|
|
SmallVector<IITDescriptor, 8> Table;
|
|
getIntrinsicInfoTableEntries(ID, Table);
|
|
|
|
ArrayRef<IITDescriptor> 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<AtomicOrdering>(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<Type, 4> 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<Type, 8> 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<BuiltinIntegerType>() && !T->is<BuiltinRawPointerType>() &&
|
|
!T->is<BuiltinFloatType>())
|
|
return nullptr;
|
|
|
|
// Get and validate the ordering arguments, which are both required.
|
|
SmallVector<StringRef, 4> 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<BuiltinIntegerType>() && !Ty->is<BuiltinRawPointerType>())
|
|
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<BuiltinIntegerType>() && !T->is<BuiltinRawPointerType>() &&
|
|
!T->is<BuiltinFloatType>())
|
|
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<BuiltinIntegerType>() && !T->is<BuiltinRawPointerType>() &&
|
|
!T->is<BuiltinFloatType>())
|
|
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<BuiltinValueKind>(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:
|
|
case BuiltinValueKind::PrepareInitialization:
|
|
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::Interleave:
|
|
if (Types.size() != 1) return nullptr;
|
|
return getInterleaveOperation(Context, Id, Types[0]);
|
|
|
|
case BuiltinValueKind::Deinterleave:
|
|
if (Types.size() != 1) return nullptr;
|
|
return getDeinterleaveOperation(Context, Id, Types[0]);
|
|
|
|
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<TypeKind>::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<N, X> : BitwiseCopyable whenever X : BitwiseCopyable
|
|
auto bfa = cast<BuiltinFixedArrayType>(this);
|
|
auto &C = bfa->getASTContext();
|
|
return (bool)checkConformance(
|
|
bfa->getElementType(),
|
|
C.getProtocol(KnownProtocolKind::BitwiseCopyable));
|
|
}
|
|
}
|
|
}
|
|
|
|
StringRef BuiltinType::getTypeName(SmallVectorImpl<char> &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<const BuiltinVectorType>(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<const BuiltinIntegerType>(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<const BuiltinFloatType>(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<BuiltinFixedArrayType>(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<BuiltinUnboundGenericType>(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<BuiltinUnboundGenericType*>(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<BuiltinUnboundGenericType*>(this));
|
|
}
|
|
auto element = types[1]->getCanonicalType();
|
|
if (element->getMatchingParamKind() != GenericTypeParamKind::Type) {
|
|
return ErrorType::get(const_cast<BuiltinUnboundGenericType*>(this));
|
|
}
|
|
|
|
return BuiltinFixedArrayType::get(size, element);
|
|
}
|
|
|
|
case TypeKind::BuiltinInteger: {
|
|
auto size = subs.getReplacementTypes()[0];
|
|
if (size->getMatchingParamKind() != GenericTypeParamKind::Value) {
|
|
return ErrorType::get(const_cast<BuiltinUnboundGenericType*>(this));
|
|
}
|
|
|
|
// TODO: support actual generic parameters
|
|
auto literalSize = size->getAs<IntegerType>();
|
|
|
|
if (!literalSize) {
|
|
return ErrorType::get(const_cast<BuiltinUnboundGenericType*>(this));
|
|
}
|
|
|
|
return BuiltinIntegerType::get(literalSize->getValue().getLimitedValue(),
|
|
getASTContext());
|
|
}
|
|
|
|
default:
|
|
llvm_unreachable("not a generic builtin kind");
|
|
}
|
|
}
|
|
|
|
std::optional<uint64_t>
|
|
BuiltinFixedArrayType::getFixedInhabitedSize() const {
|
|
if (auto intSize = getSize()->getAs<IntegerType>()) {
|
|
if (intSize->getValue().isNegative()) {
|
|
return std::nullopt;
|
|
}
|
|
return intSize->getValue().getLimitedValue();
|
|
}
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
bool
|
|
BuiltinFixedArrayType::isFixedNegativeSize() const {
|
|
if (auto intSize = getSize()->getAs<IntegerType>()) {
|
|
return intSize->getValue().isNegative();
|
|
}
|
|
return false;
|
|
}
|