blob: 58203c014d1deb419733a8c7bb69eb9e8aaf5a2c [file] [log] [blame]
//===--- TypeLowering.cpp - Type information for SILGen -------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "libsil"
#include "swift/AST/AnyFunctionRef.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/CanTypeVisitor.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/DiagnosticsSIL.h"
#include "swift/AST/Expr.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/LazyResolver.h"
#include "swift/AST/Module.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/Pattern.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/PropertyWrappers.h"
#include "swift/AST/TypeDifferenceVisitor.h"
#include "swift/AST/Types.h"
#include "swift/ClangImporter/ClangModule.h"
#include "swift/SIL/PrettyStackTrace.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/TypeLowering.h"
#include "clang/AST/Type.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
using namespace swift;
using namespace Lowering;
namespace {
/// A CRTP type visitor for deciding whether the metatype for a type
/// is a singleton type, i.e. whether there can only ever be one
/// such value.
struct HasSingletonMetatype : CanTypeVisitor<HasSingletonMetatype, bool> {
/// Class metatypes have non-trivial representation due to the
/// possibility of subclassing.
bool visitClassType(CanClassType type) {
return false;
}
bool visitBoundGenericClassType(CanBoundGenericClassType type) {
return false;
}
bool visitDynamicSelfType(CanDynamicSelfType type) {
return false;
}
/// Dependent types have non-trivial representation in case they
/// instantiate to a class metatype.
bool visitGenericTypeParamType(CanGenericTypeParamType type) {
return false;
}
bool visitDependentMemberType(CanDependentMemberType type) {
return false;
}
/// Archetype metatypes have non-trivial representation in case
/// they instantiate to a class metatype.
bool visitArchetypeType(CanArchetypeType type) {
return false;
}
/// All levels of class metatypes support subtyping.
bool visitMetatypeType(CanMetatypeType type) {
return visit(type.getInstanceType());
}
/// Everything else is trivial. Note that ordinary metatypes of
/// existential types are still singleton.
bool visitType(CanType type) {
return true;
}
};
} // end anonymous namespace
/// Does the metatype for the given type have a known-singleton
/// representation?
static bool hasSingletonMetatype(CanType instanceType) {
return HasSingletonMetatype().visit(instanceType);
}
CaptureKind TypeConverter::getDeclCaptureKind(CapturedValue capture,
TypeExpansionContext expansion) {
auto decl = capture.getDecl();
auto *var = cast<VarDecl>(decl);
assert(var->hasStorage() &&
"should not have attempted to directly capture this variable");
// If this is a non-address-only stored 'let' constant, we can capture it
// by value. If it is address-only, then we can't load it, so capture it
// by its address (like a var) instead.
if (!var->supportsMutation() &&
!getTypeLowering(var->getType(),
TypeExpansionContext::noOpaqueTypeArchetypesSubstitution(
expansion.getResilienceExpansion()))
.isAddressOnly())
return CaptureKind::Constant;
// In-out parameters are captured by address.
if (auto *param = dyn_cast<ParamDecl>(var)) {
if (param->isInOut())
return CaptureKind::StorageAddress;
}
// Reference storage types can appear in a capture list, which means
// we might allocate boxes to store the captures. However, those boxes
// have the same lifetime as the closure itself, so we must capture
// the box itself and not the payload, even if the closure is noescape,
// otherwise they will be destroyed when the closure is formed.
if (var->getType()->is<ReferenceStorageType>()) {
return CaptureKind::Box;
}
// For 'let' constants
if (!var->supportsMutation()) {
assert(getTypeLowering(
var->getType(),
TypeExpansionContext::noOpaqueTypeArchetypesSubstitution(
expansion.getResilienceExpansion()))
.isAddressOnly());
return CaptureKind::Immutable;
}
// If we're capturing into a non-escaping closure, we can generally just
// capture the address of the value as no-escape.
return (capture.isNoEscape()
? CaptureKind::StorageAddress
: CaptureKind::Box);
}
using RecursiveProperties = TypeLowering::RecursiveProperties;
static RecursiveProperties
classifyType(AbstractionPattern origType, CanType type,
TypeConverter &TC, TypeExpansionContext expansion);
namespace {
/// A CRTP helper class for doing things that depends on type
/// classification.
template <class Impl, class RetTy>
class TypeClassifierBase
: public CanTypeVisitor<Impl, RetTy, AbstractionPattern, IsTypeExpansionSensitive_t>
{
Impl &asImpl() { return *static_cast<Impl*>(this); }
protected:
TypeConverter &TC;
TypeExpansionContext Expansion;
TypeClassifierBase(TypeConverter &TC, TypeExpansionContext Expansion)
: TC(TC), Expansion(Expansion) {}
public:
// The subclass should implement:
// // Trivial, fixed-layout, and non-address-only.
// RetTy handleTrivial(CanType);
// RetTy handleTrivial(CanType, RecursiveProperties properties);
// // A reference type.
// RetTy handleReference(CanType, RecursiveProperties properties);
// RetTy handleReference(CanType, RecursiveProperties properties);
// // Non-trivial and address-only.
// RetTy handleAddressOnly(CanType, RecursiveProperties properties);
// and, if it doesn't override handleTupleType,
// // An aggregate type that's non-trivial.
// RetTy handleNonTrivialAggregate(CanType, RecursiveProperties properties);
//
// Alternatively, it can just implement:
// RetTy handle(CanType, RecursiveProperties properties);
/// Handle a trivial, fixed-size, loadable type.
RetTy handleTrivial(CanType type, RecursiveProperties properties) {
return asImpl().handle(type, properties);
}
RetTy handleAddressOnly(CanType type, RecursiveProperties properties) {
return asImpl().handle(type, properties);
}
RetTy handleNonTrivialAggregate(CanType type,
RecursiveProperties properties) {
return asImpl().handle(type, properties);
}
RetTy handleTrivial(CanType type) {
return asImpl().handleTrivial(type, RecursiveProperties::forTrivial());
}
RetTy handleReference(CanType type) {
return handleReference(type, RecursiveProperties::forReference());
}
RetTy handleReference(CanType type, RecursiveProperties properties) {
return asImpl().handle(type, properties);
}
RecursiveProperties
mergeIsTypeExpansionSensitive(IsTypeExpansionSensitive_t isSensitive,
RecursiveProperties props) {
if (isSensitive == IsTypeExpansionSensitive)
props.setTypeExpansionSensitive(isSensitive);
return props;
}
RecursiveProperties
getTrivialRecursiveProperties(IsTypeExpansionSensitive_t isSensitive) {
return mergeIsTypeExpansionSensitive(isSensitive,
RecursiveProperties::forTrivial());
}
RecursiveProperties
getReferenceRecursiveProperties(IsTypeExpansionSensitive_t isSensitive) {
return mergeIsTypeExpansionSensitive(isSensitive,
RecursiveProperties::forReference());
}
RecursiveProperties
getOpaqueRecursiveProperties(IsTypeExpansionSensitive_t isSensitive) {
return mergeIsTypeExpansionSensitive(isSensitive,
RecursiveProperties::forOpaque());
}
#define IMPL(TYPE, LOWERING) \
RetTy visit##TYPE##Type(Can##TYPE##Type type, AbstractionPattern orig, \
IsTypeExpansionSensitive_t isSensitive) { \
return asImpl().handle##LOWERING(type, \
get##LOWERING##RecursiveProperties(isSensitive)); \
}
IMPL(BuiltinInteger, Trivial)
IMPL(BuiltinIntegerLiteral, Trivial)
IMPL(BuiltinFloat, Trivial)
IMPL(BuiltinRawPointer, Trivial)
IMPL(BuiltinRawUnsafeContinuation, Trivial)
IMPL(BuiltinJob, Trivial)
IMPL(BuiltinNativeObject, Reference)
IMPL(BuiltinBridgeObject, Reference)
IMPL(BuiltinVector, Trivial)
IMPL(SILToken, Trivial)
IMPL(Class, Reference)
IMPL(BoundGenericClass, Reference)
IMPL(AnyMetatype, Trivial)
IMPL(Module, Trivial)
#undef IMPL
RetTy visitBuiltinUnsafeValueBufferType(
CanBuiltinUnsafeValueBufferType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
return asImpl().handleAddressOnly(type, {IsNotTrivial, IsFixedABI,
IsAddressOnly, IsNotResilient,
isSensitive});
}
RetTy visitBuiltinDefaultActorStorageType(
CanBuiltinDefaultActorStorageType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
return asImpl().handleAddressOnly(type, {IsNotTrivial, IsFixedABI,
IsAddressOnly, IsNotResilient,
isSensitive});
}
RetTy visitAnyFunctionType(CanAnyFunctionType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
switch (type->getRepresentation()) {
case AnyFunctionType::Representation::Swift:
case AnyFunctionType::Representation::Block:
return asImpl().handleReference(
type, getReferenceRecursiveProperties(isSensitive));
case AnyFunctionType::Representation::CFunctionPointer:
case AnyFunctionType::Representation::Thin:
return asImpl().handleTrivial(
type, getTrivialRecursiveProperties(isSensitive));
}
llvm_unreachable("bad function representation");
}
RetTy visitSILFunctionType(CanSILFunctionType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
// Handle `@differentiable` and `@differentiable(linear)` functions.
switch (type->getDifferentiabilityKind()) {
case DifferentiabilityKind::Normal:
return asImpl().visitNormalDifferentiableSILFunctionType(
type, mergeIsTypeExpansionSensitive(
isSensitive,
getNormalDifferentiableSILFunctionTypeRecursiveProperties(
type, origType)));
case DifferentiabilityKind::Linear:
return asImpl().visitLinearDifferentiableSILFunctionType(
type, mergeIsTypeExpansionSensitive(
isSensitive,
getLinearDifferentiableSILFunctionTypeRecursiveProperties(
type, origType)));
case DifferentiabilityKind::NonDifferentiable:
break;
}
// Only escaping closures are references.
bool isSwiftEscaping = type->getExtInfo().isNoEscape() &&
type->getExtInfo().getRepresentation() ==
SILFunctionType::Representation::Thick;
if (type->getExtInfo().hasContext() && !isSwiftEscaping)
return asImpl().handleReference(
type, getReferenceRecursiveProperties(isSensitive));
// No escaping closures are trivial types.
return asImpl().handleTrivial(type,
getTrivialRecursiveProperties(isSensitive));
}
RecursiveProperties
getNormalDifferentiableSILFunctionTypeRecursiveProperties(
CanSILFunctionType type, AbstractionPattern origType) {
auto &M = TC.M;
auto origTy = type->getWithoutDifferentiability();
// Pass the `AbstractionPattern` generic signature to
// `SILFunctionType:getAutoDiffDerivativeFunctionType` for correct type
// lowering.
auto jvpTy = origTy->getAutoDiffDerivativeFunctionType(
type->getDifferentiabilityParameterIndices(),
type->getDifferentiabilityResultIndices(),
AutoDiffDerivativeFunctionKind::JVP, TC,
LookUpConformanceInModule(&M), CanGenericSignature());
auto vjpTy = origTy->getAutoDiffDerivativeFunctionType(
type->getDifferentiabilityParameterIndices(),
type->getDifferentiabilityResultIndices(),
AutoDiffDerivativeFunctionKind::VJP, TC,
LookUpConformanceInModule(&M), CanGenericSignature());
RecursiveProperties props;
props.addSubobject(classifyType(origType, origTy, TC, Expansion));
props.addSubobject(classifyType(origType, jvpTy, TC, Expansion));
props.addSubobject(classifyType(origType, vjpTy, TC, Expansion));
return props;
}
RecursiveProperties
getLinearDifferentiableSILFunctionTypeRecursiveProperties(
CanSILFunctionType type, AbstractionPattern origType) {
auto &M = TC.M;
auto origTy = type->getWithoutDifferentiability();
auto transposeTy = origTy->getAutoDiffTransposeFunctionType(
type->getDifferentiabilityParameterIndices(), TC,
LookUpConformanceInModule(&M), origType.getGenericSignatureOrNull());
RecursiveProperties props;
props.addSubobject(classifyType(origType, origTy, TC, Expansion));
props.addSubobject(classifyType(origType, transposeTy, TC, Expansion));
return props;
}
RetTy visitNormalDifferentiableSILFunctionType(
CanSILFunctionType type, RecursiveProperties props) {
return handleAggregateByProperties(type, props);
}
RetTy visitLinearDifferentiableSILFunctionType(
CanSILFunctionType type, RecursiveProperties props) {
return handleAggregateByProperties(type, props);
}
RetTy visitLValueType(CanLValueType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t) {
llvm_unreachable("shouldn't get an l-value type here");
}
RetTy visitInOutType(CanInOutType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t) {
llvm_unreachable("shouldn't get an inout type here");
}
RetTy visitErrorType(CanErrorType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
return asImpl().handleTrivial(type,
getTrivialRecursiveProperties(isSensitive));
}
// Dependent types can be lowered according to their corresponding
// abstraction pattern.
RetTy visitAbstractTypeParamType(CanType type, AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
if (origType.isTypeParameterOrOpaqueArchetype() ||
origType.isOpaqueFunctionOrOpaqueDerivativeFunction()) {
if (origType.requiresClass()) {
return asImpl().handleReference(
type, getReferenceRecursiveProperties(isSensitive));
} else {
return asImpl().handleAddressOnly(
type, getOpaqueRecursiveProperties(isSensitive));
}
} else {
// If the abstraction pattern provides a concrete type, lower as that
// type. This can occur if the abstraction pattern provides a more
// constrained generic signature with more same-type constraints than
// the original declaration whose type we're lowering.
return asImpl().visit(origType.getType(), origType, isSensitive);
}
}
RetTy visitGenericTypeParamType(CanGenericTypeParamType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
return visitAbstractTypeParamType(type, origType, isSensitive);
}
RetTy visitDependentMemberType(CanDependentMemberType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
return visitAbstractTypeParamType(type, origType, isSensitive);
}
Type getConcreteReferenceStorageReferent(Type type) {
if (type->isTypeParameter()) {
return TC.Context.getAnyObjectType();
}
return type;
}
#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
RetTy visit##Name##StorageType(Can##Name##StorageType type, \
AbstractionPattern origType, \
IsTypeExpansionSensitive_t isSensitive) { \
return asImpl().handleAddressOnly(type, {IsNotTrivial, \
IsFixedABI, \
IsAddressOnly, \
IsNotResilient, \
isSensitive}); \
}
#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
RetTy visit##Name##StorageType(Can##Name##StorageType type, \
AbstractionPattern origType, \
IsTypeExpansionSensitive_t isSensitive) { \
return asImpl().handleReference(type, \
getReferenceRecursiveProperties(isSensitive)); \
}
#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
RetTy visitLoadable##Name##StorageType(Can##Name##StorageType type, \
AbstractionPattern origType, \
IsTypeExpansionSensitive_t isSensitive) { \
return asImpl().handleReference(type, \
getReferenceRecursiveProperties(isSensitive)); \
} \
RetTy visitAddressOnly##Name##StorageType(Can##Name##StorageType type, \
AbstractionPattern origType, \
IsTypeExpansionSensitive_t isSensitive) { \
return asImpl().handleAddressOnly(type, {IsNotTrivial, \
IsFixedABI, \
IsAddressOnly, \
IsNotResilient, \
isSensitive}); \
} \
RetTy visit##Name##StorageType(Can##Name##StorageType type, \
AbstractionPattern origType, \
IsTypeExpansionSensitive_t isSensitive) { \
auto referentType = \
type->getReferentType()->lookThroughSingleOptionalType(); \
auto concreteType = getConcreteReferenceStorageReferent(referentType); \
if (Name##StorageType::get(concreteType, TC.Context) \
->isLoadable(Expansion.getResilienceExpansion())) { \
return asImpl().visitLoadable##Name##StorageType(type, origType, \
isSensitive); \
} else { \
return asImpl().visitAddressOnly##Name##StorageType(type, origType, \
isSensitive); \
} \
}
#define UNCHECKED_REF_STORAGE(Name, ...) \
RetTy visit##Name##StorageType(Can##Name##StorageType type, \
AbstractionPattern origType, \
IsTypeExpansionSensitive_t isSensitive) { \
return asImpl().handleTrivial(type, \
getTrivialRecursiveProperties(isSensitive)); \
}
#include "swift/AST/ReferenceStorage.def"
RetTy visitOpaqueTypeArchetypeType(CanOpaqueTypeArchetypeType ty,
AbstractionPattern origType, \
IsTypeExpansionSensitive_t) {
auto replacedTy = substOpaqueTypesWithUnderlyingTypes(ty, Expansion);
if (replacedTy == ty)
return visitArchetypeType(ty, origType, IsTypeExpansionSensitive);
return this->visit(replacedTy, origType, IsTypeExpansionSensitive);
}
RetTy visitArchetypeType(CanArchetypeType ty, AbstractionPattern origType) {
return visitArchetypeType(ty, origType, IsNotTypeExpansionSensitive);
}
RetTy
visitArchetypeType(CanArchetypeType type, AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
auto LayoutInfo = type->getLayoutConstraint();
if (LayoutInfo) {
if (LayoutInfo->isFixedSizeTrivial()) {
return asImpl().handleTrivial(
type, getTrivialRecursiveProperties(isSensitive));
}
if (LayoutInfo->isAddressOnlyTrivial()) {
auto properties = getTrivialRecursiveProperties(isSensitive);
properties.setAddressOnly();
return asImpl().handleAddressOnly(type, properties);
}
if (LayoutInfo->isRefCounted()) {
return asImpl().handleReference(
type, getReferenceRecursiveProperties(isSensitive));
}
}
return asImpl().handleAddressOnly(
type, getOpaqueRecursiveProperties(isSensitive));
}
RetTy visitExistentialType(CanType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
switch (SILType::getPrimitiveObjectType(type)
.getPreferredExistentialRepresentation()) {
case ExistentialRepresentation::None:
llvm_unreachable("not an existential type?!");
// Opaque existentials are address-only.
case ExistentialRepresentation::Opaque:
return asImpl().handleAddressOnly(type, {IsNotTrivial,
IsFixedABI,
IsAddressOnly,
IsNotResilient,
isSensitive});
// Class-constrained and boxed existentials are refcounted.
case ExistentialRepresentation::Class:
case ExistentialRepresentation::Boxed:
return asImpl().handleReference(
type, getReferenceRecursiveProperties(isSensitive));
// Existential metatypes are trivial.
case ExistentialRepresentation::Metatype:
return asImpl().handleTrivial(
type, getTrivialRecursiveProperties(isSensitive));
}
llvm_unreachable("Unhandled ExistentialRepresentation in switch.");
}
RetTy visitProtocolType(CanProtocolType type, AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
return visitExistentialType(type, origType, isSensitive);
}
RetTy visitProtocolCompositionType(CanProtocolCompositionType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
return visitExistentialType(type, origType, isSensitive);
}
// Enums depend on their enumerators.
RetTy visitEnumType(CanEnumType type, AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
return asImpl().visitAnyEnumType(type, origType, type->getDecl(),
isSensitive);
}
RetTy visitBoundGenericEnumType(CanBoundGenericEnumType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
return asImpl().visitAnyEnumType(type, origType, type->getDecl(),
isSensitive);
}
// Structs depend on their physical fields.
RetTy visitStructType(CanStructType type, AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
return asImpl().visitAnyStructType(type, origType, type->getDecl(),
isSensitive);
}
RetTy visitBoundGenericStructType(CanBoundGenericStructType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
return asImpl().visitAnyStructType(type, origType, type->getDecl(),
isSensitive);
}
// Tuples depend on their elements.
RetTy visitTupleType(CanTupleType type, AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
RecursiveProperties props;
for (unsigned i = 0, e = type->getNumElements(); i < e; ++i) {
props.addSubobject(classifyType(origType.getTupleElementType(i),
type.getElementType(i),
TC, Expansion));
}
props = mergeIsTypeExpansionSensitive(isSensitive, props);
return asImpl().handleAggregateByProperties(type, props);
}
RetTy visitDynamicSelfType(CanDynamicSelfType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
return this->visit(type.getSelfType(), origType, isSensitive);
}
RetTy visitSILBlockStorageType(CanSILBlockStorageType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
// Should not be loaded.
return asImpl().handleAddressOnly(type, {IsNotTrivial,
IsFixedABI,
IsAddressOnly,
IsNotResilient,
isSensitive});
}
RetTy visitSILBoxType(CanSILBoxType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
// Should not be loaded.
return asImpl().handleReference(
type, getReferenceRecursiveProperties(isSensitive));
}
RetTy handleAggregateByProperties(CanType type, RecursiveProperties props) {
if (props.isAddressOnly()) {
return asImpl().handleAddressOnly(type, props);
}
assert(props.isFixedABI() && "unsupported combination for now");
if (props.isTrivial()) {
return asImpl().handleTrivial(type, props);
}
return asImpl().handleNonTrivialAggregate(type, props);
}
};
class TypeClassifier :
public TypeClassifierBase<TypeClassifier, RecursiveProperties> {
public:
TypeClassifier(TypeConverter &TC,
TypeExpansionContext Expansion)
: TypeClassifierBase(TC, Expansion) {}
RecursiveProperties handle(CanType type, RecursiveProperties properties) {
return properties;
}
RecursiveProperties visitAnyEnumType(CanType type,
AbstractionPattern origType,
EnumDecl *D,
IsTypeExpansionSensitive_t isSensitive) {
// We have to look through optionals here without grabbing the
// type lowering because the way that optionals are reabstracted
// can trip recursion checks if we try to build a lowered type.
if (D->isOptionalDecl()) {
return visit(type.getOptionalObjectType(),
origType.getOptionalObjectType(),
isSensitive);
}
// Consult the type lowering.
auto &lowering = TC.getTypeLowering(origType, type, Expansion);
return handleClassificationFromLowering(type, lowering, isSensitive);
}
RecursiveProperties visitAnyStructType(CanType type,
AbstractionPattern origType,
StructDecl *D,
IsTypeExpansionSensitive_t isSensitive) {
// Consult the type lowering.
auto &lowering = TC.getTypeLowering(origType, type, Expansion);
return handleClassificationFromLowering(type, lowering, isSensitive);
}
private:
RecursiveProperties
handleClassificationFromLowering(CanType type, const TypeLowering &lowering,
IsTypeExpansionSensitive_t isSensitive) {
return handle(type, mergeIsTypeExpansionSensitive(
isSensitive, lowering.getRecursiveProperties()));
}
};
} // end anonymous namespace
static RecursiveProperties classifyType(AbstractionPattern origType,
CanType type,
TypeConverter &tc,
TypeExpansionContext expansion) {
return TypeClassifier(tc, expansion)
.visit(type, origType, IsNotTypeExpansionSensitive);
}
/// True if the type, or the referenced type of an address
/// type, is address-only. For example, it could be a resilient struct or
/// something of unknown size.
bool SILType::isAddressOnly(CanType type,
TypeConverter &tc,
CanGenericSignature sig,
TypeExpansionContext expansion) {
return classifyType(AbstractionPattern(sig, type),
type, tc, expansion).isAddressOnly();
}
namespace {
/// A class for types that can be loaded and stored in SIL.
/// This always include loadable types, but can include address-only types if
/// opaque values are passed by value.
class LoadableTypeLowering : public TypeLowering {
protected:
LoadableTypeLowering(SILType type, RecursiveProperties properties,
IsReferenceCounted_t isRefCounted,
TypeExpansionContext forExpansion)
: TypeLowering(type, properties, isRefCounted, forExpansion) {}
public:
void emitDestroyAddress(SILBuilder &B, SILLocation loc,
SILValue addr) const override {
SILValue value = emitLoad(B, loc, addr, LoadOwnershipQualifier::Take);
emitDestroyValue(B, loc, value);
}
void emitDestroyRValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
emitDestroyValue(B, loc, value);
}
void emitCopyInto(SILBuilder &B, SILLocation loc,
SILValue src, SILValue dest, IsTake_t isTake,
IsInitialization_t isInit) const override {
SILValue value = emitLoadOfCopy(B, loc, src, isTake);
emitStoreOfCopy(B, loc, value, dest, isInit);
}
};
/// A class for trivial, fixed-layout, loadable types.
class TrivialTypeLowering final : public LoadableTypeLowering {
public:
TrivialTypeLowering(SILType type, RecursiveProperties properties,
TypeExpansionContext forExpansion)
: LoadableTypeLowering(type, properties, IsNotReferenceCounted,
forExpansion) {
assert(properties.isFixedABI());
assert(properties.isTrivial());
assert(!properties.isAddressOnly());
}
SILValue emitLoadOfCopy(SILBuilder &B, SILLocation loc, SILValue addr,
IsTake_t isTake) const override {
return emitLoad(B, loc, addr, LoadOwnershipQualifier::Trivial);
}
void emitStoreOfCopy(SILBuilder &B, SILLocation loc,
SILValue value, SILValue addr,
IsInitialization_t isInit) const override {
emitStore(B, loc, value, addr, StoreOwnershipQualifier::Trivial);
}
void emitStore(SILBuilder &B, SILLocation loc, SILValue value,
SILValue addr, StoreOwnershipQualifier qual) const override {
if (B.getFunction().hasOwnership()) {
B.createStore(loc, value, addr, StoreOwnershipQualifier::Trivial);
return;
}
B.createStore(loc, value, addr, StoreOwnershipQualifier::Unqualified);
}
SILValue emitLoad(SILBuilder &B, SILLocation loc, SILValue addr,
LoadOwnershipQualifier qual) const override {
if (B.getFunction().hasOwnership())
return B.createLoad(loc, addr, LoadOwnershipQualifier::Trivial);
return B.createLoad(loc, addr, LoadOwnershipQualifier::Unqualified);
}
SILValue emitLoweredLoad(SILBuilder &B, SILLocation loc, SILValue addr,
LoadOwnershipQualifier qual,
TypeExpansionKind) const override {
if (B.getFunction().hasOwnership())
return B.createLoad(loc, addr, LoadOwnershipQualifier::Trivial);
return B.createLoad(loc, addr, LoadOwnershipQualifier::Unqualified);
}
void emitLoweredStore(SILBuilder &B, SILLocation loc, SILValue value,
SILValue addr, StoreOwnershipQualifier qual,
Lowering::TypeLowering::TypeExpansionKind
expansionKind) const override {
auto storeQual = [&]() -> StoreOwnershipQualifier {
if (B.getFunction().hasOwnership())
return StoreOwnershipQualifier::Trivial;
return StoreOwnershipQualifier::Unqualified;
}();
B.createStore(loc, value, addr, storeQual);
}
void emitDestroyAddress(SILBuilder &B, SILLocation loc,
SILValue addr) const override {
// Trivial
}
void
emitLoweredDestroyValue(SILBuilder &B, SILLocation loc, SILValue value,
TypeExpansionKind loweringStyle) const override {
// Trivial
}
SILValue emitLoweredCopyValue(SILBuilder &B, SILLocation loc,
SILValue value,
TypeExpansionKind style) const override {
// Trivial
return value;
}
SILValue emitCopyValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
// Trivial
return value;
}
void emitDestroyValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
// Trivial
}
};
class NonTrivialLoadableTypeLowering : public LoadableTypeLowering {
public:
NonTrivialLoadableTypeLowering(SILType type,
RecursiveProperties properties,
IsReferenceCounted_t isRefCounted,
TypeExpansionContext forExpansion)
: LoadableTypeLowering(type, properties, isRefCounted, forExpansion) {
assert(!properties.isTrivial());
}
SILValue emitLoadOfCopy(SILBuilder &B, SILLocation loc,
SILValue addr, IsTake_t isTake) const override {
auto qual =
isTake ? LoadOwnershipQualifier::Take : LoadOwnershipQualifier::Copy;
return emitLoad(B, loc, addr, qual);
}
void emitStoreOfCopy(SILBuilder &B, SILLocation loc,
SILValue newValue, SILValue addr,
IsInitialization_t isInit) const override {
auto qual = isInit ? StoreOwnershipQualifier::Init
: StoreOwnershipQualifier::Assign;
emitStore(B, loc, newValue, addr, qual);
}
void emitStore(SILBuilder &B, SILLocation loc, SILValue value,
SILValue addr, StoreOwnershipQualifier qual) const override {
if (B.getFunction().hasOwnership()) {
B.createStore(loc, value, addr, qual);
return;
}
if (qual != StoreOwnershipQualifier::Assign) {
B.createStore(loc, value, addr, StoreOwnershipQualifier::Unqualified);
return;
}
// If the ownership qualifier is [assign], then we need to eliminate the
// old value.
//
// 1. Load old value.
// 2. Store new value.
// 3. Release old value.
SILValue old =
B.createLoad(loc, addr, LoadOwnershipQualifier::Unqualified);
B.createStore(loc, value, addr, StoreOwnershipQualifier::Unqualified);
B.emitDestroyValueOperation(loc, old);
}
SILValue emitLoad(SILBuilder &B, SILLocation loc, SILValue addr,
LoadOwnershipQualifier qual) const override {
if (B.getFunction().hasOwnership())
return B.createLoad(loc, addr, qual);
SILValue loadValue =
B.createLoad(loc, addr, LoadOwnershipQualifier::Unqualified);
// If we do not have a copy, just return the value...
if (qual != LoadOwnershipQualifier::Copy)
return loadValue;
// Otherwise, emit the copy value operation and return our original
// value. This is a small non-ownership optimization to not destabilize
// the optimizer pipeline.
//
// TODO: Once the pass pipeline is fixed, we should evaluate if we can do
// this again.
B.emitCopyValueOperation(loc, loadValue);
return loadValue;
}
SILValue emitLoweredLoad(SILBuilder &B, SILLocation loc, SILValue addr,
LoadOwnershipQualifier qual,
TypeExpansionKind expansionKind) const override {
if (B.getFunction().hasOwnership())
return B.createLoad(loc, addr, qual);
SILValue loadValue =
B.createLoad(loc, addr, LoadOwnershipQualifier::Unqualified);
// If we do not have a copy, just return the value...
if (qual != LoadOwnershipQualifier::Copy)
return loadValue;
// Otherwise, emit the copy value operation.
B.emitLoweredCopyValueOperation(loc, loadValue, expansionKind);
// Otherwise, emit the copy value operation and return our original
// value. This is a small non-ownership optimization to not destabilize
// the optimizer pipeline.
//
// TODO: Once the pass pipeline is fixed, we should evaluate if we can do
// this again.
return loadValue;
}
void emitLoweredStore(SILBuilder &B, SILLocation loc, SILValue value,
SILValue addr, StoreOwnershipQualifier qual,
Lowering::TypeLowering::TypeExpansionKind
expansionKind) const override {
if (B.getFunction().hasOwnership()) {
B.createStore(loc, value, addr, qual);
return;
}
if (qual == StoreOwnershipQualifier::Assign) {
SILValue oldValue = B.emitLoadValueOperation(
loc, addr, LoadOwnershipQualifier::Unqualified);
B.emitLoweredDestroyValueOperation(loc, oldValue, expansionKind);
}
B.createStore(loc, value, addr, StoreOwnershipQualifier::Unqualified);
}
};
/// A CRTP helper class for loadable but non-trivial aggregate types.
template <class Impl, class IndexType>
class LoadableAggTypeLowering : public NonTrivialLoadableTypeLowering {
public:
/// A child of this aggregate type.
class Child {
/// The index of this child, used to project it out.
IndexType Index;
/// The aggregate's type lowering.
const TypeLowering *Lowering;
public:
Child(IndexType index, const TypeLowering &lowering)
: Index(index), Lowering(&lowering) {}
const TypeLowering &getLowering() const { return *Lowering; }
IndexType getIndex() const { return Index; }
bool isTrivial() const { return Lowering->isTrivial(); }
};
private:
const Impl &asImpl() const { return static_cast<const Impl&>(*this); }
Impl &asImpl() { return static_cast<Impl&>(*this); }
// A reference to the lazily-allocated children vector.
mutable ArrayRef<Child> Children = {};
protected:
virtual void lowerChildren(TypeConverter &TC, SmallVectorImpl<Child> &children)
const = 0;
public:
LoadableAggTypeLowering(CanType type, RecursiveProperties properties,
TypeExpansionContext forExpansion)
: NonTrivialLoadableTypeLowering(SILType::getPrimitiveObjectType(type),
properties, IsNotReferenceCounted,
forExpansion) {
}
/// CRTP Default implementation of destructuring an aggregate value.
///
/// Uses getChildren() and emitRValueProject() to create projections for
/// each child. Subclasses should override this to customize on how
/// destructuring is done.
///
/// NOTE: Due to the CRTP, this must always be called as
/// asImpl().destructureAggregate() to ensure that one gets the proper
/// implementation!
void destructureAggregate(
SILBuilder &B, SILLocation loc, SILValue aggValue, bool skipTrivial,
function_ref<void(unsigned, SILValue, const TypeLowering &)> visitor)
const {
for (auto pair : llvm::enumerate(getChildren(B.getModule().Types))) {
auto &child = pair.value();
auto &childLowering = child.getLowering();
// Skip trivial children.
if (skipTrivial && childLowering.isTrivial())
continue;
auto childIndex = child.getIndex();
auto childValue = asImpl().emitRValueProject(B, loc, aggValue,
childIndex, childLowering);
visitor(pair.index(), childValue, childLowering);
}
}
virtual SILValue rebuildAggregate(SILBuilder &B, SILLocation loc,
ArrayRef<SILValue> values) const = 0;
ArrayRef<Child> getChildren(TypeConverter &TC) const {
if (Children.data() == nullptr) {
SmallVector<Child, 4> children;
lowerChildren(TC, children);
auto buf = operator new(sizeof(Child) * children.size(), TC);
memcpy(buf, children.data(), sizeof(Child) * children.size());
Children = {reinterpret_cast<Child*>(buf), children.size()};
}
return Children;
}
template <class T>
void forEachNonTrivialChild(SILBuilder &B, SILLocation loc,
SILValue aggValue,
const T &operation) const {
asImpl().destructureAggregate(B, loc, aggValue, true /*skipTrivial*/,
[&](unsigned, SILValue childValue,
const TypeLowering &childLowering) {
operation(B, loc, childValue,
childLowering);
});
}
using SimpleOperationTy = void (TypeLowering::*)(SILBuilder &B,
SILLocation loc,
SILValue value) const;
void forEachNonTrivialChild(SILBuilder &B, SILLocation loc,
SILValue aggValue,
SimpleOperationTy operation) const {
forEachNonTrivialChild(B, loc, aggValue,
[operation](SILBuilder &B, SILLocation loc,
SILValue childValue,
const TypeLowering &childLowering) {
(childLowering.*operation)(B, loc, childValue);
});
}
SILValue emitCopyValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
if (B.getFunction().hasOwnership())
return B.createCopyValue(loc, value);
B.createRetainValue(loc, value, B.getDefaultAtomicity());
return value;
}
SILValue emitLoweredCopyValue(SILBuilder &B, SILLocation loc,
SILValue aggValue,
TypeExpansionKind style) const override {
if (style == TypeExpansionKind::None) {
return emitCopyValue(B, loc, aggValue);
}
SmallVector<SILValue, 8> loweredChildValues;
asImpl().destructureAggregate(
B, loc, aggValue, false /*skipTrivial*/,
[&](unsigned childIndex, SILValue childValue,
const TypeLowering &childLowering) {
if (!childLowering.isTrivial())
childValue = childLowering.emitLoweredCopyChildValue(
B, loc, childValue, style);
loweredChildValues.push_back(childValue);
});
// Without ownership, return our original value. This is a small
// non-ownership optimization to not destabilize the optimizer pipeline.
//
// TODO: Once the pass pipeline is fixed, we should evaluate if we can do
// this again.
if (!B.hasOwnership())
return aggValue;
return rebuildAggregate(B, loc, loweredChildValues);
}
void emitDestroyValue(SILBuilder &B, SILLocation loc,
SILValue aggValue) const override {
if (B.getFunction().hasOwnership()) {
B.createDestroyValue(loc, aggValue);
return;
}
B.createReleaseValue(loc, aggValue, B.getDefaultAtomicity());
}
void
emitLoweredDestroyValue(SILBuilder &B, SILLocation loc, SILValue aggValue,
TypeExpansionKind loweringStyle) const override {
SimpleOperationTy Fn;
switch(loweringStyle) {
case TypeExpansionKind::None:
return emitDestroyValue(B, loc, aggValue);
case TypeExpansionKind::DirectChildren:
Fn = &TypeLowering::emitDestroyValue;
break;
case TypeExpansionKind::MostDerivedDescendents:
Fn = &TypeLowering::emitLoweredDestroyValueMostDerivedDescendents;
break;
}
forEachNonTrivialChild(B, loc, aggValue, Fn);
}
};
/// A lowering for loadable but non-trivial tuple types.
class LoadableTupleTypeLowering final
: public LoadableAggTypeLowering<LoadableTupleTypeLowering, unsigned> {
using Super = LoadableAggTypeLowering<LoadableTupleTypeLowering, unsigned>;
public:
LoadableTupleTypeLowering(CanType type, RecursiveProperties properties,
TypeExpansionContext forExpansion)
: LoadableAggTypeLowering(type, properties, forExpansion) {}
SILValue emitRValueProject(SILBuilder &B, SILLocation loc,
SILValue tupleValue, unsigned index,
const TypeLowering &eltLowering) const {
assert(!B.hasOwnership() &&
"Shouldn't call this when ownership is enabled?! Destructure "
"non-trivial tuples instead");
return B.createTupleExtract(loc, tupleValue, index,
eltLowering.getLoweredType());
}
void destructureAggregate(
SILBuilder &B, SILLocation loc, SILValue aggValue, bool skipTrivial,
function_ref<void(unsigned childIndex, SILValue childValue,
const TypeLowering &childLowering)>
visitor) const {
// Without ownership, use our parent.
if (!B.hasOwnership())
return Super::destructureAggregate(B, loc, aggValue, skipTrivial,
visitor);
// Otherwise, emit a destructure tuple and do the loop.
auto *dti = B.createDestructureTuple(loc, aggValue);
for (auto pair : llvm::enumerate(dti->getResults())) {
SILValue childValue = pair.value();
auto &childLowering =
B.getFunction().getTypeLowering(childValue->getType());
if (skipTrivial && childLowering.isTrivial())
continue;
visitor(pair.index(), childValue, childLowering);
}
}
SILValue rebuildAggregate(SILBuilder &B, SILLocation loc,
ArrayRef<SILValue> values) const override {
return B.createTuple(loc, getLoweredType(), values);
}
private:
void lowerChildren(TypeConverter &TC, SmallVectorImpl<Child> &children)
const override {
// The children are just the elements of the lowered tuple.
auto silTy = getLoweredType();
auto tupleTy = silTy.castTo<TupleType>();
children.reserve(tupleTy->getNumElements());
unsigned index = 0;
for (auto elt : tupleTy.getElementTypes()) {
auto silElt = SILType::getPrimitiveType(elt, silTy.getCategory());
auto &eltTL = TC.getTypeLowering(silElt, getExpansionContext());
children.push_back(Child{index, eltTL});
++index;
}
}
};
/// A lowering for loadable but non-trivial struct types.
class LoadableStructTypeLowering final
: public LoadableAggTypeLowering<LoadableStructTypeLowering, VarDecl *> {
using Super =
LoadableAggTypeLowering<LoadableStructTypeLowering, VarDecl *>;
public:
LoadableStructTypeLowering(CanType type, RecursiveProperties properties,
TypeExpansionContext forExpansion)
: LoadableAggTypeLowering(type, properties, forExpansion) {}
SILValue emitRValueProject(SILBuilder &B, SILLocation loc,
SILValue structValue, VarDecl *field,
const TypeLowering &fieldLowering) const {
return B.createStructExtract(loc, structValue, field,
fieldLowering.getLoweredType());
}
void destructureAggregate(
SILBuilder &B, SILLocation loc, SILValue aggValue, bool skipTrivial,
function_ref<void(unsigned childIndex, SILValue childValue,
const TypeLowering &childLowering)>
visitor) const {
if (!B.hasOwnership())
return Super::destructureAggregate(B, loc, aggValue, skipTrivial,
visitor);
auto *dsi = B.createDestructureStruct(loc, aggValue);
for (auto pair : llvm::enumerate(dsi->getResults())) {
SILValue childValue = pair.value();
auto &childLowering =
B.getFunction().getTypeLowering(childValue->getType());
if (skipTrivial && childLowering.isTrivial())
continue;
visitor(pair.index(), childValue, childLowering);
}
}
SILValue rebuildAggregate(SILBuilder &B, SILLocation loc,
ArrayRef<SILValue> values) const override {
return B.createStruct(loc, getLoweredType(), values);
}
private:
void lowerChildren(TypeConverter &TC, SmallVectorImpl<Child> &children)
const override {
auto silTy = getLoweredType();
auto structDecl = silTy.getStructOrBoundGenericStruct();
assert(structDecl);
for (auto prop : structDecl->getStoredProperties()) {
SILType propTy = silTy.getFieldType(prop, TC, getExpansionContext());
auto &propTL = TC.getTypeLowering(propTy, getExpansionContext());
children.push_back(Child{prop, propTL});
}
}
};
/// A lowering for loadable but non-trivial enum types.
class LoadableEnumTypeLowering final : public NonTrivialLoadableTypeLowering {
public:
LoadableEnumTypeLowering(CanType type, RecursiveProperties properties,
TypeExpansionContext forExpansion)
: NonTrivialLoadableTypeLowering(SILType::getPrimitiveObjectType(type),
properties,
IsNotReferenceCounted,
forExpansion) {}
SILValue emitCopyValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
if (B.getFunction().hasOwnership())
return B.createCopyValue(loc, value);
B.createRetainValue(loc, value, B.getDefaultAtomicity());
return value;
}
SILValue emitLoweredCopyValue(SILBuilder &B, SILLocation loc,
SILValue value,
TypeExpansionKind style) const override {
if (B.getFunction().hasOwnership())
return B.createCopyValue(loc, value);
B.createRetainValue(loc, value, B.getDefaultAtomicity());
return value;
}
void emitDestroyValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
if (B.getFunction().hasOwnership()) {
B.createDestroyValue(loc, value);
return;
}
B.createReleaseValue(loc, value, B.getDefaultAtomicity());
}
void emitLoweredDestroyValue(SILBuilder &B, SILLocation loc, SILValue value,
TypeExpansionKind style) const override {
// Enums, we never want to expand.
return emitDestroyValue(B, loc, value);
}
};
/// A type lowering for `@differentiable` function types.
class NormalDifferentiableSILFunctionTypeLowering final
: public LoadableAggTypeLowering<
NormalDifferentiableSILFunctionTypeLowering,
NormalDifferentiableFunctionTypeComponent> {
public:
using LoadableAggTypeLowering::LoadableAggTypeLowering;
SILValue emitRValueProject(
SILBuilder &B, SILLocation loc, SILValue tupleValue,
NormalDifferentiableFunctionTypeComponent extractee,
const TypeLowering &eltLowering) const {
return B.createDifferentiableFunctionExtract(
loc, extractee, tupleValue);
}
SILValue rebuildAggregate(SILBuilder &B, SILLocation loc,
ArrayRef<SILValue> values) const override {
assert(values.size() == 3);
auto fnTy = getLoweredType().castTo<SILFunctionType>();
auto *parameterIndices = fnTy->getDifferentiabilityParameterIndices();
auto *resultIndices = fnTy->getDifferentiabilityResultIndices();
return B.createDifferentiableFunction(
loc, parameterIndices, resultIndices, values[0],
std::make_pair(values[1], values[2]));
}
void lowerChildren(TypeConverter &TC,
SmallVectorImpl<Child> &children) const override {
auto fnTy = getLoweredType().castTo<SILFunctionType>();
auto numDerivativeFns = 2;
children.reserve(numDerivativeFns + 1);
auto origFnTy = fnTy->getWithoutDifferentiability();
auto *paramIndices = fnTy->getDifferentiabilityParameterIndices();
auto *resultIndices = fnTy->getDifferentiabilityResultIndices();
children.push_back(Child{
NormalDifferentiableFunctionTypeComponent::Original,
TC.getTypeLowering(origFnTy, getExpansionContext())
});
for (AutoDiffDerivativeFunctionKind kind :
{AutoDiffDerivativeFunctionKind::JVP,
AutoDiffDerivativeFunctionKind::VJP}) {
auto derivativeFnTy = origFnTy->getAutoDiffDerivativeFunctionType(
paramIndices, resultIndices, kind, TC,
LookUpConformanceInModule(&TC.M));
auto silTy = SILType::getPrimitiveObjectType(derivativeFnTy);
NormalDifferentiableFunctionTypeComponent extractee(kind);
// Assert that we have the right extractee. A terrible bug in the past
// was caused by implicit conversions from `unsigned` to
// `NormalDifferentiableFunctionTypeComponent` which resulted into a
// wrong extractee.
assert(extractee.getAsDerivativeFunctionKind() == kind);
children.push_back(Child{
extractee, TC.getTypeLowering(silTy, getExpansionContext())});
}
assert(children.size() == 3);
}
};
/// A type lowering for `@differentiable(linear)` function types.
class LinearDifferentiableSILFunctionTypeLowering final
: public LoadableAggTypeLowering<
LinearDifferentiableSILFunctionTypeLowering,
LinearDifferentiableFunctionTypeComponent> {
public:
using LoadableAggTypeLowering::LoadableAggTypeLowering;
SILValue emitRValueProject(
SILBuilder &B, SILLocation loc, SILValue tupleValue,
LinearDifferentiableFunctionTypeComponent component,
const TypeLowering &eltLowering) const {
return B.createLinearFunctionExtract(loc, component, tupleValue);
}
SILValue rebuildAggregate(SILBuilder &B, SILLocation loc,
ArrayRef<SILValue> values) const override {
assert(values.size() == 2);
auto fnTy = getLoweredType().castTo<SILFunctionType>();
auto paramIndices = fnTy->getDifferentiabilityParameterIndices();
return B.createLinearFunction(loc, paramIndices, values[0], values[1]);
}
void lowerChildren(TypeConverter &TC,
SmallVectorImpl<Child> &children) const override {
auto fnTy = getLoweredType().castTo<SILFunctionType>();
children.reserve(2);
auto origFnTy = fnTy->getWithoutDifferentiability();
auto paramIndices = fnTy->getDifferentiabilityParameterIndices();
children.push_back(Child{
LinearDifferentiableFunctionTypeComponent::Original,
TC.getTypeLowering(origFnTy, getExpansionContext())
});
auto transposeFnTy = origFnTy->getAutoDiffTransposeFunctionType(
paramIndices, TC, LookUpConformanceInModule(&TC.M));
auto transposeSILFnTy = SILType::getPrimitiveObjectType(transposeFnTy);
children.push_back(Child{
LinearDifferentiableFunctionTypeComponent::Transpose,
TC.getTypeLowering(transposeSILFnTy, getExpansionContext())
});
assert(children.size() == 2);
}
};
class LeafLoadableTypeLowering : public NonTrivialLoadableTypeLowering {
public:
LeafLoadableTypeLowering(SILType type, RecursiveProperties properties,
IsReferenceCounted_t isRefCounted,
TypeExpansionContext forExpansion)
: NonTrivialLoadableTypeLowering(type, properties, isRefCounted,
forExpansion) {}
SILValue emitLoweredCopyValue(SILBuilder &B, SILLocation loc,
SILValue value,
TypeExpansionKind style) const override {
return emitCopyValue(B, loc, value);
}
void emitLoweredDestroyValue(SILBuilder &B, SILLocation loc, SILValue value,
TypeExpansionKind style) const override {
emitDestroyValue(B, loc, value);
}
};
/// A class for reference types, which are all non-trivial but still
/// loadable.
class ReferenceTypeLowering : public LeafLoadableTypeLowering {
public:
ReferenceTypeLowering(SILType type, RecursiveProperties properties,
TypeExpansionContext forExpansion)
: LeafLoadableTypeLowering(type, properties, IsReferenceCounted,
forExpansion) {}
SILValue emitCopyValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
if (isa<FunctionRefInst>(value) || isa<DynamicFunctionRefInst>(value) ||
isa<PreviousDynamicFunctionRefInst>(value))
return value;
if (B.getFunction().hasOwnership())
return B.createCopyValue(loc, value);
B.createStrongRetain(loc, value, B.getDefaultAtomicity());
return value;
}
void emitDestroyValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
if (B.getFunction().hasOwnership()) {
B.createDestroyValue(loc, value);
return;
}
B.createStrongRelease(loc, value, B.getDefaultAtomicity());
}
};
/// A type lowering for loadable @unowned types.
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
class Loadable##Name##TypeLowering final : public LeafLoadableTypeLowering { \
public: \
Loadable##Name##TypeLowering(SILType type, \
TypeExpansionContext forExpansion, \
RecursiveProperties props) \
: LeafLoadableTypeLowering(type, props, \
IsReferenceCounted, \
forExpansion) {} \
SILValue emitCopyValue(SILBuilder &B, SILLocation loc, \
SILValue value) const override { \
if (B.getFunction().hasOwnership()) \
return B.createCopyValue(loc, value); \
B.create##Name##Retain(loc, value, B.getDefaultAtomicity()); \
return value; \
} \
void emitDestroyValue(SILBuilder &B, SILLocation loc, \
SILValue value) const override { \
if (B.getFunction().hasOwnership()) { \
B.createDestroyValue(loc, value); \
return; \
} \
B.create##Name##Release(loc, value, B.getDefaultAtomicity()); \
} \
};
#include "swift/AST/ReferenceStorage.def"
/// A class for non-trivial, address-only types.
class AddressOnlyTypeLowering : public TypeLowering {
public:
AddressOnlyTypeLowering(SILType type, RecursiveProperties properties,
TypeExpansionContext forExpansion)
: TypeLowering(type, properties, IsNotReferenceCounted,
forExpansion) {
assert(properties.isAddressOnly());
}
void emitCopyInto(SILBuilder &B, SILLocation loc,
SILValue src, SILValue dest, IsTake_t isTake,
IsInitialization_t isInit) const override {
B.createCopyAddr(loc, src, dest, isTake, isInit);
}
SILValue emitLoadOfCopy(SILBuilder &B, SILLocation loc,
SILValue addr, IsTake_t isTake) const override {
llvm_unreachable("calling emitLoadOfCopy on non-loadable type");
}
void emitStoreOfCopy(SILBuilder &B, SILLocation loc,
SILValue newValue, SILValue addr,
IsInitialization_t isInit) const override {
llvm_unreachable("calling emitStoreOfCopy on non-loadable type");
}
void emitStore(SILBuilder &B, SILLocation loc, SILValue value,
SILValue addr, StoreOwnershipQualifier qual) const override {
llvm_unreachable("calling emitStore on non-loadable type");
}
SILValue emitLoad(SILBuilder &B, SILLocation loc, SILValue addr,
LoadOwnershipQualifier qual) const override {
llvm_unreachable("calling emitLoad on non-loadable type");
}
SILValue emitLoweredLoad(SILBuilder &B, SILLocation loc, SILValue addr,
LoadOwnershipQualifier qual,
Lowering::TypeLowering::TypeExpansionKind
expansionKind) const override {
llvm_unreachable("calling emitLoweredLoad on non-loadable type?!");
}
void emitLoweredStore(SILBuilder &B, SILLocation loc, SILValue value,
SILValue addr, StoreOwnershipQualifier qual,
Lowering::TypeLowering::TypeExpansionKind
expansionKind) const override {
llvm_unreachable("calling emitLoweredStore on non-loadable type?!");
}
void emitDestroyAddress(SILBuilder &B, SILLocation loc,
SILValue addr) const override {
if (!isTrivial())
B.createDestroyAddr(loc, addr);
}
void emitDestroyRValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
if (!isTrivial())
B.createDestroyAddr(loc, value);
}
SILValue emitCopyValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
llvm_unreachable("type is not loadable!");
}
SILValue emitLoweredCopyValue(SILBuilder &B, SILLocation loc,
SILValue value,
TypeExpansionKind style) const override {
llvm_unreachable("type is not loadable!");
}
void emitDestroyValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
llvm_unreachable("type is not loadable!");
}
void emitLoweredDestroyValue(SILBuilder &B, SILLocation loc, SILValue value,
TypeExpansionKind style) const override {
llvm_unreachable("type is not loadable!");
}
};
/// A class for Builtin.UnsafeValueBuffer. The only purpose here is
/// to catch obviously broken attempts to copy or destroy the buffer.
class UnsafeValueBufferTypeLowering : public AddressOnlyTypeLowering {
public:
UnsafeValueBufferTypeLowering(SILType type,
TypeExpansionContext forExpansion,
IsTypeExpansionSensitive_t isSensitive)
: AddressOnlyTypeLowering(type,
{IsNotTrivial, IsFixedABI,
IsAddressOnly, IsNotResilient, isSensitive},
forExpansion) {}
void emitCopyInto(SILBuilder &B, SILLocation loc,
SILValue src, SILValue dest, IsTake_t isTake,
IsInitialization_t isInit) const override {
llvm_unreachable("cannot copy an UnsafeValueBuffer!");
}
void emitDestroyAddress(SILBuilder &B, SILLocation loc,
SILValue addr) const override {
llvm_unreachable("cannot destroy an UnsafeValueBuffer!");
}
void emitDestroyRValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
llvm_unreachable("cannot destroy an UnsafeValueBuffer!");
}
};
/// Lower address only types as opaque values.
///
/// Opaque values behave like loadable leaf types in SIL.
///
/// FIXME: When you remove an unreachable, just delete the method.
class OpaqueValueTypeLowering : public LeafLoadableTypeLowering {
public:
OpaqueValueTypeLowering(SILType type, RecursiveProperties properties,
TypeExpansionContext forExpansion)
: LeafLoadableTypeLowering(type, properties, IsNotReferenceCounted,
forExpansion) {}
void emitCopyInto(SILBuilder &B, SILLocation loc,
SILValue src, SILValue dest, IsTake_t isTake,
IsInitialization_t isInit) const override {
llvm_unreachable("copy into");
}
// --- Same as LeafLoadableTypeLowering.
SILValue emitLoweredCopyValue(SILBuilder &B, SILLocation loc,
SILValue value,
TypeExpansionKind style) const override {
llvm_unreachable("lowered copy");
}
void emitLoweredDestroyValue(SILBuilder &B, SILLocation loc, SILValue value,
TypeExpansionKind style) const override {
llvm_unreachable("destroy value");
}
SILValue emitCopyValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
return B.createCopyValue(loc, value);
}
void emitDestroyValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
B.createDestroyValue(loc, value);
}
};
/// Build the appropriate TypeLowering subclass for the given type,
/// which is assumed to already have been lowered.
class LowerType
: public TypeClassifierBase<LowerType, TypeLowering *>
{
public:
LowerType(TypeConverter &TC, TypeExpansionContext Expansion)
: TypeClassifierBase(TC, Expansion) {}
TypeLowering *handleTrivial(CanType type) {
return handleTrivial(type, RecursiveProperties::forTrivial());
}
TypeLowering *handleTrivial(CanType type,
RecursiveProperties properties) {
auto silType = SILType::getPrimitiveObjectType(type);
return new (TC) TrivialTypeLowering(silType, properties, Expansion);
}
TypeLowering *handleReference(CanType type,
RecursiveProperties properties) {
auto silType = SILType::getPrimitiveObjectType(type);
return new (TC) ReferenceTypeLowering(silType, properties, Expansion);
}
TypeLowering *handleReference(CanType type) {
auto silType = SILType::getPrimitiveObjectType(type);
return new (TC) ReferenceTypeLowering(
silType, RecursiveProperties::forReference(), Expansion);
}
TypeLowering *handleAddressOnly(CanType type,
RecursiveProperties properties) {
if (!TC.Context.LangOpts.EnableSILOpaqueValues) {
auto silType = SILType::getPrimitiveAddressType(type);
return new (TC) AddressOnlyTypeLowering(silType, properties,
Expansion);
}
auto silType = SILType::getPrimitiveObjectType(type);
return new (TC) OpaqueValueTypeLowering(silType, properties, Expansion);
}
#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
TypeLowering * \
visit##Name##StorageType(Can##Name##StorageType type, \
AbstractionPattern origType, \
IsTypeExpansionSensitive_t isSensitive) { \
return new (TC) Loadable##Name##TypeLowering( \
SILType::getPrimitiveObjectType(type), \
Expansion, \
getReferenceRecursiveProperties(isSensitive)); \
}
#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
TypeLowering * \
visitLoadable##Name##StorageType(Can##Name##StorageType type, \
AbstractionPattern origType, \
IsTypeExpansionSensitive_t isSensitive) { \
return new (TC) Loadable##Name##TypeLowering( \
SILType::getPrimitiveObjectType(type), \
Expansion, \
getReferenceRecursiveProperties(isSensitive)); \
}
#include "swift/AST/ReferenceStorage.def"
TypeLowering *
visitBuiltinUnsafeValueBufferType(CanBuiltinUnsafeValueBufferType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
auto silType = SILType::getPrimitiveAddressType(type);
return new (TC)
UnsafeValueBufferTypeLowering(silType, Expansion, isSensitive);
}
TypeLowering *visitTupleType(CanTupleType tupleType,
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
RecursiveProperties properties;
for (unsigned i = 0, e = tupleType->getNumElements(); i < e; ++i) {
auto eltType = tupleType.getElementType(i);
auto origEltType = origType.getTupleElementType(i);
auto &lowering = TC.getTypeLowering(origEltType, eltType, Expansion);
properties.addSubobject(lowering.getRecursiveProperties());
}
properties = mergeIsTypeExpansionSensitive(isSensitive, properties);
return handleAggregateByProperties<LoadableTupleTypeLowering>(tupleType,
properties);
}
bool handleResilience(CanType type, NominalTypeDecl *D,
RecursiveProperties &properties) {
if (D->isResilient()) {
// If the type is resilient and defined in our module, make a note of
// that, since our lowering now depends on the resilience expansion.
bool sameModule = (D->getModuleContext() == &TC.M);
if (sameModule)
properties.addSubobject(RecursiveProperties::forResilient());
// If the type is in a different module, or if we're using a minimal
// expansion, the type is address only and completely opaque to us.
//
// Note: if the type is in a different module, the lowering does
// not depend on the resilience expansion, so we do not need to set
// the isResilent() flag above.
if (!sameModule || Expansion.getResilienceExpansion() ==
ResilienceExpansion::Minimal) {
properties.addSubobject(RecursiveProperties::forOpaque());
return true;
}
}
return false;
}
TypeLowering *visitAnyStructType(CanType structType,
AbstractionPattern origType,
StructDecl *D,
IsTypeExpansionSensitive_t isSensitive) {
RecursiveProperties properties;
properties = mergeIsTypeExpansionSensitive(isSensitive, properties);
if (handleResilience(structType, D, properties))
return handleAddressOnly(structType, properties);
if (D->isCxxNonTrivial()) {
properties.setAddressOnly();
properties.setNonTrivial();
}
auto subMap = structType->getContextSubstitutionMap(&TC.M, D);
// Classify the type according to its stored properties.
for (auto field : D->getStoredProperties()) {
auto substFieldType =
field->getInterfaceType().subst(subMap)
->getCanonicalType();
// We are determining the recursive properties of the struct here,
// not the lowered types of the fields, so instead of lowering the
// field type against the declaration's interface type as we normally
// would, we use the substituted field type in order to accurately
// preserve the properties of the aggregate.
auto origFieldType = origType.unsafeGetSubstFieldType(field);
properties.addSubobject(classifyType(origFieldType, substFieldType,
TC, Expansion));
}
return handleAggregateByProperties<LoadableStructTypeLowering>(structType,
properties);
}
TypeLowering *visitAnyEnumType(CanType enumType,
AbstractionPattern origType,
EnumDecl *D,
IsTypeExpansionSensitive_t isSensitive) {
RecursiveProperties properties;
properties = mergeIsTypeExpansionSensitive(isSensitive, properties);
if (handleResilience(enumType, D, properties))
return handleAddressOnly(enumType, properties);
// If the whole enum is indirect, we lower it as if all payload
// cases were indirect. This means a fixed-layout indirect enum
// is always loadable and nontrivial. A resilient indirect enum
// is still address only, because we don't know how many bits
// are used for the discriminator, and new non-indirect cases
// may be added resiliently later.
if (D->isIndirect()) {
properties.setNonTrivial();
return new (TC) LoadableEnumTypeLowering(enumType, properties,
Expansion);
}
auto subMap = enumType->getContextSubstitutionMap(&TC.M, D);
// Accumulate the properties of all direct payloads.
for (auto elt : D->getAllElements()) {
// No-payload elements do not affect any recursive properties.
if (!elt->hasAssociatedValues())
continue;
// Indirect elements only make the type nontrivial.
if (elt->isIndirect()) {
properties.setNonTrivial();
continue;
}
auto substEltType =
elt->getArgumentInterfaceType().subst(subMap)
->getCanonicalType();
auto origEltType = origType.unsafeGetSubstFieldType(elt,
elt->getArgumentInterfaceType()
->getCanonicalType(D->getGenericSignature()));
properties.addSubobject(classifyType(origEltType, substEltType,
TC, Expansion));
}
return handleAggregateByProperties<LoadableEnumTypeLowering>(enumType,
properties);
}
TypeLowering *
visitNormalDifferentiableSILFunctionType(CanSILFunctionType type,
RecursiveProperties props) {
return handleAggregateByProperties
<NormalDifferentiableSILFunctionTypeLowering>(type, props);
}
TypeLowering *
visitLinearDifferentiableSILFunctionType(CanSILFunctionType type,
RecursiveProperties props) {
return handleAggregateByProperties
<LinearDifferentiableSILFunctionTypeLowering>(type, props);
}
template <class LoadableLoweringClass>
TypeLowering *handleAggregateByProperties(CanType type,
RecursiveProperties props) {
if (props.isAddressOnly()) {
return handleAddressOnly(type, props);
}
assert(props.isFixedABI());
if (props.isTrivial()) {
return handleTrivial(type, props);
}
return new (TC) LoadableLoweringClass(type, props, Expansion);
}
};
} // end anonymous namespace
TypeConverter::TypeConverter(ModuleDecl &m)
: M(m), Context(m.getASTContext()) {
}
TypeConverter::~TypeConverter() {
// The bump pointer allocator destructor will deallocate but not destroy all
// our independent TypeLowerings.
for (auto &ti : LoweredTypes) {
// Destroy only the unique entries.
CanType srcType = ti.first.OrigType;
if (!srcType) continue;
CanType mappedType = ti.second->getLoweredType().getASTType();
if (srcType == mappedType)
ti.second->~TypeLowering();
}
}
void *TypeLowering::operator new(size_t size, TypeConverter &tc) {
return tc.TypeLoweringBPA.Allocate(size, alignof(TypeLowering&));
}
const TypeLowering *TypeConverter::find(const TypeKey &k) {
if (!k.isCacheable()) return nullptr;
auto ck = k.getCachingKey();
auto found = LoweredTypes.find(ck);
if (found == LoweredTypes.end())
return nullptr;
assert((found->second || k.expansionContext.isMinimal()) &&
"type recursion not caught in Sema");
return found->second;
}
#ifndef NDEBUG
void TypeConverter::removeNullEntry(const TypeKey &k) {
if (!k.isCacheable())
return;
auto ck = k.getCachingKey();
auto found = LoweredTypes.find(ck);
if (found == LoweredTypes.end() || found->second != nullptr)
return;
LoweredTypes.erase(ck);
}
#endif
void TypeConverter::insert(const TypeKey &k, const TypeLowering *tl) {
if (!k.isCacheable()) return;
LoweredTypes[k.getCachingKey()] = tl;
}
/// Lower each of the elements of the substituted type according to
/// the abstraction pattern of the given original type.
static CanTupleType computeLoweredTupleType(TypeConverter &tc,
TypeExpansionContext context,
AbstractionPattern origType,
CanTupleType substType) {
assert(origType.matchesTuple(substType));
// Does the lowered tuple type differ from the substituted type in
// any interesting way?
bool changed = false;
SmallVector<TupleTypeElt, 4> loweredElts;
loweredElts.reserve(substType->getNumElements());
for (auto i : indices(substType->getElementTypes())) {
auto origEltType = origType.getTupleElementType(i);
auto substEltType = substType.getElementType(i);
auto &substElt = substType->getElement(i);
// Make sure we don't have something non-materializable.
auto Flags = substElt.getParameterFlags();
assert(Flags.getValueOwnership() == ValueOwnership::Default);
assert(!Flags.isVariadic());
CanType loweredSubstEltType =
tc.getLoweredRValueType(context, origEltType, substEltType);
changed = (changed || substEltType != loweredSubstEltType ||
!Flags.isNone());
// Note: we drop @escaping and @autoclosure which can still appear on
// materializable tuple types.
//
// FIXME: Replace this with an assertion that the original tuple element
// did not have any flags.
loweredElts.emplace_back(loweredSubstEltType,
substElt.getName(),
ParameterTypeFlags());
}
if (!changed) return substType;
// The cast should succeed, because if we end up with a one-element
// tuple type here, it must have a label.
return cast<TupleType>(CanType(TupleType::get(loweredElts, tc.Context)));
}
static CanType computeLoweredOptionalType(TypeConverter &tc,
TypeExpansionContext context,
AbstractionPattern origType,
CanType substType,
CanType substObjectType) {
assert(substType.getOptionalObjectType() == substObjectType);
CanType loweredObjectType = tc.getLoweredRValueType(
context, origType.getOptionalObjectType(), substObjectType);
// If the object type didn't change, we don't have to rebuild anything.
if (loweredObjectType == substObjectType) {
return substType;
}
auto optDecl = tc.Context.getOptionalDecl();
return CanType(BoundGenericEnumType::get(optDecl, Type(), loweredObjectType));
}
static CanType
computeLoweredReferenceStorageType(TypeConverter &tc,
TypeExpansionContext context,
AbstractionPattern origType,
CanReferenceStorageType substType) {
CanType loweredReferentType = tc.getLoweredRValueType(
context, origType.getReferenceStorageReferentType(),
substType.getReferentType());
if (loweredReferentType == substType.getReferentType())
return substType;
return CanReferenceStorageType::get(loweredReferentType,
substType->getOwnership());
}
CanSILFunctionType
TypeConverter::getSILFunctionType(TypeExpansionContext context,
AbstractionPattern origType,
CanFunctionType substType) {
return cast<SILFunctionType>(
getLoweredRValueType(context, origType, substType));
}
const TypeLowering &
TypeConverter::getTypeLowering(AbstractionPattern origType,
Type origSubstType,
TypeExpansionContext forExpansion) {
CanType substType = origSubstType->getCanonicalType();
bool origHasOpaqueArchetype = substType->hasOpaqueArchetype();
// A type is type expansion sensitive if its lowering could depend on the type
// expansion context:
// - If the type has an opaque archetype
// Because depending on the type expansion context we might get a different
// SIL type (Foo<some P> vs Foo<Int>).
// - or if during type lowering we discover an opaque archetype that
// influences type lowering by type expansion context
// E.g a struct containing a field that is a opaque archetype will be
// loadable or not depending on the type expansion context. In a more
// permissive type expansion context we will look through the opaque
// archetype and could discover a loadable type making the whole aggregate
// loadable.
auto isTypeExpansionSensitive = origHasOpaqueArchetype
? IsTypeExpansionSensitive
: IsNotTypeExpansionSensitive;
auto key = getTypeKey(origType, substType, forExpansion);
assert(!substType->is<InOutType>());
auto *candidateLowering = find(key.getKeyForMinimalExpansion());
auto *lowering = getTypeLoweringForExpansion(
key, forExpansion, candidateLowering, IsNotTypeExpansionSensitive);
if (lowering != nullptr)
return *lowering;
#ifndef NDEBUG
// Catch reentrancy bugs.
if (candidateLowering == nullptr)
insert(key.getKeyForMinimalExpansion(), nullptr);
#endif
// Lower the type.
auto loweredSubstType =
computeLoweredRValueType(forExpansion, origType, substType);
// If that didn't change the type and the key is cachable, there's no
// point in re-checking the table, so just construct a type lowering
// and cache it.
if (loweredSubstType == substType && key.isCacheable()) {
lowering =
LowerType(*this, forExpansion)
.visit(key.SubstType, key.OrigType, isTypeExpansionSensitive);
// Otherwise, check the table at a key that would be used by the
// SILType-based lookup path for the type we just lowered to, then cache
// that same result at this key if possible.
} else {
lowering = &getTypeLoweringForLoweredType(
origType, loweredSubstType, forExpansion, isTypeExpansionSensitive);
}
if (!lowering->isResilient() && !lowering->isTypeExpansionSensitive()) {
insert(key.getKeyForMinimalExpansion(), lowering);
} else {
insert(key, lowering);
#ifndef NDEBUG
removeNullEntry(key.getKeyForMinimalExpansion());
#endif
}
return *lowering;
}
CanType
TypeConverter::computeLoweredRValueType(TypeExpansionContext forExpansion,
AbstractionPattern origType,
CanType substType) {
class LoweredRValueTypeVisitor
: public CanTypeVisitor<LoweredRValueTypeVisitor, CanType> {
TypeConverter &TC;
TypeExpansionContext forExpansion;
AbstractionPattern origType;
public:
LoweredRValueTypeVisitor(TypeConverter &TC,
TypeExpansionContext forExpansion,
AbstractionPattern origType)
: TC(TC), forExpansion(forExpansion), origType(origType) {}
// AST function types are turned into SIL function types:
// - the type is uncurried as desired
// - types are turned into their unbridged equivalents, depending
// on the abstract CC
// - ownership conventions are deduced
// - a minimal substituted generic signature is extracted to represent
// possible ABI-compatible substitutions
CanType visitAnyFunctionType(CanAnyFunctionType substFnType) {
// If the formal type uses a C convention, it is not formally
// abstractable, and it may be subject to implicit bridging.
auto extInfo = substFnType->getExtInfo();
auto rep = extInfo.getRepresentation();
SILFunctionTypeRepresentation silRep = convertRepresentation(rep);
if (getSILFunctionLanguage(silRep) == SILFunctionLanguage::C) {
// The importer only applies fully-reversible bridging to the
// component types of C function pointers.
auto bridging = Bridgeability::Full;
if (silRep == SILFunctionTypeRepresentation::CFunctionPointer)
bridging = Bridgeability::None;
// Bridge the parameters and result of the function type.
auto bridgedFnType =
TC.getBridgedFunctionType(origType, substFnType, bridging, silRep);
substFnType = bridgedFnType;
// Also rewrite the type of the abstraction pattern.
auto signature = origType.getGenericSignatureOrNull();
if (origType.isTypeParameter()) {
origType = AbstractionPattern(signature, bridgedFnType);
} else {
origType.rewriteType(signature, bridgedFnType);
}
}
AnyFunctionType::ExtInfo baseExtInfo;
if (auto origFnType = origType.getAs<AnyFunctionType>()) {
baseExtInfo = origFnType->getExtInfo();
} else {
baseExtInfo = substFnType->getExtInfo();
}
const clang::Type *clangType = baseExtInfo.getClangTypeInfo().getType();
if (shouldStoreClangType(rep) && !clangType) {
clangType = TC.Context.getClangFunctionType(
substFnType->getParams(), substFnType->getResult(), rep);
}
auto silExtInfo =
SILExtInfoBuilder(
baseExtInfo.intoBuilder().withClangFunctionType(clangType), false)
.build();
return ::getNativeSILFunctionType(TC, forExpansion, origType, substFnType,
silExtInfo);
}
// Ignore dynamic self types.
CanType visitDynamicSelfType(CanDynamicSelfType selfType) {
return TC.getLoweredRValueType(forExpansion, origType,
selfType.getSelfType());
}
// Static metatypes are unitary and can optimized to a "thin" empty
// representation if the type also appears as a static metatype in the
// original abstraction pattern.
CanType visitMetatypeType(CanMetatypeType substMeta) {
// If the metatype has already been lowered, it will already carry its
// representation.
if (substMeta->hasRepresentation()) {
assert(substMeta->isLegalSILType());
return substOpaqueTypesWithUnderlyingTypes(substMeta, forExpansion);
}
MetatypeRepresentation repr;
auto origMeta = origType.getAs<MetatypeType>();
if (!origMeta) {
// If the metatype matches a dependent type, it must be thick.
assert(origType.isTypeParameterOrOpaqueArchetype());
repr = MetatypeRepresentation::Thick;
} else {
// Otherwise, we're thin if the metatype is thinnable both
// substituted and in the abstraction pattern.
if (hasSingletonMetatype(substMeta.getInstanceType()) &&
hasSingletonMetatype(origMeta.getInstanceType()))
repr = MetatypeRepresentation::Thin;
else
repr = MetatypeRepresentation::Thick;
}
CanType instanceType = substOpaqueTypesWithUnderlyingTypes(
substMeta.getInstanceType(), forExpansion);
// Regardless of thinness, metatypes are always trivial.
return CanMetatypeType::get(instanceType, repr);
}
// Give existential metatypes @thick representation by default.
CanType
visitExistentialMetatypeType(CanExistentialMetatypeType existMetatype) {
if (existMetatype->hasRepresentation()) {
assert(existMetatype->isLegalSILType());
return existMetatype;
}
return CanExistentialMetatypeType::get(existMetatype.getInstanceType(),
MetatypeRepresentation::Thick);
}
// Lower tuple element types.
CanType visitTupleType(CanTupleType substTupleType) {
return computeLoweredTupleType(TC, forExpansion, origType,
substTupleType);
}
// Lower the referent type of reference storage types.
CanType visitReferenceStorageType(CanReferenceStorageType substRefType) {
return computeLoweredReferenceStorageType(TC, forExpansion, origType,
substRefType);
}
CanType visitSILFunctionType(CanSILFunctionType silFnTy) {
if (!silFnTy->hasOpaqueArchetype() ||
!forExpansion.shouldLookThroughOpaqueTypeArchetypes())
return silFnTy;
return silFnTy->substituteOpaqueArchetypes(TC, forExpansion);
}
CanType visitType(CanType substType) {
// Lower the object type of optional types.
if (auto substObjectType = substType.getOptionalObjectType()) {
return computeLoweredOptionalType(TC, forExpansion, origType, substType,
substObjectType);
}
// The Swift type directly corresponds to the lowered type.
auto underlyingTy =
substOpaqueTypesWithUnderlyingTypes(substType, forExpansion,
/*allowLoweredTypes*/ true);
if (underlyingTy != substType) {
underlyingTy =
TC.computeLoweredRValueType(forExpansion, origType, underlyingTy);
}
return underlyingTy;
}
};
LoweredRValueTypeVisitor visitor(*this, forExpansion, origType);
return visitor.visit(substType);
}
const TypeLowering &
TypeConverter::getTypeLowering(SILType type,
TypeExpansionContext forExpansion,
CanGenericSignature sig) {
// The type lowering for a type parameter relies on its context.
assert(sig || !type.getASTType()->hasTypeParameter());
auto loweredType = type.getASTType();
auto isTypeExpansionSensitive = loweredType->hasOpaqueArchetype()
? IsTypeExpansionSensitive
: IsNotTypeExpansionSensitive;
return getTypeLoweringForLoweredType(AbstractionPattern(sig, loweredType),
loweredType, forExpansion,
isTypeExpansionSensitive);
}
const TypeLowering &
TypeConverter::getTypeLowering(SILType t, SILFunction &F) {
return getTypeLowering(t, TypeExpansionContext(F),
F.getLoweredFunctionType()->getSubstGenericSignature());
}
const TypeLowering &TypeConverter::getTypeLoweringForLoweredType(
AbstractionPattern origType, CanType loweredType,
TypeExpansionContext forExpansion,
IsTypeExpansionSensitive_t isTypeExpansionSensitive) {
assert(loweredType->isLegalSILType() && "type is not lowered!");
(void)loweredType;
// Cache the lowered type record for a contextualized type independent of the
// abstraction pattern. Lowered type parameters can't be cached or looked up
// without context. (TODO: We could if they match the out-of-context
// abstraction pattern.)
AbstractionPattern origTypeForCaching = loweredType->hasTypeParameter()
? AbstractionPattern::getInvalid()
: AbstractionPattern(loweredType);
auto key = getTypeKey(origTypeForCaching, loweredType, forExpansion);
auto *candidateLowering = find(key.getKeyForMinimalExpansion());
auto *lowering = getTypeLoweringForExpansion(
key, forExpansion, candidateLowering, isTypeExpansionSensitive);
if (lowering != nullptr)
return *lowering;
#ifndef NDEBUG
// Catch reentrancy bugs.
if (candidateLowering == nullptr)
insert(key.getKeyForMinimalExpansion(), nullptr);
#endif
if (forExpansion.shouldLookThroughOpaqueTypeArchetypes() &&
loweredType->hasOpaqueArchetype()) {
loweredType = computeLoweredRValueType(
forExpansion, origType, loweredType);
}
lowering =
LowerType(*this, forExpansion)
.visit(loweredType, origType, isTypeExpansionSensitive);
if (!lowering->isResilient() && !lowering->isTypeExpansionSensitive())
insert(key.getKeyForMinimalExpansion(), lowering);
else {
insert(key, lowering);
#ifndef NDEBUG
removeNullEntry(key.getKeyForMinimalExpansion());
#endif
}
return *lowering;
}
/// When we've found a type lowering for one resilience expansion,
/// check if its the one we want; if not, walk the list until we
/// find the right one, returning nullptr if the caller needs to
/// go ahead and lower the type with the correct expansion.
const TypeLowering *TypeConverter::getTypeLoweringForExpansion(
TypeKey key, TypeExpansionContext forExpansion,
const TypeLowering *minimalExpansionLowering,
IsTypeExpansionSensitive_t isOrigTypeSensitive) {
if (minimalExpansionLowering == nullptr)
return nullptr;
if (!minimalExpansionLowering->isResilient() &&
!minimalExpansionLowering->isTypeExpansionSensitive() &&
!isOrigTypeSensitive) {
// Don't try to refine the lowering for other resilience expansions if
// we don't expect to get a different lowering anyway. Similar if the
// original type did not have opaque type archetypes.
//
// See LowerType::handleResilience() for the gory details; we only
// set this flag if the type is resilient *and* inside our module.
return minimalExpansionLowering;
}
auto *exactLowering = find(key);
if (exactLowering)
return exactLowering;
// We have to create a new one.
return nullptr;
}
static GenericSignature
getEffectiveGenericSignature(DeclContext *dc,
CaptureInfo captureInfo) {
if (dc->getParent()->isLocalContext() &&
!captureInfo.hasGenericParamCaptures())
return nullptr;
return dc->getGenericSignatureOfContext();
}
static GenericSignature
getEffectiveGenericSignature(AnyFunctionRef fn,
CaptureInfo captureInfo) {
return getEffectiveGenericSignature(fn.getAsDeclContext(), captureInfo);
}
static CanGenericSignature
getCanonicalSignatureOrNull(GenericSignature sig) {
if (!sig || sig->areAllParamsConcrete())
return nullptr;
return sig.getCanonicalSignature();
}
/// Get the type of a global variable accessor function, () -> RawPointer.
static CanAnyFunctionType getGlobalAccessorType(CanType varType) {
ASTContext &C = varType->getASTContext();
return CanFunctionType::get({}, C.TheRawPointerType);
}
/// Removes @noescape from the given type if it's a function type. Otherwise,
/// returns the original type.
static CanType removeNoEscape(CanType resultType) {
if (auto funTy = resultType->getAs<AnyFunctionType>()) {
auto newExtInfo = funTy->getExtInfo().withNoEscape(false);
return adjustFunctionType(cast<AnyFunctionType>(resultType), newExtInfo);
}
return resultType;
}
/// Get the type of a default argument generator, () -> T.
static CanAnyFunctionType getDefaultArgGeneratorInterfaceType(
SILDeclRef c) {
auto *vd = c.getDecl();
auto resultTy = getParameterAt(vd,
c.defaultArgIndex)->getInterfaceType();
assert(resultTy && "Didn't find default argument?");
// The result type might be written in terms of type parameters
// that have been made fully concrete.
CanType canResultTy = resultTy->getCanonicalType(
vd->getInnermostDeclContext()
->getGenericSignatureOfContext());
// Remove @noescape from function return types. A @noescape
// function return type is a contradiction.
canResultTy = removeNoEscape(canResultTy);
// Get the generic signature from the surrounding context.
auto sig = vd->getInnermostDeclContext()->getGenericSignatureOfContext();
if (auto *afd = dyn_cast<AbstractFunctionDecl>(vd)) {
auto *param = getParameterAt(afd, c.defaultArgIndex);
if (param->hasDefaultExpr()) {
auto captureInfo = param->getDefaultArgumentCaptureInfo();
sig = getEffectiveGenericSignature(afd, captureInfo);
}
}
return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig),
{}, canResultTy);
}
/// Get the type of a stored property initializer, () -> T.
static CanAnyFunctionType getStoredPropertyInitializerInterfaceType(
VarDecl *VD) {
auto *DC = VD->getDeclContext();
CanType resultTy =
VD->getParentPattern()->getType()->mapTypeOutOfContext()
->getCanonicalType();
// If this is the backing storage for a property with an attached
// wrapper that was initialized with '=', the stored property initializer
// will be in terms of the original property's type.
if (auto originalProperty = VD->getOriginalWrappedProperty()) {
if (originalProperty->isPropertyMemberwiseInitializedWithWrappedType()) {
resultTy = originalProperty->getPropertyWrapperInitValueInterfaceType()
->getCanonicalType();
// Stored property initializers can't return @noescape functions
resultTy = removeNoEscape(resultTy);
}
}
auto sig = DC->getGenericSignatureOfContext();
return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig),
{}, resultTy);
}
/// Get the type of a property wrapper backing initializer,
/// (property-type) -> backing-type.
static CanAnyFunctionType getPropertyWrapperBackingInitializerInterfaceType(
TypeConverter &TC,
VarDecl *VD) {
CanType resultType =
VD->getPropertyWrapperBackingPropertyType()->getCanonicalType();
auto *DC = VD->getInnermostDeclContext();
CanType inputType =
VD->getPropertyWrapperInitValueInterfaceType()->getCanonicalType();
auto sig = DC->getGenericSignatureOfContext();
AnyFunctionType::Param param(
inputType, Identifier(),
ParameterTypeFlags().withValueOwnership(ValueOwnership::Owned));
return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig), {param},
resultType);
}
/// Get the type of a destructor function.
static CanAnyFunctionType getDestructorInterfaceType(DestructorDecl *dd,
bool isDeallocating,
bool isForeign) {
auto classType = dd->getDeclContext()->getDeclaredInterfaceType()
->getCanonicalType(dd->getGenericSignatureOfContext());
assert((!isForeign || isDeallocating)
&& "There are no foreign destroying destructors");
auto extInfoBuilder =
AnyFunctionType::ExtInfoBuilder(FunctionType::Representation::Thin,
/*throws*/ false);
if (isForeign)
extInfoBuilder = extInfoBuilder.withSILRepresentation(
SILFunctionTypeRepresentation::ObjCMethod);
else
extInfoBuilder = extInfoBuilder.withSILRepresentation(
SILFunctionTypeRepresentation::Method);
auto extInfo = extInfoBuilder.build();
auto &C = dd->getASTContext();
CanType resultTy = (isDeallocating
? TupleType::getEmpty(C)
: C.TheNativeObjectType);
CanType methodTy = CanFunctionType::get({}, resultTy);
auto sig = dd->getGenericSignatureOfContext();
FunctionType::Param args[] = {FunctionType::Param(classType)};
return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig),
llvm::makeArrayRef(args),
methodTy, extInfo);
}
/// Retrieve the type of the ivar initializer or destroyer method for
/// a class.
static CanAnyFunctionType getIVarInitDestroyerInterfaceType(ClassDecl *cd,
bool isObjC,
bool isDestroyer) {
auto classType = cd->getDeclaredInterfaceType()
->getCanonicalType(cd->getGenericSignatureOfContext());
auto resultType = (isDestroyer
? TupleType::getEmpty(cd->getASTContext())
: classType);
auto extInfoBuilder =
AnyFunctionType::ExtInfoBuilder(FunctionType::Representation::Thin,
/*throws*/ false);
auto extInfo = extInfoBuilder
.withSILRepresentation(
isObjC ? SILFunctionTypeRepresentation::ObjCMethod
: SILFunctionTypeRepresentation::Method)
.build();
resultType = CanFunctionType::get({}, resultType, extInfo);
auto sig = cd->getGenericSignature();
FunctionType::Param args[] = {FunctionType::Param(classType)};
return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig),
llvm::makeArrayRef(args),
resultType, extInfo);
}
static CanAnyFunctionType
getFunctionInterfaceTypeWithCaptures(TypeConverter &TC,
CanAnyFunctionType funcType,
SILDeclRef constant) {
// Get transitive closure of value captured by this function, and any
// captured functions.
auto captureInfo = TC.getLoweredLocalCaptures(constant);
// Capture generic parameters from the enclosing context if necessary.
auto closure = *constant.getAnyFunctionRef();
auto genericSig = getEffectiveGenericSignature(closure, captureInfo);
auto innerExtInfo =
AnyFunctionType::ExtInfoBuilder(FunctionType::Representation::Thin,
funcType->isThrowing())
.withAsync(funcType->isAsync())
.build();
return CanAnyFunctionType::get(
getCanonicalSignatureOrNull(genericSig),
funcType.getParams(), funcType.getResult(),
innerExtInfo);
}
CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) {
if (auto *derivativeId = c.getDerivativeFunctionIdentifier()) {
auto originalFnTy =
makeConstantInterfaceType(c.asAutoDiffOriginalFunction());
auto *derivativeFnTy = originalFnTy->getAutoDiffDerivativeFunctionType(
derivativeId->getParameterIndices(), derivativeId->getKind(),
LookUpConformanceInModule(&M));
return cast<AnyFunctionType>(derivativeFnTy->getCanonicalType());
}
auto *vd = c.loc.dyn_cast<ValueDecl *>();
switch (c.kind) {
case SILDeclRef::Kind::Func: {
CanAnyFunctionType funcTy;
if (auto *ACE = c.loc.dyn_cast<AbstractClosureExpr *>()) {
// FIXME: Closures could have an interface type computed by Sema.
funcTy = cast<AnyFunctionType>(
ACE->getType()->mapTypeOutOfContext()->getCanonicalType());
} else {
funcTy = cast<AnyFunctionType>(
vd->getInterfaceType()->getCanonicalType());
}
return getFunctionInterfaceTypeWithCaptures(*this, funcTy, c);
}
case SILDeclRef::Kind::EnumElement: {
auto funcTy = cast<AnyFunctionType>(
vd->getInterfaceType()->getCanonicalType());
auto sig = vd->getDeclContext()->getGenericSignatureOfContext();
return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig),
funcTy->getParams(),
funcTy.getResult(),
funcTy->getExtInfo());
}
case SILDeclRef::Kind::Allocator: {
auto *cd = cast<ConstructorDecl>(vd);
auto funcTy = cast<AnyFunctionType>(
cd->getInterfaceType()->getCanonicalType());
return getFunctionInterfaceTypeWithCaptures(*this, funcTy, c);
}
case SILDeclRef::Kind::Initializer: {
auto *cd = cast<ConstructorDecl>(vd);
auto funcTy = cast<AnyFunctionType>(
cd->getInitializerInterfaceType()->getCanonicalType());
return getFunctionInterfaceTypeWithCaptures(*this, funcTy, c);
}
case SILDeclRef::Kind::Destroyer:
case SILDeclRef::Kind::Deallocator:
return getDestructorInterfaceType(cast<DestructorDecl>(vd),
c.kind == SILDeclRef::Kind::Deallocator,
c.isForeign);
case SILDeclRef::Kind::GlobalAccessor: {
VarDecl *var = cast<VarDecl>(vd);
assert(var->hasStorage() &&
"constant ref to computed global var");
return getGlobalAccessorType(var->getInterfaceType()->getCanonicalType());
}
case SILDeclRef::Kind::DefaultArgGenerator:
return getDefaultArgGeneratorInterfaceType(c);
case SILDeclRef::Kind::StoredPropertyInitializer:
return getStoredPropertyInitializerInterfaceType(cast<VarDecl>(vd));
case SILDeclRef::Kind::PropertyWrapperBackingInitializer:
return getPropertyWrapperBackingInitializerInterfaceType(*this,
cast<VarDecl>(vd));
case SILDeclRef::Kind::IVarInitializer:
return getIVarInitDestroyerInterfaceType(cast<ClassDecl>(vd),
c.isForeign, false);
case SILDeclRef::Kind::IVarDestroyer:
return getIVarInitDestroyerInterfaceType(cast<ClassDecl>(vd),
c.isForeign, true);
}
llvm_unreachable("Unhandled SILDeclRefKind in switch.");
}
GenericSignature
TypeConverter::getConstantGenericSignature(SILDeclRef c) {
auto *vd = c.loc.dyn_cast<ValueDecl *>();
/// Get the function generic params, including outer params.
switch (c.kind) {
case SILDeclRef::Kind::Func:
case SILDeclRef::Kind::Allocator:
case SILDeclRef::Kind::Initializer:
case SILDeclRef::Kind::Destroyer:
case SILDeclRef::Kind::Deallocator: {
auto captureInfo = getLoweredLocalCaptures(c);
return getEffectiveGenericSignature(
*c.getAnyFunctionRef(), captureInfo);
}
case SILDeclRef::Kind::IVarInitializer:
case SILDeclRef::Kind::IVarDestroyer:
return cast<ClassDecl>(vd)->getGenericSignature();
case SILDeclRef::Kind::DefaultArgGenerator: {
// Use the generic environment of the original function.
auto captureInfo = getLoweredLocalCaptures(c);
return getEffectiveGenericSignature(
vd->getInnermostDeclContext(), captureInfo);
}
case SILDeclRef::Kind::EnumElement:
case SILDeclRef::Kind::GlobalAccessor:
case SILDeclRef::Kind::StoredPropertyInitializer:
case SILDeclRef::Kind::PropertyWrapperBackingInitializer:
return vd->getDeclContext()->getGenericSignatureOfContext();
}
llvm_unreachable("Unhandled SILDeclRefKind in switch.");
}
GenericEnvironment *
TypeConverter::getConstantGenericEnvironment(SILDeclRef c) {
if (auto sig = getConstantGenericSignature(c))
return sig->getGenericEnvironment();
return nullptr;
}
SILType TypeConverter::getSubstitutedStorageType(TypeExpansionContext context,
AbstractStorageDecl *value,
Type lvalueType) {
// The l-value type is the result of applying substitutions to
// the type-of-reference. Essentially, we want to apply those
// same substitutions to value->getType().
// Canonicalize and lower the l-value's object type.
AbstractionPattern origType = getAbstractionPattern(value);
CanType substType = lvalueType->getCanonicalType();
assert(!isa<LValueType>(substType));
// Look through reference storage on the original type.
auto origRefType = origType.getAs<ReferenceStorageType>();
if (origRefType) {
origType = origType.getReferenceStorageReferentType();
substType = substType.getReferenceStorageReferent();
}
CanType substLoweredType = getLoweredRValueType(context, origType, substType);
// Type substitution preserves structural type structure, and the
// type-of-reference is only different in the outermost structural
// types. So, basically, we just need to undo the changes made by
// getTypeOfReference and then reapply them on the substituted type.
// The only really significant manipulation there is with @weak and
// @unowned.
if (origRefType) {
substLoweredType = CanReferenceStorageType::get(substType,
origRefType->getOwnership());
}
return SILType::getPrimitiveAddressType(substLoweredType);
}
ProtocolDispatchStrategy
TypeConverter::getProtocolDispatchStrategy(ProtocolDecl *P) {
// ObjC protocols use ObjC method dispatch, and Swift protocols
// use witness tables.
if (P->isObjC())
return ProtocolDispatchStrategy::ObjC;
return ProtocolDispatchStrategy::Swift;
}
/// If a capture references a local function, return a reference to that
/// function.
static Optional<AnyFunctionRef>
getAnyFunctionRefFromCapture(CapturedValue capture) {
if (auto *afd = dyn_cast<AbstractFunctionDecl>(capture.getDecl()))
return AnyFunctionRef(afd);
return None;
}
bool
TypeConverter::hasLoweredLocalCaptures(SILDeclRef fn) {
return !getLoweredLocalCaptures(fn).getCaptures().empty();
}
CaptureInfo
TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
PrettyStackTraceSILLocation stack("getting lowered local captures",
fn.getAsRegularLocation(), Context);
// If we're guaranteed to never have local captures, bail out now.
switch (fn.kind) {
case SILDeclRef::Kind::StoredPropertyInitializer:
case SILDeclRef::Kind::PropertyWrapperBackingInitializer:
return CaptureInfo::empty();
default:
if (fn.hasDecl()) {
if (!fn.getDecl()->isLocalCapture())
return CaptureInfo::empty();
}
break;
}
fn.isForeign = 0;
// See if we've cached the lowered capture list for this function.
auto found = LoweredCaptures.find(fn);
if (found != LoweredCaptures.end())
return found->second;
// Recursively collect transitive captures from captured local functions.
llvm::DenseSet<AnyFunctionRef> visitedFunctions;
llvm::MapVector<ValueDecl*,CapturedValue> captures;
// If there is a capture of 'self' with dynamic 'Self' type, it goes last so
// that IRGen can pass dynamic 'Self' metadata.
Optional<CapturedValue> selfCapture;
bool capturesGenericParams = false;
DynamicSelfType *capturesDynamicSelf = nullptr;
OpaqueValueExpr *capturesOpaqueValue = nullptr;
std::function<void (CaptureInfo captureInfo, DeclContext *dc)> collectCaptures;
std::function<void (AnyFunctionRef)> collectFunctionCaptures;
std::function<void (SILDeclRef)> collectConstantCaptures;
collectCaptures = [&](CaptureInfo captureInfo, DeclContext *dc) {
assert(captureInfo.hasBeenComputed());
if (captureInfo.hasGenericParamCaptures())
capturesGenericParams = true;
if (captureInfo.hasDynamicSelfCapture())
capturesDynamicSelf = captureInfo.getDynamicSelfType();
if (captureInfo.hasOpaqueValueCapture())
capturesOpaqueValue = captureInfo.getOpaqueValue();
SmallVector<CapturedValue, 4> localCaptures;
captureInfo.getLocalCaptures(localCaptures);
for (auto capture : localCaptures) {
// If the capture is of another local function, grab its transitive
// captures instead.
if (auto capturedFn = getAnyFunctionRefFromCapture(capture)) {
collectFunctionCaptures(*capturedFn);
continue;
}
// If the capture is of a computed property, grab the transitive captures
// of its accessors.
if (auto capturedVar = dyn_cast<VarDecl>(capture.getDecl())) {
auto collectAccessorCaptures = [&](AccessorKind kind) {
if (auto *accessor = capturedVar->getParsedAccessor(kind))
collectFunctionCaptures(accessor);
};
if (!capture.isDirect()) {
auto impl = capturedVar->getImplInfo();
switch (impl.getReadImpl()) {
case ReadImplKind::Stored:
// Will capture storage later.
break;
case ReadImplKind::Address:
collectAccessorCaptures(AccessorKind::Address);
break;
case ReadImplKind::Get:
collectAccessorCaptures(AccessorKind::Get);
break;
case ReadImplKind::Read:
collectAccessorCaptures(AccessorKind::Read);
break;
case ReadImplKind::Inherited:
llvm_unreachable("inherited local variable?");
}
switch (impl.getWriteImpl()) {
case WriteImplKind::Immutable:
case WriteImplKind::Stored:
break;
case WriteImplKind::StoredWithObservers:
collectAccessorCaptures(AccessorKind::WillSet);
collectAccessorCaptures(AccessorKind::DidSet);
break;
case WriteImplKind::Set:
collectAccessorCaptures(AccessorKind::Set);
break;
case WriteImplKind::MutableAddress:
collectAccessorCaptures(AccessorKind::MutableAddress);
break;
case WriteImplKind::Modify:
collectAccessorCaptures(AccessorKind::Modify);
break;
case WriteImplKind::InheritedWithObservers:
llvm_unreachable("inherited local variable");
}
switch (impl.getReadWriteImpl()) {
case ReadWriteImplKind::Immutable:
case ReadWriteImplKind::Stored:
break;
case ReadWriteImplKind::MaterializeToTemporary:
// We've already processed the read and write operations.
break;
case ReadWriteImplKind::MutableAddress:
collectAccessorCaptures(AccessorKind::MutableAddress);
break;
case ReadWriteImplKind::Modify:
collectAccessorCaptures(AccessorKind::Modify);
break;
case ReadWriteImplKind::StoredWithDidSet:
// We've already processed the didSet operation.
break;
case ReadWriteImplKind::InheritedWithDidSet:
llvm_unreachable("inherited local variable");
}
}
if (!capturedVar->hasStorage())
continue;
// We can always capture the storage in these cases.
Type captureType = capturedVar->getType()->getMetatypeInstanceType();
if (auto *selfType = captureType->getAs<DynamicSelfType>()) {
captureType = selfType->getSelfType();
// We're capturing a 'self' value with dynamic 'Self' type;
// handle it specially.
//
// However, only do this if its a 'let'; if the capture is
// mutable, we're going to be capturing a box or an address.
if (captureType->getClassOrBoundGenericClass() &&
capturedVar->isLet()) {
// If we've already captured the same value already, just merge
// flags.
if (selfCapture && selfCapture->getDecl() == capture.getDecl()) {
selfCapture = selfCapture->mergeFlags(capture);
continue;
// Otherwise, record the canonical self capture. It will appear
// at the end of the capture list.
} else if (!selfCapture) {
selfCapture = capture;
continue;
}
// If we end up here, we have multiple different captured values
// with a dynamic 'Self' type. Handle this and any subsequent
// captures via the normal code path below.
}
}
// Fall through to capture the storage.
}
// Collect non-function captures.
ValueDecl *value = capture.getDecl();
auto existing = captures.find(value);
if (existing != captures.end()) {
existing->second = existing->second.mergeFlags(capture);
} else {
captures.insert(std::pair<ValueDecl *, CapturedValue>(value, capture));
}
}
};
collectFunctionCaptures = [&](AnyFunctionRef curFn) {
if (!curFn.getBody())
return;
if (!visitedFunctions.insert(curFn).second)
return;
PrettyStackTraceAnyFunctionRef("lowering local captures", curFn);
auto dc = curFn.getAsDeclContext();
collectCaptures(curFn.getCaptureInfo(), dc);
// A function's captures also include its default arguments, because
// when we reference a function we don't track which default arguments
// are referenced too.
//
// FIXME: This should be more fine-grained -- we should only need the
// captures for default arguments that are actually referenced.
if (auto *AFD = curFn.getAbstractFunctionDecl()) {
for (auto *P : *AFD->getParameters()) {
if (P->hasDefaultExpr())
collectCaptures(P->getDefaultArgumentCaptureInfo(), dc);
}
}
};
collectConstantCaptures = [&](SILDeclRef curFn) {
if (curFn.isDefaultArgGenerator()) {
PrettyStackTraceSILLocation stack("lowering local captures",
fn.getAsRegularLocation(), Context);
if (auto *afd = dyn_cast<AbstractFunctionDecl>(curFn.getDecl())) {
auto *param = getParameterAt(afd, curFn.defaultArgIndex);
if (param->hasDefaultExpr()) {
auto dc = afd->getInnermostDeclContext();
collectCaptures(param->getDefaultArgumentCaptureInfo(), dc);
}
return;
}
if (curFn.getDecl()->getInnermostDeclContext()
->getGenericSignatureOfContext())
capturesGenericParams = true;
return;
}
collectFunctionCaptures(*curFn.getAnyFunctionRef());
};
collectConstantCaptures(fn);
SmallVector<CapturedValue, 4> resultingCaptures;
for (auto capturePair : captures) {
resultingCaptures.push_back(capturePair.second);
}
// If we captured an opaque value, add it.
if (capturesOpaqueValue) {
resultingCaptures.push_back(CapturedValue(capturesOpaqueValue, 0));
}
// If we captured the dynamic 'Self' type and we have a 'self' value also,
// add it as the final capture. Otherwise, add a fake hidden capture for
// the dynamic 'Self' metatype.
if (selfCapture.hasValue()) {
resultingCaptures.push_back(*selfCapture);
} else if (capturesDynamicSelf) {
selfCapture = CapturedValue::getDynamicSelfMetadata();
resultingCaptures.push_back(*selfCapture);
}
// Cache the uniqued set of transitive captures.
CaptureInfo info{Context, resultingCaptures, capturesDynamicSelf,
capturesOpaqueValue, capturesGenericParams};
auto inserted = LoweredCaptures.insert({fn, info});
assert(inserted.second && "already in map?!");
(void)inserted;
return info;
}
/// Given that type1 is known to be a subtype of type2, check if the two
/// types have the same calling convention representation.
TypeConverter::ABIDifference
TypeConverter::checkForABIDifferences(SILModule &M,
SILType type1, SILType type2,
bool thunkOptionals) {
// Unwrap optionals, but remember that we did.
bool type1WasOptional = false;
bool type2WasOptional = false;
if (auto object = type1.getOptionalObjectType()) {
type1WasOptional = true;
type1 = object;
}
if (auto object = type2.getOptionalObjectType()) {
type2WasOptional = true;
type2 = object;
}
bool optionalityChange;
if (thunkOptionals) {
// Forcing IUOs always requires a thunk.
if (type1WasOptional && !type2WasOptional)
return ABIDifference::NeedsThunk;
// Except for the above case, we should not be making a value less optional.
// If we're introducing a level of optionality, only certain types are
// ABI-compatible -- check below.
optionalityChange = (!type1WasOptional && type2WasOptional);
} else {
// We haven't implemented codegen for optional thunking at all levels
// (particularly objc_blocks at depth). Just accept ABI compatibility
// in either direction in these cases.
optionalityChange = type1WasOptional != type2WasOptional;
}
// If the types are identical and there was no optionality change,
// we're done.
if (type1 == type2 && !optionalityChange)
return ABIDifference::CompatibleRepresentation;
// Classes, class-constrained archetypes, and pure-ObjC existential types
// all have single retainable pointer representation; optionality change
// is allowed.
if (type1.getASTType()->satisfiesClassConstraint() &&
type2.getASTType()->satisfiesClassConstraint())
return ABIDifference::CompatibleRepresentation;
// Function parameters are ABI compatible if their differences are
// trivial.
if (auto fnTy1 = type1.getAs<SILFunctionType>()) {
if (auto fnTy2 = type2.getAs<SILFunctionType>()) {
// Async/synchronous conversions always need a thunk.
if (fnTy1->isAsync() != fnTy2->isAsync())
return ABIDifference::NeedsThunk;
// @convention(block) is a single retainable pointer so optionality
// change is allowed.
if (optionalityChange)
if (fnTy1->getRepresentation() != fnTy2->getRepresentation() ||
fnTy1->getRepresentation() != SILFunctionTypeRepresentation::Block)
return ABIDifference::NeedsThunk;
return checkFunctionForABIDifferences(M, fnTy1, fnTy2);
}
}
// Metatypes are ABI-compatible if they have the same representation.
if (auto meta1 = type1.getAs<MetatypeType>()) {
if (auto meta2 = type2.getAs<MetatypeType>()) {
if (meta1->getRepresentation() == meta2->getRepresentation() &&
(!optionalityChange ||
meta1->getRepresentation() == MetatypeRepresentation::Thick))
return ABIDifference::CompatibleRepresentation;
}
}
// Existential metatypes which are not identical are only ABI-compatible
// in @objc representation.
//
// Optionality change is allowed since @objc existential metatypes have a
// single retainable pointer representation.
if (auto meta1 = type1.getAs<ExistentialMetatypeType>()) {
if (auto meta2 = type2.getAs<ExistentialMetatypeType>()) {
if (meta1->getRepresentation() == meta2->getRepresentation() &&
meta1->getRepresentation() == MetatypeRepresentation::ObjC)
return ABIDifference::CompatibleRepresentation;
}
}
// Tuple types are ABI-compatible if their elements are.
if (!optionalityChange) {
if (auto tuple1 = type1.getAs<TupleType>()) {
if (auto tuple2 = type2.getAs<TupleType>()) {
if (tuple1->getNumElements() != tuple2->getNumElements())
return ABIDifference::NeedsThunk;
for (unsigned i = 0, e = tuple1->getNumElements(); i < e; i++) {
if (checkForABIDifferences(M,
type1.getTupleElementType(i),
type2.getTupleElementType(i))
!= ABIDifference::CompatibleRepresentation)
return ABIDifference::NeedsThunk;
}
// Tuple lengths and elements match
return ABIDifference::CompatibleRepresentation;
}
}
}
// The types are different, or there was an optionality change resulting
// in a change in representation.
return ABIDifference::NeedsThunk;
}
namespace {
class HaveDifferentAbstractStructure
: public CanTypeDifferenceVisitor<HaveDifferentAbstractStructure> {
public:
// Treat any sort of abstract type as equivalent.
static bool isAbstract(CanType type) {
return (isa<SubstitutableType>(type) || isa<DependentMemberType>(type));
};
// We can fast-path some of these checks by proviing these two overrides:
bool visitSubstitutableType(CanSubstitutableType type1,
CanSubstitutableType type2) {
return false;
}
bool visitDependentMemberType(CanDependentMemberType type1,
CanDependentMemberType type2) {
return false;
}
// We also need to handle the general case where we have different
// kinds of substitutable types.
bool visitDifferentComponentTypes(CanType type1, CanType type2) {
// This is a difference only if both types aren't abstract.
return !(isAbstract(type1) && isAbstract(type2));
}
// Change the rules used for SIL function types to only consider
// the basic structure, not any substitutions.
bool visitSILFunctionType(CanSILFunctionType type1,
CanSILFunctionType type2) {
return visitSILFunctionTypeStructure(type1, type2)
|| visitSILFunctionTypeComponents(type1, type2);
}
};
}
static bool haveDifferentAbstractStructure(CanType type1, CanType type2) {
return HaveDifferentAbstractStructure().visit(type1, type2);
}
static TypeConverter::ABIDifference
checkForABIDifferencesInYield(TypeConverter &TC, SILModule &M,
SILFunctionType *fnTy1, SILYieldInfo yield1,
SILFunctionType *fnTy2, SILYieldInfo yield2) {
// Require the interface types to have the same basic abstract
// structure, ignoring any substitutions from the function type.
// This structure is what determines the signature of the continuation
// function.
if (haveDifferentAbstractStructure(yield1.getInterfaceType(),
yield2.getInterfaceType()))
return TypeConverter::ABIDifference::NeedsThunk;
// Also make sure that the actual yield types match in ABI.
return TC.checkForABIDifferences(
M, yield1.getSILStorageType(M, fnTy1, TypeExpansionContext::minimal()),
yield2.getSILStorageType(M, fnTy2, TypeExpansionContext::minimal()));
}
TypeConverter::ABIDifference
TypeConverter::checkFunctionForABIDifferences(SILModule &M,
SILFunctionType *fnTy1,
SILFunctionType *fnTy2) {
// For now, only differentiate representation from calling convention when
// staging in substituted function types.
//
// We might still want to conditionalize this behavior even after we commit
// substituted function types, to avoid bloating
// IR for platforms that don't differentiate function type representations.
bool DifferentFunctionTypesHaveDifferentRepresentation
= Context.LangOpts.EnableSubstSILFunctionTypesForFunctionValues;
// TODO: For C language types we should consider the attached Clang types.
if (fnTy1->getLanguage() == SILFunctionLanguage::C)
DifferentFunctionTypesHaveDifferentRepresentation = false;
// Fast path -- if both functions were unwrapped from a CanSILFunctionType,
// we might have pointer equality here.
if (fnTy1 == fnTy2)
return ABIDifference::CompatibleRepresentation;
if (fnTy1->getParameters().size() != fnTy2->getParameters().size())
return ABIDifference::NeedsThunk;
if (fnTy1->getNumResults() != fnTy2->getNumResults())
return ABIDifference::NeedsThunk;
if (fnTy1->getNumYields() != fnTy2->getNumYields())
return ABIDifference::NeedsThunk;
// If we don't have a context but the other type does, we'll return
// ABIDifference::ThinToThick below.
if (fnTy1->getExtInfo().hasContext() &&
fnTy1->getCalleeConvention() != fnTy2->getCalleeConvention())
return ABIDifference::NeedsThunk;
for (unsigned i : indices(fnTy1->getResults())) {
auto result1 = fnTy1->getResults()[i];
auto result2 = fnTy2->getResults()[i];
if (result1.getConvention() != result2.getConvention())
return ABIDifference::NeedsThunk;
if (checkForABIDifferences(M,
result1.getSILStorageType(
M, fnTy1, TypeExpansionContext::minimal()),
result2.getSILStorageType(
M, fnTy2, TypeExpansionContext::minimal()),
/*thunk iuos*/ fnTy1->getLanguage() ==
SILFunctionLanguage::Swift) !=
ABIDifference::CompatibleRepresentation)
return ABIDifference::NeedsThunk;
}
for (unsigned i : indices(fnTy1->getYields())) {
auto yield1 = fnTy1->getYields()[i];
auto yield2 = fnTy2->getYields()[i];
if (yield1.getConvention() != yield2.getConvention())
return ABIDifference::NeedsThunk;
if (checkForABIDifferencesInYield(*this, M, fnTy1, yield1, fnTy2, yield2)
!= ABIDifference::CompatibleRepresentation)
return ABIDifference::NeedsThunk;
}
// If one type does not have an error result, we can still trivially cast
// (casting away an error result is only safe if the function never throws,
// of course).
if (fnTy1->hasErrorResult() && fnTy2->hasErrorResult()) {
auto error1 = fnTy1->getErrorResult(), error2 = fnTy2->getErrorResult();
if (error1.getConvention() != error2.getConvention())
return ABIDifference::NeedsThunk;
if (checkForABIDifferences(
M,
error1.getSILStorageType(M, fnTy1, TypeExpansionContext::minimal()),
error2.getSILStorageType(M, fnTy2, TypeExpansionContext::minimal()),
/*thunk iuos*/ fnTy1->getLanguage() ==
SILFunctionLanguage::Swift) !=
ABIDifference::CompatibleRepresentation)
return ABIDifference::NeedsThunk;
}
for (unsigned i = 0, e = fnTy1->getParameters().size(); i < e; ++i) {
auto param1 = fnTy1->getParameters()[i], param2 = fnTy2->getParameters()[i];
if (param1.getConvention() != param2.getConvention())
return ABIDifference::NeedsThunk;
// Parameters are contravariant and our relation is not symmetric, so
// make sure to flip the relation around.
if (checkForABIDifferences(
M,
param2.getSILStorageType(M, fnTy2, TypeExpansionContext::minimal()),
param1.getSILStorageType(M, fnTy1, TypeExpansionContext::minimal()),
/*thunk iuos*/ fnTy1->getLanguage() ==
SILFunctionLanguage::Swift) !=
ABIDifference::CompatibleRepresentation)
return ABIDifference::NeedsThunk;
}
auto rep1 = fnTy1->getRepresentation(), rep2 = fnTy2->getRepresentation();
if (rep1 != rep2) {
if (rep1 == SILFunctionTypeRepresentation::Thin &&
rep2 == SILFunctionTypeRepresentation::Thick) {
if (DifferentFunctionTypesHaveDifferentRepresentation) {
// FIXME: check whether the representations are compatible modulo
// context
return ABIDifference::CompatibleCallingConvention_ThinToThick;
} else {
return ABIDifference::CompatibleRepresentation_ThinToThick;
}
}
return ABIDifference::NeedsThunk;
}
if (DifferentFunctionTypesHaveDifferentRepresentation)
return ABIDifference::CompatibleCallingConvention;
else
return ABIDifference::CompatibleRepresentation;
}
CanSILBoxType
TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured,
CanType loweredInterfaceType,
bool isMutable) {
auto &C = M.getASTContext();
auto signature = getCanonicalSignatureOrNull(
captured->getDeclContext()->getGenericSignatureOfContext());
// If the type is not dependent at all, we can form a concrete box layout.
// We don't need to capture the generic environment.
if (!loweredInterfaceType->hasTypeParameter()) {
auto layout = SILLayout::get(C, nullptr,
SILField(loweredInterfaceType, isMutable));
return SILBoxType::get(C, layout, {});
}
// Otherwise, the layout needs to capture the generic environment of its
// originating scope.
// TODO: We could conceivably minimize the captured generic environment to
// only the parts used by the captured variable.
auto layout = SILLayout::get(C, signature,
SILField(loweredInterfaceType, isMutable));
// Instantiate the layout with identity substitutions.
auto subMap = SubstitutionMap::get(
signature,
[&](SubstitutableType *type) -> Type {
return signature->getCanonicalTypeInContext(type);
},
MakeAbstractConformanceForGenericType());
auto boxTy = SILBoxType::get(C, layout, subMap);
#ifndef NDEBUG
auto loweredContextType = loweredInterfaceType;
auto contextBoxTy = boxTy;
if (signature) {
auto env = signature->getGenericEnvironment();
loweredContextType = env->mapTypeIntoContext(loweredContextType)
->getCanonicalType();
contextBoxTy = cast<SILBoxType>(
env->mapTypeIntoContext(contextBoxTy)
->getCanonicalType());
}
assert(contextBoxTy->getLayout()->getFields().size() == 1 &&
getSILBoxFieldType(TypeExpansionContext::minimal(), contextBoxTy,
*this, 0)
.getASTType() == loweredContextType &&
"box field type doesn't match capture!");
#endif
return boxTy;
}
CanSILBoxType
TypeConverter::getContextBoxTypeForCapture(ValueDecl *captured,
CanType loweredContextType,
GenericEnvironment *env,
bool isMutable) {
CanType loweredInterfaceType = loweredContextType;
if (env) {
auto homeSig = captured->getDeclContext()
->getGenericSignatureOfContext();
loweredInterfaceType =
loweredInterfaceType->mapTypeOutOfContext()
->getCanonicalType(homeSig);
}
auto boxType = getInterfaceBoxTypeForCapture(captured,
loweredInterfaceType,
isMutable);
if (env)
boxType = cast<SILBoxType>(
env->mapTypeIntoContext(boxType)
->getCanonicalType());
return boxType;
}
CanSILBoxType TypeConverter::getBoxTypeForEnumElement(
TypeExpansionContext context, SILType enumType, EnumElementDecl *elt) {
auto *enumDecl = enumType.getEnumOrBoundGenericEnum();
assert(elt->getDeclContext() == enumDecl);
assert(elt->isIndirect() || elt->getParentEnum()->isIndirect());
auto &C = M.getASTContext();
auto boxSignature = getCanonicalSignatureOrNull(
enumDecl->getGenericSignature());
if (boxSignature == CanGenericSignature()) {
auto eltIntfTy = elt->getArgumentInterfaceType();
auto boxVarTy = getLoweredRValueType(context, eltIntfTy);
auto layout = SILLayout::get(C, nullptr, SILField(boxVarTy, true));
return SILBoxType::get(C, layout, {});
}
// Use the enum's signature for the box type.
auto boundEnum = enumType.getASTType();
// Lower the enum element's argument in the box's context.
auto eltIntfTy = elt->getArgumentInterfaceType();
auto boxVarTy = getLoweredRValueType(context,
getAbstractionPattern(elt), eltIntfTy);
auto layout = SILLayout::get(C, boxSignature, SILField(boxVarTy, true));
// Instantiate the layout with enum's substitution list.
auto subMap = boundEnum->getContextSubstitutionMap(
&M, enumDecl, enumDecl->getGenericEnvironment());
auto boxTy = SILBoxType::get(C, layout, subMap);
return boxTy;
}
static void countNumberOfInnerFields(unsigned &fieldsCount, TypeConverter &TC,
SILType Ty,
TypeExpansionContext expansion) {
if (auto *structDecl = Ty.getStructOrBoundGenericStruct()) {
assert(
!structDecl->isResilient(&TC.M, expansion.getResilienceExpansion()) &&
" FSO should not be trying to explode resilient (ie address-only) "
"types at all");
for (auto *prop : structDecl->getStoredProperties()) {
SILType propTy = Ty.getFieldType(prop, TC, expansion);
unsigned fieldsCountBefore = fieldsCount;
countNumberOfInnerFields(fieldsCount, TC, propTy, expansion);
if (fieldsCount == fieldsCountBefore) {
// size of Struct(BigStructType) == size of BigStructType()
// prevent counting its size as BigStructType()+1
++fieldsCount;
}
}
return;
}
if (auto tupleTy = Ty.getAs<TupleType>()) {
for (auto elt : tupleTy.getElementTypes()) {
auto silElt = SILType::getPrimitiveObjectType(elt);
countNumberOfInnerFields(fieldsCount, TC, silElt, expansion);
}
return;
}
if (auto *enumDecl = Ty.getEnumOrBoundGenericEnum()) {
if (enumDecl->isIndirect()) {
return;
}
assert(!enumDecl->isResilient(&TC.M, expansion.getResilienceExpansion()) &&
" FSO should not be trying to explode resilient (ie address-only) "
"types at all");
unsigned fieldsCountBefore = fieldsCount;
unsigned maxEnumCount = 0;
for (auto elt : enumDecl->getAllElements()) {
if (!elt->hasAssociatedValues())
continue;
if (elt->isIndirect())
continue;
// Although one might assume enums have a fields count of 1
// Which holds true for current uses of this code
// (we shouldn't expand enums)
// Number of fields > 1 as "future proof" for this heuristic:
// In case it is used by a pass that tries to explode enums.
auto payloadTy = Ty.getEnumElementType(elt, TC, expansion);
fieldsCount = 0;
countNumberOfInnerFields(fieldsCount, TC, payloadTy, expansion);
if (fieldsCount > maxEnumCount) {
maxEnumCount = fieldsCount;
}
}
fieldsCount = fieldsCountBefore + maxEnumCount;
return;
}
}
unsigned TypeConverter::countNumberOfFields(SILType Ty,
TypeExpansionContext expansion) {
auto key = std::make_pair(Ty, unsigned(expansion.getResilienceExpansion()));
auto Iter = TypeFields.find(key);
if (Iter != TypeFields.end()) {
return std::max(Iter->second, 1U);
}
unsigned fieldsCount = 0;
countNumberOfInnerFields(fieldsCount, *this, Ty, expansion);
TypeFields[key] = fieldsCount;
return std::max(fieldsCount, 1U);
}
void TypeLowering::print(llvm::raw_ostream &os) const {
auto BOOL = [&](bool b) -> StringRef {
if (b)
return "true";
return "false";
};
os << "Type Lowering for lowered type: " << LoweredType << ".\n"
<< "Expansion: " << getResilienceExpansion() << "\n"
<< "isTrivial: " << BOOL(Properties.isTrivial()) << ".\n"
<< "isFixedABI: " << BOOL(Properties.isFixedABI()) << ".\n"
<< "isAddressOnly: " << BOOL(Properties.isAddressOnly()) << ".\n"
<< "isResilient: " << BOOL(Properties.isResilient()) << ".\n"
<< "\n";
}
void TypeLowering::dump() const {
print(llvm::dbgs());
}