blob: fa0ea2c9a7cbd2dad05bc2e728e19cb87f224374 [file] [log] [blame]
//===--- Builtins.cpp - Swift Language Builtin ASTs -----------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file 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/FileUnit.h"
#include "swift/AST/Module.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/AST/Types.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) {
// Vectors are VecNxT, where "N" is the number of elements and
// T is the element type.
if (Name.startswith("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 == "NativeObject")
return Context.TheNativeObjectType;
if (Name == "BridgeObject")
return Context.TheBridgeObjectType;
if (Name == "SILToken")
return Context.TheSILTokenType;
if (Name == "UnsafeValueBuffer")
return Context.TheUnsafeValueBufferType;
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;
// 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 insane 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::get(Context, {},
/*HasExplicitAnyObject=*/true));
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;
}
/// Build a builtin function declaration.
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,
/*GenericParams=*/nullptr, paramList, ResType, DC);
FD->setAccess(AccessLevel::Public);
return FD;
}
template <class ExtInfoS, class ParamsS, class ResultS>
static FuncDecl *
getBuiltinFunction(ASTContext &ctx, Identifier id,
const ExtInfoS &extInfoS, const ParamsS &paramsS,
const ResultS &resultS) {
ModuleDecl *M = ctx.TheBuiltinModule;
DeclContext *DC = &M->getMainFile(FileUnitKind::Builtin);
SynthesisContext SC(ctx, DC);
auto params = synthesizeParameterList(SC, paramsS);
auto extInfo = synthesizeExtInfo(SC, extInfoS);
auto resultType = synthesizeType(SC, resultS);
DeclName name(ctx, id, params);
auto *FD = FuncDecl::createImplicit(
ctx, StaticSpellingKind::None, name, /*NameLoc=*/SourceLoc(),
extInfo.isAsync(), extInfo.isThrowing(),
/*GenericParams=*/nullptr, params, resultType, DC);
FD->setAccess(AccessLevel::Public);
return FD;
}
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) {
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,
GenericParams, paramList, ResType, DC);
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(Identifier Id, Type ArgType) {
auto &Context = ArgType->getASTContext();
// This is always "(i8*, IntTy) -> i8*"
Type ArgElts[] = { Context.TheRawPointerType, ArgType };
Type ResultTy = Context.TheRawPointerType;
return getBuiltinFunction(Id, ArgElts, ResultTy);
}
static ValueDecl *getStringObjectOrOperation(Identifier Id, Type ArgType) {
return getBuiltinFunction(Id, {ArgType, ArgType}, ArgType);
}
/// Build a binary operation declaration.
static ValueDecl *getBinaryOperation(Identifier Id, Type ArgType) {
return getBuiltinFunction(Id, { ArgType, ArgType }, ArgType);
}
/// Build a declaration for a binary operation with overflow.
static ValueDecl *getBinaryOperationWithOverflow(Identifier Id,
Type ArgType) {
auto &Context = ArgType->getASTContext();
Type ShouldCheckForOverflowTy = BuiltinIntegerType::get(1, Context);
Type ArgElts[] = { ArgType, ArgType, ShouldCheckForOverflowTy };
Type OverflowBitTy = BuiltinIntegerType::get(1, Context);
TupleTypeElt ResultElts[] = { ArgType, OverflowBitTy };
Type ResultTy = TupleType::get(ResultElts, Context);
return getBuiltinFunction(Id, ArgElts, ResultTy);
}
static ValueDecl *getUnaryOperation(Identifier Id, Type ArgType) {
return getBuiltinFunction(Id, { ArgType }, ArgType);
}
/// Build a binary predicate declaration.
static ValueDecl *getBinaryPredicate(Identifier Id, Type ArgType) {
auto &Context = ArgType->getASTContext();
Type ArgElts[] = { ArgType, ArgType };
Type ResultTy = BuiltinIntegerType::get(1, Context);
if (auto VecTy = ArgType->getAs<BuiltinVectorType>()) {
ResultTy = BuiltinVectorType::get(Context, ResultTy,
VecTy->getNumElements());
}
return getBuiltinFunction(Id, ArgElts, ResultTy);
}
/// 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;
// FIXME: Implement bitcast typechecking.
llvm_unreachable("Bitcast not supported yet!");
return nullptr;
}
return getBuiltinFunction(Id, { Input }, Output);
}
static const char * const GenericParamNames[] = {
"T",
"U",
"V",
"W",
"X",
"Y",
"Z"
};
static GenericTypeParamDecl*
createGenericParam(ASTContext &ctx, const char *name, unsigned index) {
ModuleDecl *M = ctx.TheBuiltinModule;
Identifier ident = ctx.getIdentifier(name);
auto genericParam =
new (ctx) GenericTypeParamDecl(&M->getMainFile(FileUnitKind::Builtin),
ident, SourceLoc(), 0, index);
return genericParam;
}
/// Create a generic parameter list with multiple generic parameters.
static GenericParamList *getGenericParams(ASTContext &ctx,
unsigned numParameters) {
assert(numParameters <= llvm::array_lengthof(GenericParamNames));
SmallVector<GenericTypeParamDecl *, 2> genericParams;
for (unsigned i = 0; i != numParameters; ++i)
genericParams.push_back(createGenericParam(ctx, GenericParamNames[i], i));
auto paramList = GenericParamList::create(ctx, SourceLoc(), genericParams,
SourceLoc());
return paramList;
}
namespace {
class BuiltinFunctionBuilder {
public:
ASTContext &Context;
private:
GenericParamList *TheGenericParamList;
SmallVector<AnyFunctionType::Param, 4> InterfaceParams;
Type InterfaceResult;
bool Async = false;
BuiltinThrowsKind Throws = BuiltinThrowsKind::None;
// Accumulate params and requirements here, so that we can make the
// appropriate `AbstractGenericSignatureRequest` when `build()` is called.
SmallVector<GenericTypeParamType *, 2> genericParamTypes;
SmallVector<Requirement, 2> addedRequirements;
public:
BuiltinFunctionBuilder(ASTContext &ctx, unsigned numGenericParams = 1,
bool wantsAdditionalAnyObjectRequirement = false)
: Context(ctx) {
TheGenericParamList = getGenericParams(ctx, numGenericParams);
if (wantsAdditionalAnyObjectRequirement) {
Requirement req(RequirementKind::Conformance,
TheGenericParamList->getParams()[0]->getInterfaceType(),
ctx.getAnyObjectType());
addedRequirements.push_back(req);
}
for (auto gp : TheGenericParamList->getParams()) {
genericParamTypes.push_back(
gp->getDeclaredInterfaceType()->castTo<GenericTypeParamType>());
}
}
template <class G>
void addParameter(const G &generator,
ValueOwnership ownership = ValueOwnership::Default) {
Type gTyIface = generator.build(*this);
auto flags = ParameterTypeFlags().withValueOwnership(ownership);
InterfaceParams.emplace_back(gTyIface, Identifier(), flags);
}
template <class G>
void setResult(const G &generator) {
InterfaceResult = generator.build(*this);
}
template <class G>
void addConformanceRequirement(const G &generator, ProtocolDecl *proto) {
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;
}
FuncDecl *build(Identifier name) {
auto GenericSig = evaluateOrDefault(
Context.evaluator,
AbstractGenericSignatureRequest{
nullptr, std::move(genericParamTypes), std::move(addedRequirements)},
nullptr);
return getBuiltinGenericFunction(name, InterfaceParams,
InterfaceResult,
TheGenericParamList, GenericSig,
Async, Throws);
}
// 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;
Optional<MetatypeRepresentation> Repr;
Type build(BuiltinFunctionBuilder &builder) const {
return MetatypeType::get(Object.build(builder), Repr);
}
};
};
} // 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, Optional<MetatypeRepresentation> repr = None) {
return { object, repr };
}
/// Create a function with type <T> T -> ().
static ValueDecl *getRefCountingOperation(ASTContext &Context, Identifier Id) {
BuiltinFunctionBuilder builder(Context);
builder.addParameter(makeGenericParam());
builder.setResult(makeConcrete(TupleType::getEmpty(Context)));
return builder.build(Id);
}
static ValueDecl *getLoadOperation(ASTContext &Context, Identifier Id) {
BuiltinFunctionBuilder builder(Context);
builder.addParameter(makeConcrete(Context.TheRawPointerType));
builder.setResult(makeGenericParam());
return builder.build(Id);
}
static ValueDecl *getStoreOperation(ASTContext &Context, Identifier Id) {
BuiltinFunctionBuilder builder(Context);
builder.addParameter(makeGenericParam(), ValueOwnership::Owned);
builder.addParameter(makeConcrete(Context.TheRawPointerType));
builder.setResult(makeConcrete(TupleType::getEmpty(Context)));
return builder.build(Id);
}
static ValueDecl *getDestroyOperation(ASTContext &Context, Identifier Id) {
BuiltinFunctionBuilder builder(Context);
builder.addParameter(makeMetatype(makeGenericParam()));
builder.addParameter(makeConcrete(Context.TheRawPointerType));
builder.setResult(makeConcrete(TupleType::getEmpty(Context)));
return builder.build(Id);
}
static ValueDecl *getDestroyArrayOperation(ASTContext &Context, Identifier Id) {
auto wordType = BuiltinIntegerType::get(BuiltinIntegerWidth::pointer(),
Context);
BuiltinFunctionBuilder builder(Context);
builder.addParameter(makeMetatype(makeGenericParam()));
builder.addParameter(makeConcrete(Context.TheRawPointerType));
builder.addParameter(makeConcrete(wordType));
builder.setResult(makeConcrete(TupleType::getEmpty(Context)));
return builder.build(Id);
}
static ValueDecl *getTransferArrayOperation(ASTContext &Context, Identifier Id){
auto wordType = BuiltinIntegerType::get(BuiltinIntegerWidth::pointer(),
Context);
BuiltinFunctionBuilder builder(Context);
builder.addParameter(makeMetatype(makeGenericParam()));
builder.addParameter(makeConcrete(Context.TheRawPointerType));
builder.addParameter(makeConcrete(Context.TheRawPointerType));
builder.addParameter(makeConcrete(wordType));
builder.setResult(makeConcrete(TupleType::getEmpty(Context)));
return builder.build(Id);
}
static ValueDecl *getIsUniqueOperation(ASTContext &Context, Identifier Id) {
// <T> (@inout T) -> Int1
Type Int1Ty = BuiltinIntegerType::get(1, Context);
BuiltinFunctionBuilder builder(Context);
builder.addParameter(makeGenericParam(), ValueOwnership::InOut);
builder.setResult(makeConcrete(Int1Ty));
return builder.build(Id);
}
static ValueDecl *getEndCOWMutation(ASTContext &Context, Identifier Id) {
// <T> (@inout T) -> ()
BuiltinFunctionBuilder builder(Context);
builder.addParameter(makeGenericParam(), ValueOwnership::InOut);
builder.setResult(makeConcrete(TupleType::getEmpty(Context)));
return builder.build(Id);
}
static ValueDecl *getBindMemoryOperation(ASTContext &Context, Identifier Id) {
BuiltinFunctionBuilder builder(Context);
builder.addParameter(makeConcrete(Context.TheRawPointerType));
builder.addParameter(makeConcrete(BuiltinIntegerType::getWordType(Context)));
builder.addParameter(makeMetatype(makeGenericParam()));
builder.setResult(makeConcrete(TupleType::getEmpty(Context)));
return builder.build(Id);
}
static ValueDecl *getAllocWithTailElemsOperation(ASTContext &Context,
Identifier Id,
int NumTailTypes) {
if (NumTailTypes < 1 ||
1 + NumTailTypes > (int)llvm::array_lengthof(GenericParamNames))
return nullptr;
BuiltinFunctionBuilder builder(Context, 1 + NumTailTypes);
builder.addParameter(makeMetatype(makeGenericParam(0)));
for (int Idx = 0; Idx < NumTailTypes; ++Idx) {
builder.addParameter(makeConcrete(BuiltinIntegerType::getWordType(Context)));
builder.addParameter(makeMetatype(makeGenericParam(Idx + 1)));
}
builder.setResult(makeGenericParam(0));
return builder.build(Id);
}
static ValueDecl *getProjectTailElemsOperation(ASTContext &Context,
Identifier Id) {
BuiltinFunctionBuilder builder(Context, 2);
builder.addParameter(makeGenericParam(0));
builder.addParameter(makeMetatype(makeGenericParam(1)));
builder.setResult(makeConcrete(Context.TheRawPointerType));
return builder.build(Id);
}
/// Build a getelementptr operation declaration.
static ValueDecl *getGepOperation(ASTContext &Context, Identifier Id,
Type ArgType) {
BuiltinFunctionBuilder builder(Context, 1);
builder.addParameter(makeConcrete(Context.TheRawPointerType));
builder.addParameter(makeConcrete(ArgType));
builder.addParameter(makeMetatype(makeGenericParam(0)));
builder.setResult(makeConcrete(Context.TheRawPointerType));
return builder.build(Id);
}
static ValueDecl *getGetTailAddrOperation(ASTContext &Context, Identifier Id,
Type ArgType) {
BuiltinFunctionBuilder builder(Context, 2);
builder.addParameter(makeConcrete(Context.TheRawPointerType));
builder.addParameter(makeConcrete(ArgType));
builder.addParameter(makeMetatype(makeGenericParam(0)));
builder.addParameter(makeMetatype(makeGenericParam(1)));
builder.setResult(makeConcrete(Context.TheRawPointerType));
return builder.build(Id);
}
static ValueDecl *getBeginUnpairedAccessOperation(ASTContext &Context,
Identifier Id) {
BuiltinFunctionBuilder builder(Context);
builder.addParameter(makeConcrete(Context.TheRawPointerType));
builder.addParameter(makeConcrete(Context.TheRawPointerType));
builder.addParameter(makeMetatype(makeGenericParam(0)));
builder.setResult(makeConcrete(Context.TheEmptyTupleType));
return builder.build(Id);
}
static ValueDecl *
getPerformInstantaneousReadAccessOperation(ASTContext &Context,
Identifier Id) {
BuiltinFunctionBuilder builder(Context);
builder.addParameter(makeConcrete(Context.TheRawPointerType));
builder.addParameter(makeMetatype(makeGenericParam(0)));
builder.setResult(makeConcrete(Context.TheEmptyTupleType));
return builder.build(Id);
}
static ValueDecl *getEndUnpairedAccessOperation(ASTContext &Context,
Identifier Id) {
return getBuiltinFunction(Id, { Context.TheRawPointerType },
Context.TheEmptyTupleType);
}
static ValueDecl *getSizeOrAlignOfOperation(ASTContext &Context,
Identifier Id) {
BuiltinFunctionBuilder builder(Context);
builder.addParameter(makeMetatype(makeGenericParam()));
builder.setResult(makeConcrete(BuiltinIntegerType::getWordType(Context)));
return builder.build(Id);
}
static ValueDecl *getIsPODOperation(ASTContext &Context, Identifier Id) {
BuiltinFunctionBuilder builder(Context);
builder.addParameter(makeMetatype(makeGenericParam()));
builder.setResult(makeConcrete(BuiltinIntegerType::get(1,Context)));
return builder.build(Id);
}
static ValueDecl *getIsConcrete(ASTContext &Context, Identifier Id) {
BuiltinFunctionBuilder builder(Context);
builder.addParameter(makeMetatype(makeGenericParam()));
builder.setResult(makeConcrete(BuiltinIntegerType::get(1,Context)));
return builder.build(Id);
}
static ValueDecl *getIsBitwiseTakable(ASTContext &Context, Identifier Id) {
BuiltinFunctionBuilder builder(Context);
builder.addParameter(makeMetatype(makeGenericParam()));
builder.setResult(makeConcrete(BuiltinIntegerType::get(1,Context)));
return builder.build(Id);
}
static ValueDecl *getIsOptionalOperation(ASTContext &Context, Identifier Id) {
BuiltinFunctionBuilder builder(Context);
builder.addParameter(makeMetatype(makeGenericParam()));
builder.setResult(makeConcrete(BuiltinIntegerType::get(1,Context)));
return builder.build(Id);
}
static ValueDecl *getIsSameMetatypeOperation(ASTContext &Context, Identifier Id) {
CanType anyMetatype = CanExistentialMetatypeType::get(Context.TheAnyType);
auto ResultTy = BuiltinIntegerType::get(1,Context);
return getBuiltinFunction(Id, {anyMetatype, anyMetatype}, ResultTy);
}
static ValueDecl *getAllocOperation(ASTContext &Context, Identifier Id) {
Type PtrSizeTy = BuiltinIntegerType::getWordType(Context);
Type ResultTy = Context.TheRawPointerType;
return getBuiltinFunction(Id, { PtrSizeTy, PtrSizeTy }, ResultTy);
}
static ValueDecl *getDeallocOperation(ASTContext &Context, Identifier Id) {
auto PtrSizeTy = BuiltinIntegerType::getWordType(Context);
Type ArgElts[] = { Context.TheRawPointerType, PtrSizeTy, PtrSizeTy };
Type ResultTy = TupleType::getEmpty(Context);
return getBuiltinFunction(Id, ArgElts, ResultTy);
}
static ValueDecl *getFenceOperation(ASTContext &Context, Identifier Id) {
return getBuiltinFunction(Id, {}, TupleType::getEmpty(Context));
}
static ValueDecl *getVoidErrorOperation(ASTContext &Context, Identifier Id) {
return getBuiltinFunction(Id, {Context.getExceptionType()},
TupleType::getEmpty(Context));
}
static ValueDecl *getUnexpectedErrorOperation(ASTContext &Context,
Identifier Id) {
return getBuiltinFunction(Id, {Context.getExceptionType()},
Context.getNeverType());
}
static ValueDecl *getCmpXChgOperation(ASTContext &Context, Identifier Id,
Type T) {
Type ArgElts[] = { Context.TheRawPointerType, T, T };
Type BoolTy = BuiltinIntegerType::get(1, Context);
Type ResultTy = TupleType::get({ T, BoolTy }, Context);
return getBuiltinFunction(Id, ArgElts, ResultTy);
}
static ValueDecl *getAtomicRMWOperation(ASTContext &Context, Identifier Id,
Type T) {
return getBuiltinFunction(Id, { Context.TheRawPointerType, T }, T);
}
static ValueDecl *getAtomicLoadOperation(ASTContext &Context, Identifier Id,
Type T) {
return getBuiltinFunction(Id, { Type(Context.TheRawPointerType) }, T);
}
static ValueDecl *getAtomicStoreOperation(ASTContext &Context, Identifier Id,
Type T) {
return getBuiltinFunction(Id, { Context.TheRawPointerType, T },
Context.TheEmptyTupleType);
}
static ValueDecl *getNativeObjectCast(ASTContext &Context, Identifier Id,
BuiltinValueKind BV) {
ValueOwnership ownership;
Type builtinTy;
switch (BV) {
case BuiltinValueKind::CastToNativeObject:
case BuiltinValueKind::UnsafeCastToNativeObject:
case BuiltinValueKind::CastFromNativeObject:
builtinTy = Context.TheNativeObjectType;
ownership = ValueOwnership::Owned;
break;
case BuiltinValueKind::BridgeToRawPointer:
case BuiltinValueKind::BridgeFromRawPointer:
builtinTy = Context.TheRawPointerType;
ownership = ValueOwnership::Default;
break;
default:
llvm_unreachable("unexpected kind");
}
BuiltinFunctionBuilder builder(Context);
if (BV == BuiltinValueKind::CastToNativeObject ||
BV == BuiltinValueKind::UnsafeCastToNativeObject ||
BV == BuiltinValueKind::BridgeToRawPointer) {
builder.addParameter(makeGenericParam(), ownership);
builder.setResult(makeConcrete(builtinTy));
} else {
builder.addParameter(makeConcrete(builtinTy), ownership);
builder.setResult(makeGenericParam());
}
return builder.build(Id);
}
static ValueDecl *getCastToBridgeObjectOperation(ASTContext &C,
Identifier Id) {
auto wordType = BuiltinIntegerType::get(BuiltinIntegerWidth::pointer(),
C);
BuiltinFunctionBuilder builder(C);
builder.addParameter(makeGenericParam(), ValueOwnership::Owned);
builder.addParameter(makeConcrete(wordType));
builder.setResult(makeConcrete(C.TheBridgeObjectType));
return builder.build(Id);
}
static ValueDecl *getCastFromBridgeObjectOperation(ASTContext &C,
Identifier Id,
BuiltinValueKind BV) {
Type BridgeTy = C.TheBridgeObjectType;
switch (BV) {
case BuiltinValueKind::CastReferenceFromBridgeObject: {
BuiltinFunctionBuilder builder(C);
builder.addParameter(makeConcrete(BridgeTy), ValueOwnership::Owned);
builder.setResult(makeGenericParam());
return builder.build(Id);
}
case BuiltinValueKind::CastBitPatternFromBridgeObject: {
Type WordTy = BuiltinIntegerType::get(BuiltinIntegerWidth::pointer(), C);
return getBuiltinFunction(Id, { BridgeTy }, WordTy);
}
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 &C, Identifier Id) {
BuiltinFunctionBuilder builder(C);
builder.addParameter(makeGenericParam(0));
builder.setResult(makeConcrete(C.TheBridgeObjectType));
return builder.build(Id);
}
static ValueDecl *getCOWBufferForReading(ASTContext &C, Identifier Id) {
// <T : AnyObject> T -> T
//
BuiltinFunctionBuilder builder(C, 1, true);
auto T = makeGenericParam();
builder.addParameter(T);
builder.setResult(T);
return builder.build(Id);
}
static ValueDecl *getUnsafeGuaranteed(ASTContext &C, Identifier Id) {
// <T : AnyObject> T -> (T, Int8Ty)
//
BuiltinFunctionBuilder builder(C);
auto T = makeGenericParam();
builder.addParameter(T);
Type Int8Ty = BuiltinIntegerType::get(8, C);
builder.setResult(makeTuple(T, makeConcrete(Int8Ty)));
return builder.build(Id);
}
static ValueDecl *getUnsafeGuaranteedEnd(ASTContext &C, Identifier Id) {
// Int8Ty -> ()
Type Int8Ty = BuiltinIntegerType::get(8, C);
return getBuiltinFunction(Id, { Int8Ty }, TupleType::getEmpty(C));
}
static ValueDecl *getIntInstrprofIncrement(ASTContext &C, Identifier Id) {
// (Builtin.RawPointer, Builtin.Int64, Builtin.Int32, Builtin.Int32) -> ()
Type Int64Ty = BuiltinIntegerType::get(64, C);
Type Int32Ty = BuiltinIntegerType::get(32, C);
return getBuiltinFunction(Id,
{C.TheRawPointerType, Int64Ty, Int32Ty, Int32Ty},
TupleType::getEmpty(C));
}
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), ValueOwnership::Owned);
builder.setResult(makeGenericParam(1));
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), ValueOwnership::Owned);
builder.setResult(makeGenericParam(1));
return builder.build(name);
}
static ValueDecl *getZeroInitializerOperation(ASTContext &Context,
Identifier Id) {
// <T> () -> T
BuiltinFunctionBuilder builder(Context);
builder.setResult(makeGenericParam());
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) {
assert(arity >= 1);
// JVP:
// <...T...(arity), R> (@differentiable (...T) throws -> R, ...T)
// rethrows -> (R, (...T.TangentVector) -> R.TangentVector)
// VJP:
// <...T...(arity), R> (@differentiable (...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()
.withDifferentiabilityKind(DifferentiabilityKind::Normal)
.withNoEscape()
.withThrows(throws)
.build();
SmallVector<FunctionType::Param, 2> params;
for (auto &paramGen : fnParamGens)
params.push_back(FunctionType::Param(paramGen.build(builder)));
auto innerFunction =
FunctionType::get(params, fnResultGen.build(builder));
return innerFunction->withExtInfo(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{
[=, &Context](BuiltinFunctionBuilder &builder) -> Type {
auto derivativeFnTy = diffFnType->getAutoDiffDerivativeFunctionType(
paramIndices, kind,
LookUpConformanceInModule(Context.TheBuiltinModule));
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) {
assert(arity >= 1);
// <...T...(arity), R>
// (@differentiable (...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)
.build();
SmallVector<FunctionType::Param, 2> params;
for (auto &paramGen : linearFnParamGens)
params.push_back(FunctionType::Param(paramGen.build(builder)));
auto innerFunction = FunctionType::get(params,
linearFnResultGen.build(builder));
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 *getDifferentiableFunctionConstructor(
ASTContext &Context, Identifier Id, unsigned arity, bool throws) {
assert(arity >= 1);
unsigned numGenericParams = 1 + arity;
BuiltinFunctionBuilder builder(Context, numGenericParams);
// Get the `Differentiable` and `AdditiveArithmetic` protocols.
auto *diffableProto =
Context.getProtocol(KnownProtocolKind::Differentiable);
auto *tangentVectorDecl =
diffableProto->getAssociatedType(Context.Id_TangentVector);
assert(tangentVectorDecl);
// Create type parameters and add conformance constraints.
auto origResultGen = makeGenericParam(arity);
builder.addConformanceRequirement(origResultGen, diffableProto);
SmallVector<decltype(origResultGen), 2> fnArgGens;
for (auto i : range(arity)) {
auto T = makeGenericParam(i);
builder.addConformanceRequirement(T, diffableProto);
fnArgGens.push_back(T);
}
BuiltinFunctionBuilder::LambdaGenerator origFnGen {
[=, &fnArgGens](BuiltinFunctionBuilder &builder) -> Type {
SmallVector<FunctionType::Param, 2> params;
for (auto &paramGen : fnArgGens)
params.push_back(FunctionType::Param(paramGen.build(builder)));
return FunctionType::get(params, origResultGen.build(builder))
->withExtInfo(FunctionType::ExtInfoBuilder(
FunctionTypeRepresentation::Swift, throws)
.build());
}
};
BuiltinFunctionBuilder::LambdaGenerator jvpGen {
[=, &fnArgGens, &Context](BuiltinFunctionBuilder &builder) -> Type {
SmallVector<FunctionType::Param, 2> params;
for (auto &paramGen : fnArgGens)
params.push_back(FunctionType::Param(paramGen.build(builder)));
auto origResultType = origResultGen.build(builder);
SmallVector<FunctionType::Param, 2> differentialParams;
for (auto &param : params) {
auto tanType = DependentMemberType::get(
param.getPlainType(), tangentVectorDecl);
differentialParams.push_back(FunctionType::Param(tanType));
}
auto differentialResultType = DependentMemberType::get(
origResultType, tangentVectorDecl);
auto differentialType =
FunctionType::get({differentialParams}, differentialResultType);
auto jvpResultType = TupleType::get(
{TupleTypeElt(origResultType, Context.Id_value),
TupleTypeElt(differentialType, Context.Id_differential)}, Context);
return FunctionType::get(params, jvpResultType)
->withExtInfo(FunctionType::ExtInfoBuilder(
FunctionTypeRepresentation::Swift, throws)
.build());
}
};
BuiltinFunctionBuilder::LambdaGenerator vjpGen {
[=, &fnArgGens, &Context](BuiltinFunctionBuilder &builder) -> Type {
SmallVector<FunctionType::Param, 2> params;
for (auto &paramGen : fnArgGens)
params.push_back(FunctionType::Param(paramGen.build(builder)));
auto origResultType = origResultGen.build(builder);
SmallVector<TupleTypeElt, 2> pullbackResultTupleElts;
for (auto &param : params) {
auto tanType = DependentMemberType::get(
param.getPlainType(), tangentVectorDecl);
pullbackResultTupleElts.push_back(TupleTypeElt(tanType));
}
auto pullbackParam = FunctionType::Param(
DependentMemberType::get(origResultType, tangentVectorDecl));
auto pullbackType = FunctionType::get(
{pullbackParam},
pullbackResultTupleElts.size() == 1
? pullbackResultTupleElts.front().getType()
: TupleType::get(pullbackResultTupleElts, Context));
auto vjpResultType = TupleType::get(
{TupleTypeElt(origResultType, Context.Id_value),
TupleTypeElt(pullbackType, Context.Id_pullback)}, Context);
return FunctionType::get(params, vjpResultType)
->withExtInfo(FunctionType::ExtInfoBuilder(
FunctionTypeRepresentation::Swift, throws)
.build());
}
};
BuiltinFunctionBuilder::LambdaGenerator resultGen {
[&](BuiltinFunctionBuilder &builder) -> Type {
auto origFnType = origFnGen.build(builder)->castTo<FunctionType>();
return origFnType->withExtInfo(
origFnType->getExtInfo()
.intoBuilder()
.withDifferentiabilityKind(DifferentiabilityKind::Normal)
.build());
}
};
builder.addParameter(origFnGen, ValueOwnership::Owned);
builder.addParameter(jvpGen, ValueOwnership::Owned);
builder.addParameter(vjpGen, ValueOwnership::Owned);
builder.setResult(resultGen);
return builder.build(Id);
}
static ValueDecl *getLinearFunctionConstructor(
ASTContext &Context, Identifier Id, unsigned arity, bool throws) {
assert(arity >= 1);
unsigned numGenericParams = 1 + arity;
BuiltinFunctionBuilder builder(Context, numGenericParams);
// Get the `Differentiable` and `AdditiveArithmetic` protocols.
auto *diffableProto =
Context.getProtocol(KnownProtocolKind::Differentiable);
auto *addArithProto =
Context.getProtocol(KnownProtocolKind::AdditiveArithmetic);
// Create type parameters and add conformance constraints.
auto origResultGen = makeGenericParam(arity);
builder.addConformanceRequirement(origResultGen, diffableProto);
builder.addConformanceRequirement(origResultGen, addArithProto);
SmallVector<decltype(origResultGen), 2> fnArgGens;
for (auto i : range(arity)) {
auto T = makeGenericParam(i);
builder.addConformanceRequirement(T, diffableProto);
builder.addConformanceRequirement(T, addArithProto);
fnArgGens.push_back(T);
}
BuiltinFunctionBuilder::LambdaGenerator origFnGen {
[=, &fnArgGens](BuiltinFunctionBuilder &builder) -> Type {
SmallVector<FunctionType::Param, 2> params;
for (auto &paramGen : fnArgGens)
params.push_back(FunctionType::Param(paramGen.build(builder)));
return FunctionType::get(params, origResultGen.build(builder))
->withExtInfo(FunctionType::ExtInfoBuilder(
FunctionTypeRepresentation::Swift, throws)
.build());
}
};
BuiltinFunctionBuilder::LambdaGenerator transposeFnGen {
[=, &fnArgGens, &Context](BuiltinFunctionBuilder &builder) -> Type {
auto origResultType = origResultGen.build(builder);
SmallVector<TupleTypeElt, 2> resultTupleElts;
for (auto &paramGen : fnArgGens)
resultTupleElts.push_back(paramGen.build(builder));
return FunctionType::get(
{FunctionType::Param(origResultType)},
resultTupleElts.size() == 1
? resultTupleElts.front().getType()
: TupleType::get(resultTupleElts, Context));
}
};
BuiltinFunctionBuilder::LambdaGenerator resultGen {
[&](BuiltinFunctionBuilder &builder) -> Type {
auto origFnType = origFnGen.build(builder)->castTo<FunctionType>();
return origFnType->withExtInfo(
origFnType->getExtInfo()
.intoBuilder()
.withDifferentiabilityKind(DifferentiabilityKind::Linear)
.build());
}
};
builder.addParameter(origFnGen, ValueOwnership::Owned);
builder.addParameter(transposeFnGen, ValueOwnership::Owned);
builder.setResult(resultGen);
return builder.build(Id);
}
static ValueDecl *getGlobalStringTablePointer(ASTContext &Context,
Identifier Id) {
// String -> Builtin.RawPointer
auto stringType = NominalType::get(Context.getStringDecl(), Type(), Context);
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), ValueOwnership::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), ValueOwnership::InOut); // Unmanaged
builder.setResult(makeGenericParam(2)); // Guaranteed Result
return builder.build(id);
}
static ValueDecl *getGetCurrentAsyncTask(ASTContext &ctx, Identifier id) {
return getBuiltinFunction(id, { }, ctx.TheNativeObjectType);
}
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 *getCreateAsyncTask(ASTContext &ctx, Identifier id) {
auto extInfo = ASTExtInfoBuilder().withAsync().withThrows().build();
return getBuiltinFunction(
id,
{ ctx.getIntDecl()->getDeclaredInterfaceType(),
OptionalType::get(ctx.TheNativeObjectType),
FunctionType::get({ }, ctx.TheEmptyTupleType, extInfo) },
getAsyncTaskAndContextType(ctx));
}
static ValueDecl *getCreateAsyncTaskFuture(ASTContext &ctx, Identifier id) {
BuiltinFunctionBuilder builder(ctx);
auto genericParam = makeGenericParam().build(builder);
builder.addParameter(
makeConcrete(ctx.getIntDecl()->getDeclaredInterfaceType()));
builder.addParameter(
makeConcrete(OptionalType::get(ctx.TheNativeObjectType)));
auto extInfo = ASTExtInfoBuilder().withAsync().withThrows().build();
builder.addParameter(
makeConcrete(FunctionType::get({ }, genericParam, extInfo)));
builder.setResult(makeConcrete(getAsyncTaskAndContextType(ctx)));
return builder.build(id);
}
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 *getAutoDiffCreateLinearMapContext(ASTContext &ctx,
Identifier id) {
return getBuiltinFunction(
id, {BuiltinIntegerType::getWordType(ctx)}, ctx.TheNativeObjectType);
}
static ValueDecl *getAutoDiffProjectTopLevelSubcontext(ASTContext &ctx,
Identifier id) {
return getBuiltinFunction(
id, {ctx.TheNativeObjectType}, ctx.TheRawPointerType);
}
static ValueDecl *getAutoDiffAllocateSubcontext(ASTContext &ctx,
Identifier id) {
return getBuiltinFunction(
id, {ctx.TheNativeObjectType, BuiltinIntegerType::getWordType(ctx)},
ctx.TheRawPointerType);
}
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(), ValueOwnership::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), ValueOwnership::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 *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 *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;
if (withContext) {
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)
.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);
}
static ValueDecl *getPolymorphicBinaryOperation(ASTContext &ctx,
Identifier id) {
BuiltinFunctionBuilder builder(ctx);
builder.addParameter(makeGenericParam());
builder.addParameter(makeGenericParam());
builder.setResult(makeGenericParam());
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));
builder.setResult(makeGenericParam());
builder.setAsync();
if (throws)
builder.setThrows();
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.startswith("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::Metadata:
case IITDescriptor::ExtendArgument:
case IITDescriptor::TruncArgument:
case IITDescriptor::HalfVecArgument:
case IITDescriptor::VarArg:
case IITDescriptor::Token:
case IITDescriptor::VecElementArgument:
case IITDescriptor::VecOfAnyPtrsToElt:
case IITDescriptor::VecOfBitcastsToInt:
case IITDescriptor::Subdivide2Argument:
case IITDescriptor::Subdivide4Argument:
// 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.Min);
}
// 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 pointer to a type argument.
case IITDescriptor::PtrToArgument: {
Type argType = getTypeArgument(D.getArgumentNumber());
if (!argType) return Type();
unsigned addrspace = 0; // An apparent limitation of LLVM.
return makePointer(argType, addrspace);
}
// 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 pointer to the element type of a type argument, which must be a vector.
case IITDescriptor::PtrToElt: {
Type argType = getTypeArgument(D.getArgumentNumber());
if (!argType) return Type();
auto vecType = argType->getAs<BuiltinVectorType>();
if (!vecType) return Type();
unsigned addrspace = 0; // An apparent limitation of LLVM.
return makePointer(vecType->getElementType(), addrspace);
}
// 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.hasAttribute(llvm::AttributeList::FunctionIndex,
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) {
#if SWIFT_BUILD_ONLY_SYNTAXPARSERLIB
return nullptr; // not needed for the parser library.
#endif
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.startswith("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.startswith("_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.startswith("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.startswith("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.startswith("_volatile"))
OperationName = OperationName.drop_front(strlen("_volatile"));
if (OperationName.startswith("_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.startswith("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.startswith("_volatile"))
OperationName = OperationName.drop_front(strlen("_volatile"));
if (OperationName.startswith("_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.startswith("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.startswith("_volatile"))
OperationName = OperationName.drop_front(strlen("_volatile"));
if (OperationName.startswith("_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.startswith("allocWithTailElems_")) {
OperationName = OperationName.drop_front(strlen("allocWithTailElems_"));
int NumTailTypes = 0;
if (OperationName.getAsInteger(10, NumTailTypes))
return nullptr;
return getAllocWithTailElemsOperation(Context, Id, NumTailTypes);
}
if (OperationName.startswith("applyDerivative_")) {
AutoDiffDerivativeFunctionKind kind;
unsigned arity;
bool throws;
if (!autodiff::getBuiltinApplyDerivativeConfig(
OperationName, kind, arity, throws))
return nullptr;
return getAutoDiffApplyDerivativeFunction(Context, Id, kind, arity,
throws);
}
if (OperationName.startswith("applyTranspose_")) {
unsigned arity;
bool throws;
if (!autodiff::getBuiltinApplyTransposeConfig(
OperationName, arity, throws))
return nullptr;
return getAutoDiffApplyTransposeFunction(Context, Id, arity, throws);
}
if (OperationName.startswith("differentiableFunction_")) {
unsigned arity;
bool throws;
if (!autodiff::getBuiltinDifferentiableOrLinearFunctionConfig(
OperationName, arity, throws))
return nullptr;
return getDifferentiableFunctionConstructor(Context, Id, arity, throws);
}
if (OperationName.startswith("linearFunction_")) {
unsigned arity;
bool throws;
if (!autodiff::getBuiltinDifferentiableOrLinearFunctionConfig(
OperationName, arity, throws))
return nullptr;
return getLinearFunctionConstructor(Context, Id, arity, throws);
}
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::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(Id, Types[0]);
case BuiltinValueKind::StringObjectOr:
if (Types.size() != 1)
return nullptr;
return getStringObjectOrOperation(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);
#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(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(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(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(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:
case BuiltinValueKind::Take:
if (!Types.empty()) return nullptr;
return getLoadOperation(Context, Id);
case BuiltinValueKind::Destroy:
if (!Types.empty()) return nullptr;
return getDestroyOperation(Context, Id);
case BuiltinValueKind::Assign:
case BuiltinValueKind::Init:
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::TakeArrayNoAlias:
case BuiltinValueKind::TakeArrayFrontToBack:
case BuiltinValueKind::TakeArrayBackToFront:
case BuiltinValueKind::AssignCopyArrayNoAlias:
case BuiltinValueKind::AssignCopyArrayFrontToBack:
case BuiltinValueKind::AssignCopyArrayBackToFront:
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::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::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:
if (!Types.empty()) return nullptr;
return getAddressOfOperation(Context, Id);
case BuiltinValueKind::LegacyCondFail:
return getLegacyCondFailOperation(Context, Id);
case BuiltinValueKind::AddressOfBorrow:
if (!Types.empty()) return nullptr;
return getAddressOfBorrowOperation(Context, Id);
case BuiltinValueKind::CondFailMessage:
return getCondFailOperation(Context, Id);
case BuiltinValueKind::AssertConf:
return getAssertConfOperation(Context, Id);
case BuiltinValueKind::FixLifetime:
return getFixLifetimeOperation(Context, Id);
case BuiltinValueKind::CanBeObjCClass:
return getCanBeObjCClassOperation(Context, Id);
case BuiltinValueKind::CondUnreachable:
case BuiltinValueKind::Unreachable:
return getUnreachableOperation(Context, Id);
case BuiltinValueKind::ZeroInitializer:
return getZeroInitializerOperation(Context, Id);
case BuiltinValueKind::Once:
case BuiltinValueKind::OnceWithContext:
return getOnceOperation(Context, Id, BV == BuiltinValueKind::OnceWithContext);
case BuiltinValueKind::WillThrow:
case BuiltinValueKind::ErrorInMain:
return getVoidErrorOperation(Context, Id);
case BuiltinValueKind::UnexpectedError:
return getUnexpectedErrorOperation(Context, Id);
case BuiltinValueKind::ExtractElement:
if (Types.size() != 2) return nullptr;
return getExtractElementOperation(Context, Id, Types[0], Types[1]);
case BuiltinValueKind::InsertElement:
if (Types.size() != 3) return nullptr;
return getInsertElementOperation(Context, Id, Types[0], Types[1], Types[2]);
case BuiltinValueKind::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::UnsafeGuaranteed:
return getUnsafeGuaranteed(Context, Id);
case BuiltinValueKind::UnsafeGuaranteedEnd:
return getUnsafeGuaranteedEnd(Context, Id);
case BuiltinValueKind::ApplyDerivative:
case BuiltinValueKind::ApplyTranspose:
case BuiltinValueKind::DifferentiableFunction:
case BuiltinValueKind::LinearFunction:
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::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::CancelAsyncTask:
return getCancelAsyncTask(Context, Id);
case BuiltinValueKind::CreateAsyncTask:
return getCreateAsyncTask(Context, Id);
case BuiltinValueKind::CreateAsyncTaskFuture:
return getCreateAsyncTaskFuture(Context, Id);
case BuiltinValueKind::ConvertTaskToJob:
return getConvertTaskToJob(Context, Id);
case BuiltinValueKind::PoundAssert:
return getPoundAssert(Context, Id);
case BuiltinValueKind::TSanInoutAccess:
return getTSanInoutAccess(Context, Id);
case BuiltinValueKind::Swift3ImplicitObjCEntrypoint:
return getBuiltinFunction(Id,
{},
TupleType::getEmpty(Context));
case BuiltinValueKind::IntInstrprofIncrement:
return getIntInstrprofIncrement(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::DestroyDefaultActor:
return getDefaultActorInitDestroy(Context, Id);
case BuiltinValueKind::WithUnsafeContinuation:
return getWithUnsafeContinuation(Context, Id, /*throws=*/false);
case BuiltinValueKind::WithUnsafeThrowingContinuation:
return getWithUnsafeContinuation(Context, Id, /*throws=*/true);
case BuiltinValueKind::AutoDiffCreateLinearMapContext:
return getAutoDiffCreateLinearMapContext(Context, Id);
case BuiltinValueKind::AutoDiffProjectTopLevelSubcontext:
return getAutoDiffProjectTopLevelSubcontext(Context, Id);
case BuiltinValueKind::AutoDiffAllocateSubcontext:
return getAutoDiffAllocateSubcontext(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()));
}
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::BuiltinDefaultActorStorage:
printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_DEFAULTACTORSTORAGE);
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.startswith(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;
}
}
#undef MAYBE_GET_NAMESPACED_BUILTIN
return printer.str();
}