Merge pull request #1821 from gregomni/typealias
[SR-995] Handle name changes to ArrayLiteralConvertible associated type
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e5f2fc9..3016259 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,9 @@
Swift 3.0
-------
+* [SE-0043](https://github.com/apple/swift-evolution/blob/master/proposals/0043-declare-variables-in-case-labels-with-multiple-patterns.md)
+ landed, adding the ability to declare variables in multiple patterns in cases.
+
* Renamification landed, so the Clang importer imports ObjC symbols
substantially differently. *Someone should expand on this point.*
diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def
index 4ab7fe2..2e07908 100644
--- a/include/swift/AST/Attr.def
+++ b/include/swift/AST/Attr.def
@@ -252,6 +252,13 @@
DECL_ATTR(_cdecl, CDecl,
OnFunc | LongAttribute | UserInaccessible, 63)
+// A testing attribute for Library Evolution ("resilience").
+// FIXME: Replace with improved @available attribute.
+SIMPLE_DECL_ATTR(_versioned, Versioned,
+ OnFunc | OnVar | OnSubscript | OnConstructor |
+ OnStruct | OnEnum | OnClass | OnProtocol |
+ LongAttribute | UserInaccessible,
+ 64)
#undef TYPE_ATTR
#undef DECL_ATTR_ALIAS
diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h
index 2955afe..f6c427a 100644
--- a/include/swift/AST/Decl.h
+++ b/include/swift/AST/Decl.h
@@ -5810,7 +5810,7 @@
}
namespace impl {
- bool isTestingEnabled(const ValueDecl *VD);
+ bool isInternalDeclEffectivelyPublic(const ValueDecl *VD);
}
inline Accessibility ValueDecl::getEffectiveAccess() const {
@@ -5818,8 +5818,9 @@
case Accessibility::Public:
return Accessibility::Public;
case Accessibility::Internal:
- if (impl::isTestingEnabled(this))
+ if (impl::isInternalDeclEffectivelyPublic(this)) {
return Accessibility::Public;
+ }
return Accessibility::Internal;
case Accessibility::Private:
return Accessibility::Private;
diff --git a/include/swift/Basic/ClusteredBitVector.h b/include/swift/Basic/ClusteredBitVector.h
index a13c461..aee44b1 100644
--- a/include/swift/Basic/ClusteredBitVector.h
+++ b/include/swift/Basic/ClusteredBitVector.h
@@ -48,6 +48,7 @@
#include <cassert>
#include <climits>
#include <cstdlib>
+#include <type_traits>
namespace llvm {
class APInt;
@@ -58,7 +59,8 @@
/// A vector of bits. This data structure is optimized to store an
/// empty vector of any size without doing any allocation.
class ClusteredBitVector {
- using ChunkType = uint64_t; // must be unsigned
+ using ChunkType = uint64_t;
+ static_assert(std::is_unsigned<ChunkType>::value, "ChunkType must be unsigned");
enum {
ChunkSizeInBits = sizeof(ChunkType) * CHAR_BIT
};
diff --git a/include/swift/Basic/RelativePointer.h b/include/swift/Basic/RelativePointer.h
index 33681f5..8570d87 100644
--- a/include/swift/Basic/RelativePointer.h
+++ b/include/swift/Basic/RelativePointer.h
@@ -17,114 +17,6 @@
// unnecessary relocation at dynamic linking time. This header contains types
// to help dereference these relative addresses.
//
-// Theory of references to objects
-// -------------------------------
-//
-// A reference can be absolute or relative:
-//
-// - An absolute reference is a pointer to the object.
-//
-// - A relative reference is a (signed) offset from the address of the
-// reference to the address of its direct referent.
-//
-// A relative reference can be direct, indirect, or symbolic.
-//
-// In a direct reference, the direct referent is simply the target object.
-// Generally, a statically-emitted relative reference can only be direct
-// if it can be resolved to a constant offset by the linker, because loaders
-// do not support forming relative references. This means that either the
-// reference and object must lie within the same linkage unit or the
-// difference must be computed at runtime by code.
-//
-// In a symbolic reference, the direct referent is a string holding the symbol
-// name of the object. A relative reference can only be symbolic if the
-// object actually has a symbol at runtime, which may require exporting
-// many internal symbols that would otherwise be strippable.
-//
-// In an indirect reference, the direct referent is a variable holding an
-// absolute reference to the object. An indirect relative reference may
-// refer to an arbitrary symbol, be it anonymous within the linkage unit
-// or completely external to it, but it requires the introduction of an
-// intermediate absolute reference that requires load-time initialization.
-// However, this initialization can be shared among all indirect references
-// within the linkage unit, and the linker will generally place all such
-// references adjacent to one another to improve load-time locality.
-//
-// A reference can be made a dynamic union of more than one of these options.
-// This allows the compiler/linker to use a direct reference when possible
-// and a less-efficient option where required. However, it also requires
-// the cases to be dynamically distinguished. This can be done by setting
-// a low bit of the offset, as long as the difference between the direct
-// referent's address and the reference is a multiple of 2. This works well
-// for "indirectable" references because most objects are known to be
-// well-aligned, and the cases that aren't (chiefly functions and strings)
-// rarely need the flexibility of this kind of reference. It does not
-// work quite as well for "possibly symbolic" references because C strings
-// are not naturally aligned, and making them aligned generally requires
-// moving them out of the linker's ordinary string section; however, it's
-// still workable.
-//
-// Finally, a relative reference can be near or far. A near reference
-// is potentially smaller, but it requires the direct referent to lie
-// within a certain distance of the reference, even if dynamically
-// initialized.
-//
-// In Swift, we always prefer to use a near direct relative reference
-// when it is possible to do so: that is, when the relationship is always
-// between two global objects emitted in the same linkage unit, and there
-// is no compatibility constraint requiring the use of an absolute reference.
-//
-// When more flexibility is required, there are several options:
-//
-// 1. Use an absolute reference. Size penalty on 64-bit. Requires
-// load-time work.
-//
-// 2. Use a far direct relative reference. Size penalty on 64-bit.
-// Requires load-time work when object is outside linkage unit.
-// Generally not directly supported by loaders.
-//
-// 3. Use an always-indirect relative reference. Size penalty of one
-// pointer (shared). Requires load-time work even when object is
-// within linkage unit.
-//
-// 4. Use a near indirectable relative reference. Size penalty of one
-// pointer (shared) when reference exceeds range. Runtime / code-size
-// penalty on access. Requires load-time work (shared) only when
-// object is outside linkage unit.
-//
-// 5. Use a far indirectable relative reference. Size penalty on 64-bit.
-// Size penalty of one pointer (shared) when reference exceeds range
-// and is initialized statically. Runtime / code-size penalty on access.
-// Requires load-time work (shared) only when object is outside linkage
-// unit.
-//
-// 6. Use a near or far symbolic relative reference. No load-time work.
-// Severe runtime penalty on access. Requires custom logic to statically
-// optimize. Requires emission of symbol for target even if private
-// to linkage unit.
-//
-// 7. Use a near or far direct-or-symbolic relative reference. No
-// load-time work. Severe runtime penalty on access if object is
-// outside of linkage unit. Requires custom logic to statically optimize.
-//
-// In general, it's our preference in Swift to use option #4 when there
-// is no possibility of initializing the reference dynamically and option #5
-// when there is. This is because it is infeasible to actually share the
-// memory for the intermediate absolute reference when it must be allocated
-// dynamically.
-//
-// Symbolic references are an interesting idea that we have not yet made
-// use of. They may be acceptable in reflective metadata cases where it
-// is desireable to heavily bias towards never using the metadata. However,
-// they're only profitable if there wasn't any other indirect reference
-// to the target, and it is likely that their optimal use requires a more
-// intelligent toolchain from top to bottom.
-//
-// Note that the cost of load-time work also includes a binary-size penalty
-// to store the loader metadata necessary to perform that work. Therefore
-// it is better to avoid it even when there are dynamic optimizations in
-// place to skip the work itself.
-//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_BASIC_RELATIVEPOINTER_H
@@ -387,8 +279,7 @@
/// A direct relative reference to an aligned object, with an additional
/// tiny integer value crammed into its low bits.
-template<typename PointeeTy, typename IntTy, bool Nullable = false,
- typename Offset = int32_t>
+template<typename PointeeTy, typename IntTy, typename Offset = int32_t>
class RelativeDirectPointerIntPair {
Offset RelativeOffsetPlusInt;
@@ -414,14 +305,9 @@
using PointerTy = PointeeTy*;
PointerTy getPointer() const & {
- Offset offset = (RelativeOffsetPlusInt & ~getMask());
-
- // Check for null.
- if (Nullable && offset == 0)
- return nullptr;
-
// The value is addressed relative to `this`.
- uintptr_t absolute = detail::applyRelativeOffset(this, offset);
+ uintptr_t absolute = detail::applyRelativeOffset(this,
+ RelativeOffsetPlusInt & ~getMask());
return reinterpret_cast<PointerTy>(absolute);
}
diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h
index c4b5cb2..09713ac 100644
--- a/include/swift/Runtime/Metadata.h
+++ b/include/swift/Runtime/Metadata.h
@@ -34,6 +34,31 @@
namespace swift {
+/// A bump pointer for metadata allocations. Since metadata is (currently)
+/// never released, it does not support deallocation. This allocator by itself
+/// is not thread-safe; in concurrent uses, allocations must be guarded by
+/// a lock, such as the per-metadata-cache lock used to guard metadata
+/// instantiations. All allocations are pointer-aligned.
+class MetadataAllocator {
+ /// Address of the next available space. The allocator grabs a page at a time,
+ /// so the need for a new page can be determined by page alignment.
+ ///
+ /// Initializing to -1 instead of nullptr ensures that the first allocation
+ /// triggers a page allocation since it will always span a "page" boundary.
+ char *next = (char*)(~(uintptr_t)0U);
+
+public:
+ MetadataAllocator() = default;
+
+ // Don't copy or move, please.
+ MetadataAllocator(const MetadataAllocator &) = delete;
+ MetadataAllocator(MetadataAllocator &&) = delete;
+ MetadataAllocator &operator=(const MetadataAllocator &) = delete;
+ MetadataAllocator &operator=(MetadataAllocator &&) = delete;
+
+ void *alloc(size_t size);
+};
+
template <unsigned PointerSize>
struct RuntimeTarget;
@@ -65,10 +90,6 @@
template <typename T, bool Nullable = false>
using FarRelativeDirectPointer = FarRelativeDirectPointer<T, Nullable>;
-
- template <typename T, bool Nullable = false>
- using FarRelativeIndirectablePointer =
- FarRelativeIndirectablePointer<T, Nullable>;
template <typename T, bool Nullable = true>
using RelativeDirectPointer = RelativeDirectPointer<T, Nullable>;
@@ -97,9 +118,6 @@
template <typename T, bool Nullable = false>
using FarRelativeDirectPointer = StoredPointer;
-
- template <typename T, bool Nullable = false>
- using FarRelativeIndirectablePointer = StoredSize;
template <typename T, bool Nullable = true>
using RelativeDirectPointer = int32_t;
@@ -127,10 +145,6 @@
using TargetRelativeDirectPointer
= typename Runtime::template RelativeDirectPointer<Pointee, Nullable>;
-template <typename Runtime, typename Pointee, bool Nullable = true>
-using TargetFarRelativeIndirectablePointer
- = typename Runtime::template FarRelativeIndirectablePointer<Pointee,Nullable>;
-
struct HeapObject;
template <typename Runtime> struct TargetMetadata;
@@ -1466,22 +1480,9 @@
};
RelativeDirectPointerIntPair<TargetGenericMetadata<Runtime>,
- NominalTypeKind, /*Nullable*/ true>
+ NominalTypeKind>
GenericMetadataPatternAndKind;
- using NonGenericMetadataAccessFunction = const Metadata *();
-
- /// A pointer to the metadata access function for this type.
- ///
- /// The type of the returned function is speculative; in reality, it
- /// takes one argument for each of the generic requirements, in the order
- /// they are listed. Therefore, the function type is correct only if
- /// this type is non-generic.
- ///
- /// Not all type metadata have access functions.
- TargetRelativeDirectPointer<Runtime, NonGenericMetadataAccessFunction,
- /*nullable*/ true> AccessFunction;
-
/// A pointer to the generic metadata pattern that is used to instantiate
/// instances of this type. Zero if the type is not generic.
TargetGenericMetadata<Runtime> *getGenericMetadataPattern() const {
@@ -1489,10 +1490,6 @@
GenericMetadataPatternAndKind.getPointer());
}
- NonGenericMetadataAccessFunction *getAccessFunction() const {
- return AccessFunction.get();
- }
-
NominalTypeKind getKind() const {
return GenericMetadataPatternAndKind.getInt();
}
@@ -1931,9 +1928,9 @@
Description;
/// The parent type of this member type, or null if this is not a
- /// member type. It's acceptable to make this a direct pointer because
- /// parent types are relatively uncommon.
- TargetPointer<Runtime, const TargetMetadata<Runtime>> Parent;
+ /// member type.
+ FarRelativeIndirectablePointer<const TargetMetadata<Runtime>,
+ /*nullable*/ true> Parent;
static bool classof(const TargetMetadata<Runtime> *metadata) {
return metadata->getKind() == MetadataKind::Struct
@@ -2781,6 +2778,12 @@
using ProtocolConformanceRecord
= TargetProtocolConformanceRecord<InProcess>;
+/// \brief Fetch a uniqued metadata object for a nominal type with
+/// resilient layout.
+SWIFT_RUNTIME_EXPORT
+extern "C" const Metadata *
+swift_getResilientMetadata(GenericMetadata *pattern);
+
/// \brief Fetch a uniqued metadata object for a generic nominal type.
///
/// The basic algorithm for fetching a metadata object is:
@@ -3025,16 +3028,11 @@
/// Initialize the field offset vector for a dependent-layout class, using the
/// "Universal" layout strategy.
-///
-/// This will relocate the metadata if it doesn't have enough space
-/// for its superclass. Note that swift_allocateGenericClassMetadata will
-/// never produce a metadata that requires relocation.
SWIFT_RUNTIME_EXPORT
-extern "C" ClassMetadata *
-swift_initClassMetadata_UniversalStrategy(ClassMetadata *self,
- size_t numFields,
- const ClassFieldLayout *fieldLayouts,
- size_t *fieldOffsets);
+extern "C" void swift_initClassMetadata_UniversalStrategy(ClassMetadata *self,
+ size_t numFields,
+ const ClassFieldLayout *fieldLayouts,
+ size_t *fieldOffsets);
/// \brief Fetch a uniqued metadata for a metatype type.
SWIFT_RUNTIME_EXPORT
diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def
index a1bce1e..afb10f1 100644
--- a/include/swift/Runtime/RuntimeFunctions.def
+++ b/include/swift/Runtime/RuntimeFunctions.def
@@ -568,6 +568,12 @@
ARGS(TypeMetadataPtrTy),
ATTRS(NoUnwind, ReadNone)) // only writes to runtime-private fields
+// Metadata *swift_getResilientMetadata(GenericMetadata *pattern);
+FUNCTION(GetResilientMetadata, swift_getResilientMetadata, DefaultCC,
+ RETURNS(TypeMetadataPtrTy),
+ ARGS(TypeMetadataPatternPtrTy),
+ ATTRS(NoUnwind, ReadOnly))
+
// Metadata *swift_getGenericMetadata(GenericMetadata *pattern,
// const void *arguments);
FUNCTION(GetGenericMetadata, swift_getGenericMetadata, RegisterPreservingCC,
@@ -658,13 +664,13 @@
ATTRS(NoUnwind, ReadOnly))
// struct FieldInfo { size_t Size; size_t AlignMask; };
-// Metadata *swift_initClassMetadata_UniversalStrategy(Metadata *self,
-// size_t numFields,
-// const FieldInfo *fields,
-// size_t *fieldOffsets);
+// void swift_initClassMetadata_UniversalStrategy(Metadata *self,
+// size_t numFields,
+// const FieldInfo *fields,
+// size_t *fieldOffsets);
FUNCTION(InitClassMetadataUniversal,
swift_initClassMetadata_UniversalStrategy, DefaultCC,
- RETURNS(TypeMetadataPtrTy),
+ RETURNS(VoidTy),
ARGS(TypeMetadataPtrTy, SizeTy,
SizeTy->getPointerTo(),
SizeTy->getPointerTo()),
@@ -928,6 +934,10 @@
ARGS(TypeMetadataRecordPtrTy, TypeMetadataRecordPtrTy),
ATTRS(NoUnwind))
+FUNCTION(InitializeSuperclass, swift_initializeSuperclass, DefaultCC,
+ RETURNS(VoidTy),
+ ARGS(TypeMetadataPtrTy, Int1Ty),
+ ATTRS(NoUnwind))
FUNCTION(InstantiateObjCClass, swift_instantiateObjCClass, DefaultCC,
RETURNS(VoidTy),
ARGS(TypeMetadataPtrTy),
diff --git a/include/swift/SIL/SILDeclRef.h b/include/swift/SIL/SILDeclRef.h
index 5f352d3..c490b51 100644
--- a/include/swift/SIL/SILDeclRef.h
+++ b/include/swift/SIL/SILDeclRef.h
@@ -264,6 +264,8 @@
/// \brief True if the function should be treated as transparent.
bool isTransparent() const;
+ /// \brief True if the function should have its body serialized.
+ bool isFragile() const;
/// \brief True if the function has noinline attribute.
bool isNoinline() const;
/// \brief True if the function has __always inline attribute.
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index dceeda5..1133be5 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -43,8 +43,21 @@
using namespace swift;
-bool impl::isTestingEnabled(const ValueDecl *VD) {
- return VD->getModuleContext()->isTestingEnabled();
+bool impl::isInternalDeclEffectivelyPublic(const ValueDecl *VD) {
+ assert(VD->getFormalAccess() == Accessibility::Internal);
+
+ if (VD->getAttrs().hasAttribute<VersionedAttr>())
+ return true;
+
+ if (auto *fn = dyn_cast<FuncDecl>(VD))
+ if (auto *ASD = fn->getAccessorStorageDecl())
+ if (ASD->getAttrs().hasAttribute<VersionedAttr>())
+ return true;
+
+ if (VD->getModuleContext()->isTestingEnabled())
+ return true;
+
+ return false;
}
clang::SourceLocation ClangNode::getLocation() const {
diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index 5f1e819..1b9c4d4 100644
--- a/lib/ClangImporter/ImportDecl.cpp
+++ b/lib/ClangImporter/ImportDecl.cpp
@@ -517,6 +517,7 @@
auto body = BraceStmt::create(C, SourceLoc(), ASTNode(ret), SourceLoc(),
/*implicit*/ true);
getterDecl->setBody(body);
+ getterDecl->getAttrs().add(new (C) TransparentAttr(/*implicit*/ true));
C.addExternalDecl(getterDecl);
}
@@ -551,6 +552,7 @@
auto body = BraceStmt::create(C, SourceLoc(), { initialize }, SourceLoc(),
/*implicit*/ true);
setterDecl->setBody(body);
+ setterDecl->getAttrs().add(new (C) TransparentAttr(/*implicit*/ true));
C.addExternalDecl(setterDecl);
}
diff --git a/lib/IRGen/ClassMetadataLayout.h b/lib/IRGen/ClassMetadataLayout.h
index f87f5d8..39a3347 100644
--- a/lib/IRGen/ClassMetadataLayout.h
+++ b/lib/IRGen/ClassMetadataLayout.h
@@ -95,7 +95,7 @@
// Add a reference to the parent class, if applicable.
if (theClass->getDeclContext()->isTypeContext()) {
- asImpl().addParentMetadataRef(theClass, type);
+ asImpl().addParentMetadataRef(theClass);
}
// Add space for the generic parameters, if applicable.
@@ -232,7 +232,7 @@
void addIVarDestroyer() { addPointer(); }
void addValueWitnessTable() { addPointer(); }
void addDestructorFunction() { addPointer(); }
- void addParentMetadataRef(ClassDecl *forClass, Type classType) {addPointer();}
+ void addParentMetadataRef(ClassDecl *forClass) { addPointer(); }
void addSuperClass() { addPointer(); }
void addClassFlags() { addInt32(); }
void addInstanceAddressPoint() { addInt32(); }
diff --git a/lib/IRGen/ConstantBuilder.h b/lib/IRGen/ConstantBuilder.h
index 2fbdb1b..c6ee1c2 100644
--- a/lib/IRGen/ConstantBuilder.h
+++ b/lib/IRGen/ConstantBuilder.h
@@ -72,48 +72,37 @@
relativeAddressBase = base;
}
- llvm::Constant *getRelativeAddressFromNextField(ConstantReference referent,
- llvm::IntegerType *addressTy) {
+ llvm::Constant *getRelativeAddressFromNextField(llvm::Constant *referent,
+ llvm::IntegerType *addressTy = nullptr) {
assert(relativeAddressBase && "no relative address base set");
+ if (!addressTy)
+ addressTy = IGM.RelativeAddressTy;
// Determine the address of the next field in the initializer.
llvm::Constant *fieldAddr =
- llvm::ConstantExpr::getPtrToInt(relativeAddressBase, IGM.IntPtrTy);
+ llvm::ConstantExpr::getPtrToInt(relativeAddressBase, IGM.SizeTy);
fieldAddr = llvm::ConstantExpr::getAdd(fieldAddr,
llvm::ConstantInt::get(IGM.SizeTy,
getNextOffset().getValue()));
- llvm::Constant *referentValue =
- llvm::ConstantExpr::getPtrToInt(referent.getValue(), IGM.IntPtrTy);
+ referent = llvm::ConstantExpr::getPtrToInt(referent, IGM.SizeTy);
llvm::Constant *relative
- = llvm::ConstantExpr::getSub(referentValue, fieldAddr);
-
+ = llvm::ConstantExpr::getSub(referent, fieldAddr);
+
if (relative->getType() != addressTy)
relative = llvm::ConstantExpr::getTrunc(relative, addressTy);
-
- if (referent.isIndirect()) {
- relative = llvm::ConstantExpr::getAdd(relative,
- llvm::ConstantInt::get(addressTy, 1));
- }
-
return relative;
}
/// Add a 32-bit relative address from the current location in the local
/// being built to another global variable.
void addRelativeAddress(llvm::Constant *referent) {
- addRelativeAddress({referent, ConstantReference::Direct});
- }
- void addRelativeAddress(ConstantReference referent) {
- addInt32(getRelativeAddressFromNextField(referent, IGM.RelativeAddressTy));
+ addInt32(getRelativeAddressFromNextField(referent));
}
/// Add a pointer-sized relative address from the current location in the
/// local being built to another global variable.
void addFarRelativeAddress(llvm::Constant *referent) {
- addFarRelativeAddress({referent, ConstantReference::Direct});
- }
- void addFarRelativeAddress(ConstantReference referent) {
addWord(getRelativeAddressFromNextField(referent,
IGM.FarRelativeAddressTy));
}
@@ -122,9 +111,6 @@
/// being built to another global variable, or null if a null referent
/// is passed.
void addRelativeAddressOrNull(llvm::Constant *referent) {
- addRelativeAddressOrNull({referent, ConstantReference::Direct});
- }
- void addRelativeAddressOrNull(ConstantReference referent) {
if (referent)
addRelativeAddress(referent);
else
@@ -135,9 +121,6 @@
/// local being built to another global variable, or null if a null referent
/// is passed.
void addFarRelativeAddressOrNull(llvm::Constant *referent) {
- addFarRelativeAddressOrNull({referent, ConstantReference::Direct});
- }
- void addFarRelativeAddressOrNull(ConstantReference referent) {
if (referent)
addFarRelativeAddress(referent);
else
@@ -150,9 +133,7 @@
void addRelativeAddressWithTag(llvm::Constant *referent,
unsigned tag) {
assert(tag < 4 && "tag too big to pack in relative address");
- llvm::Constant *relativeAddr =
- getRelativeAddressFromNextField({referent, ConstantReference::Direct},
- IGM.RelativeAddressTy);
+ llvm::Constant *relativeAddr = getRelativeAddressFromNextField(referent);
relativeAddr = llvm::ConstantExpr::getAdd(relativeAddr,
llvm::ConstantInt::get(IGM.RelativeAddressTy, tag));
addInt32(relativeAddr);
diff --git a/lib/IRGen/GenCast.cpp b/lib/IRGen/GenCast.cpp
index 508e8de..a9b5e1f 100644
--- a/lib/IRGen/GenCast.cpp
+++ b/lib/IRGen/GenCast.cpp
@@ -104,9 +104,8 @@
// TODO: use ObjC class references
llvm::Value *targetMetadata;
if (allowConservative &&
- (targetMetadata =
- tryEmitConstantHeapMetadataRef(IGF.IGM, toType.getSwiftRValueType(),
- /*allowUninitialized*/ true))) {
+ (targetMetadata = tryEmitConstantTypeMetadataRef(IGF.IGM,
+ toType.getSwiftRValueType()))) {
// ok
} else {
targetMetadata
diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp
index 3fcc480..f147d36 100644
--- a/lib/IRGen/GenClass.cpp
+++ b/lib/IRGen/GenClass.cpp
@@ -168,15 +168,10 @@
unsigned NumInherited = 0;
- // Does the class metadata require dynamic initialization above and
- // beond what the runtime can automatically achieve?
- //
- // This is true if the class or any of its ancestors:
- // - is generic,
- // - is resilient,
- // - has a parent type which isn't emittable as a constant,
- // - or has a field with resilient layout.
- bool ClassMetadataRequiresDynamicInitialization = false;
+ // Does the class require a metadata template? This will be true if
+ // the class or any of its ancestors have generic parameters, or if
+ // any of the below conditions are false.
+ bool ClassHasMetadataPattern = false;
// Does the superclass have a fixed number of stored properties?
// If not, and the class has generally-dependent layout, we have to
@@ -222,8 +217,7 @@
fieldLayout.InheritedStoredProperties = inheritedStoredProps;
fieldLayout.AllFieldAccesses = IGM.Context.AllocateCopy(AllFieldAccesses);
fieldLayout.MetadataAccess = MetadataAccess;
- fieldLayout.MetadataRequiresDynamicInitialization =
- ClassMetadataRequiresDynamicInitialization;
+ fieldLayout.HasMetadataPattern = ClassHasMetadataPattern;
return fieldLayout;
}
@@ -231,17 +225,7 @@
void addFieldsForClass(ClassDecl *theClass,
SILType classType) {
if (theClass->isGenericContext())
- ClassMetadataRequiresDynamicInitialization = true;
-
- if (!ClassMetadataRequiresDynamicInitialization) {
- if (auto parentType =
- theClass->getDeclContext()->getDeclaredTypeInContext()) {
- if (!tryEmitConstantTypeMetadataRef(IGM,
- parentType->getCanonicalType(),
- SymbolReferenceKind::Absolute))
- ClassMetadataRequiresDynamicInitialization = true;
- }
- }
+ ClassHasMetadataPattern = true;
if (theClass->hasSuperclass()) {
// TODO: apply substitutions when computing base-class layouts!
@@ -263,7 +247,7 @@
} else if (IGM.isResilient(superclass, ResilienceExpansion::Maximal)) {
// If the superclass is resilient, the number of stored properties
// is not known at compile time.
- ClassMetadataRequiresDynamicInitialization = true;
+ ClassHasMetadataPattern = true;
ClassHasFixedFieldCount = false;
ClassHasFixedSize = false;
@@ -297,7 +281,7 @@
auto &eltType = IGM.getTypeInfo(type);
if (!eltType.isFixedSize()) {
- ClassMetadataRequiresDynamicInitialization = true;
+ ClassHasMetadataPattern = true;
ClassHasFixedSize = false;
if (type.hasArchetype())
@@ -855,19 +839,11 @@
}
}
- llvm::Constant *getMetaclassRefOrNull(ClassDecl *theClass) {
- if (theClass->isGenericContext()) {
- return llvm::ConstantPointerNull::get(IGM.ObjCClassPtrTy);
- } else {
- return IGM.getAddrOfMetaclassObject(theClass, NotForDefinition);
- }
- }
-
void buildMetaclassStub() {
assert(Layout && "can't build a metaclass from a category");
// The isa is the metaclass pointer for the root class.
auto rootClass = getRootClassForMetaclass(IGM, TheEntity.get<ClassDecl *>());
- auto rootPtr = getMetaclassRefOrNull(rootClass);
+ auto rootPtr = IGM.getAddrOfMetaclassObject(rootClass, NotForDefinition);
// The superclass of the metaclass is the metaclass of the
// superclass. Note that for metaclass stubs, we can always
@@ -878,10 +854,11 @@
llvm::Constant *superPtr;
if (getClass()->hasSuperclass()) {
auto base = getClass()->getSuperclass()->getClassOrBoundGenericClass();
- superPtr = getMetaclassRefOrNull(base);
+ superPtr = IGM.getAddrOfMetaclassObject(base, NotForDefinition);
} else {
- superPtr = getMetaclassRefOrNull(
- IGM.getObjCRuntimeBaseForSwiftRootClass(getClass()));
+ superPtr = IGM.getAddrOfMetaclassObject(
+ IGM.getObjCRuntimeBaseForSwiftRootClass(getClass()),
+ NotForDefinition);
}
auto dataPtr = emitROData(ForMetaClass);
@@ -927,8 +904,7 @@
fields.push_back(IGM.getAddrOfObjCClass(getClass(), NotForDefinition));
else {
auto type = getSelfType(getClass()).getSwiftRValueType();
- llvm::Constant *metadata =
- tryEmitConstantHeapMetadataRef(IGM, type, /*allowUninit*/ true);
+ llvm::Constant *metadata = tryEmitConstantTypeMetadataRef(IGM, type);
assert(metadata &&
"extended objc class doesn't have constant metadata?");
fields.push_back(metadata);
@@ -1847,12 +1823,10 @@
IGM.Context.Id_SwiftObject);
}
-bool irgen::doesClassMetadataRequireDynamicInitialization(IRGenModule &IGM,
- ClassDecl *theClass) {
- // Classes imported from Objective-C never requires dynamic initialization.
+bool irgen::getClassHasMetadataPattern(IRGenModule &IGM, ClassDecl *theClass) {
+ // Classes imported from Objective-C never have a metadata pattern.
if (theClass->hasClangNode())
return false;
- auto &layout = getSelfTypeInfo(IGM, theClass).getClassLayout(IGM);
- return layout.MetadataRequiresDynamicInitialization;
+ return getSelfTypeInfo(IGM, theClass).getClassLayout(IGM).HasMetadataPattern;
}
diff --git a/lib/IRGen/GenClass.h b/lib/IRGen/GenClass.h
index 41b1870..83645ee 100644
--- a/lib/IRGen/GenClass.h
+++ b/lib/IRGen/GenClass.h
@@ -112,11 +112,7 @@
ClassDecl *getRootClassForMetaclass(IRGenModule &IGM, ClassDecl *theClass);
- /// Does the class metadata for the given class require dynamic
- /// initialization beyond what can be achieved automatically by
- /// the runtime?
- bool doesClassMetadataRequireDynamicInitialization(IRGenModule &IGM,
- ClassDecl *theClass);
+ bool getClassHasMetadataPattern(IRGenModule &IGM, ClassDecl *theClass);
} // end namespace irgen
} // end namespace swift
diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp
index 15c06b6..e88ba83 100644
--- a/lib/IRGen/GenDecl.cpp
+++ b/lib/IRGen/GenDecl.cpp
@@ -105,8 +105,7 @@
class_addProtocol = IGM.getClassAddProtocolFn();
CanType origTy = ext->getDeclaredTypeOfContext()->getCanonicalType();
- classMetadata =
- tryEmitConstantHeapMetadataRef(IGM, origTy, /*allowUninit*/ true);
+ classMetadata = tryEmitConstantTypeMetadataRef(IGM, origTy);
assert(classMetadata &&
"extended objc class doesn't have constant metadata?!");
classMetadata = llvm::ConstantExpr::getBitCast(classMetadata,
@@ -1699,42 +1698,6 @@
}
}
-/// Return a reference to an object that's suitable for being used for
-/// the given kind of reference.
-///
-/// Note that, if the requested reference kind is a relative reference.
-/// the returned constant will not actually be a relative reference.
-/// To form the actual relative reference, you must pass the returned
-/// result to emitRelativeReference, passing the correct base-address
-/// information.
-ConstantReference
-IRGenModule::getAddrOfLLVMVariable(LinkEntity entity, Alignment alignment,
- llvm::Type *definitionType,
- llvm::Type *defaultType,
- DebugTypeInfo debugType,
- SymbolReferenceKind refKind) {
- switch (refKind) {
- case SymbolReferenceKind::Relative_Direct:
- case SymbolReferenceKind::Far_Relative_Direct:
- assert(definitionType == nullptr);
- // FIXME: don't just fall through; force the creation of a weak
- // definition so that we can emit a relative reference.
- SWIFT_FALLTHROUGH;
-
- case SymbolReferenceKind::Absolute:
- return { getAddrOfLLVMVariable(entity, alignment, definitionType,
- defaultType, debugType),
- ConstantReference::Direct };
-
-
- case SymbolReferenceKind::Relative_Indirectable:
- case SymbolReferenceKind::Far_Relative_Indirectable:
- assert(definitionType == nullptr);
- return getAddrOfLLVMVariableOrGOTEquivalent(entity, alignment, defaultType);
- }
- llvm_unreachable("bad reference kind");
-}
-
/// A convenient wrapper around getAddrOfLLVMVariable which uses the
/// default type as the definition type.
llvm::Constant *
@@ -1836,7 +1799,7 @@
/// Creates a private, unnamed constant containing the address of another
/// global variable. LLVM can replace relative references to this variable with
/// relative references to the GOT entry for the variable in the object file.
-ConstantReference
+std::pair<llvm::Constant *, IRGenModule::DirectOrGOT>
IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity,
Alignment alignment,
llvm::Type *defaultType) {
@@ -1880,12 +1843,12 @@
// aliasee to work around that.
if (auto alias = dyn_cast<llvm::GlobalAlias>(entry))
entry = alias->getAliasee();
- return {entry, ConstantReference::Direct};
+ return {entry, DirectOrGOT::Direct};
}
auto &gotEntry = GlobalGOTEquivalents[entity];
if (gotEntry) {
- return {gotEntry, ConstantReference::Indirect};
+ return {gotEntry, DirectOrGOT::GOT};
}
// Look up the global variable.
@@ -1896,7 +1859,35 @@
entity.mangle(name);
auto gotEquivalent = createGOTEquivalent(*this, global, name);
gotEntry = gotEquivalent;
- return {gotEquivalent, ConstantReference::Indirect};
+ return {gotEquivalent, DirectOrGOT::GOT};
+}
+
+/// If true, we lazily initialize metadata at runtime because the layout
+/// is only partially known. Otherwise, we can emit a direct reference a
+/// constant metadata symbol.
+bool
+IRGenModule::hasMetadataPattern(NominalTypeDecl *theDecl) {
+ assert(theDecl != nullptr);
+ // Protocols must be special-cased in a few places.
+ assert(!isa<ProtocolDecl>(theDecl));
+
+ // For classes, we already computed this when we did the layout.
+ // FIXME: Try not to call this for classes of other modules, by referencing
+ // the metadata accessor instead.
+ if (auto *theClass = dyn_cast<ClassDecl>(theDecl))
+ return irgen::getClassHasMetadataPattern(*this, theClass);
+
+ // Ok, we have a value type. If it is generic, it is always initialized
+ // at runtime.
+ if (theDecl->isGenericContext())
+ return true;
+
+ // If the type is not fixed-size, its size depends on resilient types,
+ // and the metadata is initialized at runtime.
+ if (!getTypeInfoForUnlowered(theDecl->getDeclaredType()).isFixedSize())
+ return true;
+
+ return false;
}
namespace {
@@ -1914,16 +1905,16 @@
llvm::Type *defaultTy, *defaultPtrTy;
auto nom = conformingType->getAnyNominal();
- auto clas = dyn_cast<ClassDecl>(nom);
- if (nom->isGenericContext() ||
- (clas && doesClassMetadataRequireDynamicInitialization(IGM, clas))) {
- // Conformances for generics and concrete subclasses of generics
- // are represented by referencing the nominal type descriptor.
+ if (IGM.hasMetadataPattern(nom)) {
+ // Conformances for generics, concrete subclasses of generics, and
+ // resiliently-sized types are represented by referencing the
+ // nominal type descriptor.
typeKind = TypeMetadataRecordKind::UniqueNominalTypeDescriptor;
entity = LinkEntity::forNominalTypeDescriptor(nom);
defaultTy = IGM.NominalTypeDescriptorTy;
defaultPtrTy = IGM.NominalTypeDescriptorPtrTy;
- } else if (clas) {
+ } else if (auto ct = dyn_cast<ClassType>(conformingType)) {
+ auto clas = ct->getDecl();
if (clas->isForeign()) {
typeKind = TypeMetadataRecordKind::NonuniqueDirectType;
entity = LinkEntity::forForeignTypeMetadataCandidate(conformingType);
@@ -1972,16 +1963,17 @@
/// Form an LLVM constant for the relative distance between a reference
/// (appearing at gep (0, indices) of `base`) and `target`.
llvm::Constant *
-IRGenModule::emitRelativeReference(ConstantReference target,
+IRGenModule::emitRelativeReference(std::pair<llvm::Constant *,
+ IRGenModule::DirectOrGOT> target,
llvm::Constant *base,
ArrayRef<unsigned> baseIndices) {
llvm::Constant *relativeAddr =
- emitDirectRelativeReference(target.getValue(), base, baseIndices);
+ emitDirectRelativeReference(target.first, base, baseIndices);
- // If the reference is indirect, flag it by setting the low bit.
+ // If the reference is to a GOT entry, flag it by setting the low bit.
// (All of the base, direct target, and GOT entry need to be pointer-aligned
// for this to be OK.)
- if (target.isIndirect()) {
+ if (target.second == IRGenModule::DirectOrGOT::GOT) {
relativeAddr = llvm::ConstantExpr::getAdd(relativeAddr,
llvm::ConstantInt::get(RelativeAddressTy, 1));
}
@@ -2076,9 +2068,10 @@
// TODO: Produce a relative reference to a private generator function
// if the witness table requires lazy initialization, instantiation, or
// conditional conformance checking.
+ std::pair<llvm::Constant*, DirectOrGOT> witnessTableRef;
auto witnessTableVar = getAddrOfWitnessTable(conformance);
- auto witnessTableRef =
- ConstantReference(witnessTableVar, ConstantReference::Direct);
+ witnessTableRef = std::make_pair(witnessTableVar,
+ DirectOrGOT::Direct);
auto typeRef = getAddrOfLLVMVariableOrGOTEquivalent(
typeEntity.entity, getPointerAlignment(), typeEntity.defaultTy);
@@ -2421,13 +2414,6 @@
/// for a type metadata and it will have type TypeMetadataPtrTy.
llvm::Constant *IRGenModule::getAddrOfTypeMetadata(CanType concreteType,
bool isPattern) {
- return getAddrOfTypeMetadata(concreteType, isPattern,
- SymbolReferenceKind::Absolute).getDirectValue();
-}
-
-ConstantReference IRGenModule::getAddrOfTypeMetadata(CanType concreteType,
- bool isPattern,
- SymbolReferenceKind refKind) {
assert(isPattern || !isa<UnboundGenericType>(concreteType));
llvm::Type *defaultVarTy;
@@ -2495,13 +2481,13 @@
0, 1, nullptr);
auto addr = getAddrOfLLVMVariable(entity, alignment,
- nullptr, defaultVarTy, DbgTy, refKind);
+ nullptr, defaultVarTy, DbgTy);
// FIXME: MC breaks when emitting alias references on some platforms
// (rdar://problem/22450593 ). Work around this by referring to the aliasee
// instead.
- if (auto alias = dyn_cast<llvm::GlobalAlias>(addr.getValue()))
- addr = ConstantReference(alias->getAliasee(), addr.isIndirect());
+ if (auto alias = dyn_cast<llvm::GlobalAlias>(addr))
+ addr = alias->getAliasee();
// Adjust if necessary.
if (adjustmentIndex) {
@@ -2509,10 +2495,8 @@
llvm::ConstantInt::get(Int32Ty, 0),
llvm::ConstantInt::get(Int32Ty, adjustmentIndex)
};
- addr = ConstantReference(
- llvm::ConstantExpr::getInBoundsGetElementPtr(
- /*Ty=*/nullptr, addr.getValue(), indices),
- addr.isIndirect());
+ addr = llvm::ConstantExpr::getInBoundsGetElementPtr(
+ /*Ty=*/nullptr, addr, indices);
}
return addr;
diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp
index 1fdc0a0..1921b02 100644
--- a/lib/IRGen/GenMeta.cpp
+++ b/lib/IRGen/GenMeta.cpp
@@ -61,47 +61,12 @@
static llvm::Value *emitLoadOfObjCHeapMetadataRef(IRGenFunction &IGF,
llvm::Value *object);
-static Address emitAddressOfMetadataSlotAtIndex(IRGenFunction &IGF,
- llvm::Value *metadata,
- int index,
- llvm::Type *objectTy) {
- // Require the metadata to be some type that we recognize as a
- // metadata pointer.
- assert(metadata->getType() == IGF.IGM.TypeMetadataPtrTy);
-
- // We require objectType to be a pointer type so that the GEP will
- // scale by the right amount. We could load an arbitrary type using
- // some extra bitcasting.
- assert(IGF.IGM.DataLayout.getTypeStoreSize(objectTy) ==
- IGF.IGM.DataLayout.getTypeStoreSize(IGF.IGM.SizeTy));
-
- // Cast to T*.
- auto objectPtrTy = objectTy->getPointerTo();
- auto metadataWords = IGF.Builder.CreateBitCast(metadata, objectPtrTy);
-
- auto indexV = llvm::ConstantInt::getSigned(IGF.IGM.SizeTy, index);
-
- // GEP to the slot.
- Address slot(IGF.Builder.CreateInBoundsGEP(metadataWords, indexV),
- IGF.IGM.getPointerAlignment());
-
- return slot;
-}
-
-/// Emit a load from the given metadata at a constant index.
-static llvm::LoadInst *emitLoadFromMetadataAtIndex(IRGenFunction &IGF,
- llvm::Value *metadata,
- int index,
- llvm::Type *objectTy,
- const llvm::Twine &suffix = "") {
- Address slot =
- emitAddressOfMetadataSlotAtIndex(IGF, metadata, index, objectTy);
-
- // Load.
- return IGF.Builder.CreateLoad(slot, metadata->getName() + suffix);
-}
-
-static int getClassParentIndex(IRGenModule &IGM, ClassDecl *classDecl);
+static llvm::LoadInst *
+emitLoadFromMetadataAtIndex(IRGenFunction &IGF,
+ llvm::Value *metadata,
+ int index,
+ llvm::Type *objectTy,
+ const llvm::Twine &suffix = "");
/// Produce a constant to place in a metatype's isa field
/// corresponding to the given metadata kind.
@@ -242,45 +207,22 @@
}
/// Attempts to return a constant heap metadata reference for a
-/// class type. This is generally only valid for specific kinds of
-/// ObjC reference, like superclasses or category references.
-llvm::Constant *irgen::tryEmitConstantHeapMetadataRef(IRGenModule &IGM,
- CanType type,
- bool allowDynamicUninitialized) {
- auto theDecl = type->getClassOrBoundGenericClass();
- assert(theDecl && "emitting constant heap metadata ref for non-class type?");
+/// nominal type.
+llvm::Constant *irgen::tryEmitConstantTypeMetadataRef(IRGenModule &IGM,
+ CanType type) {
+ auto theDecl = type->getAnyNominal();
+ assert(theDecl && "emitting constant metadata ref for non-nominal type?");
- // If the class must not require dynamic initialization --- e.g. if it
- // is a super reference --- then respect everything that might impose that.
- if (!allowDynamicUninitialized) {
- if (doesClassMetadataRequireDynamicInitialization(IGM, theDecl))
- return nullptr;
-
- // Otherwise, just respect genericity.
- } else if (theDecl->isGenericContext()) {
+ if (IGM.hasMetadataPattern(theDecl))
return nullptr;
- }
- // For imported classes, use the ObjC class symbol.
- // This incidentally cannot coincide with most of the awkward cases, like
- // having parent metadata.
- if (!hasKnownSwiftMetadata(IGM, theDecl))
- return IGM.getAddrOfObjCClass(theDecl, NotForDefinition);
+ if (auto theClass = type->getClassOrBoundGenericClass())
+ if (!hasKnownSwiftMetadata(IGM, theClass))
+ return IGM.getAddrOfObjCClass(theClass, NotForDefinition);
return IGM.getAddrOfTypeMetadata(type, false);
}
-/// Attempts to return a constant type metadata reference for a
-/// nominal type.
-ConstantReference
-irgen::tryEmitConstantTypeMetadataRef(IRGenModule &IGM, CanType type,
- SymbolReferenceKind refKind) {
- if (!isTypeMetadataAccessTrivial(IGM, type))
- return ConstantReference();
-
- return IGM.getAddrOfTypeMetadata(type, false, refKind);
-}
-
/// Emit a reference to an ObjC class. In general, the only things
/// you're allowed to do with the address of an ObjC class symbol are
/// (1) send ObjC messages to it (in which case the message will be
@@ -415,19 +357,13 @@
// Value type metadata only requires dynamic initialization on first
// access if it contains a resilient type.
if (isa<StructType>(type) || isa<EnumType>(type)) {
- auto nominalType = cast<NominalType>(type);
- assert(!nominalType->getDecl()->isGenericContext() &&
+ assert(!type->getAnyNominal()->isGenericContext() &&
"shouldn't be called for a generic type");
// Imported type metadata always requires an accessor.
- if (nominalType->getDecl()->hasClangNode())
+ if (type->getAnyNominal()->hasClangNode())
return false;
- // Metadata with a non-trivial parent node always requires an accessor.
- if (auto parent = nominalType.getParent())
- if (!isTypeMetadataAccessTrivial(IGM, parent))
- return false;
-
// Resiliently-sized metadata access always requires an accessor.
return (IGM.getTypeInfoForLowered(type).isFixedSize());
}
@@ -453,27 +389,6 @@
return false;
}
-static bool hasRequiredTypeMetadataAccessFunction(IRGenModule &IGM,
- NominalTypeDecl *typeDecl) {
- // This needs to be kept in sync with getTypeMetadataStrategy.
-
- if (isa<ProtocolDecl>(typeDecl))
- return false;
-
- switch (getDeclLinkage(typeDecl)) {
- case FormalLinkage::PublicUnique:
- case FormalLinkage::HiddenUnique:
- case FormalLinkage::Private:
- return true;
-
- case FormalLinkage::PublicNonUnique:
- case FormalLinkage::HiddenNonUnique:
- return false;
- }
- llvm_unreachable("bad formal linkage");
-
-}
-
/// Return the standard access strategy for getting a non-dependent
/// type metadata object.
MetadataAccessStrategy
@@ -487,8 +402,6 @@
// Note that while protocol types don't have a metadata pattern,
// we still require an accessor since we actually want to get
// the metadata for the existential type.
- //
- // This needs to kept in sync with hasRequiredTypeMetadataAccessPattern.
auto nominal = type->getAnyNominal();
if (nominal && !isa<ProtocolDecl>(nominal)) {
// Metadata accessors for fully-substituted generic types are
@@ -1013,13 +926,6 @@
return IGF.Builder.CreateConstArrayGEP(addr, index, IGF.IGM.getPointerSize());
}
-static bool isLoadFrom(llvm::Value *value, Address address) {
- if (auto load = dyn_cast<llvm::LoadInst>(value)) {
- return load->getOperand(0) == address.getAddress();
- }
- return false;
-}
-
/// Emit the body of a lazy cache accessor.
///
/// If cacheVariable is null, we perform the direct access every time.
@@ -1088,19 +994,10 @@
IGF.Builder.emitBlock(isNullBB);
llvm::Value *directResult = getValue(IGF);
- // Store it back to the cache variable. This needs to be a store-release
- // because it needs to propagate memory visibility to the other threads
- // that can access the cache: the initializing stores might be visible
- // to this thread, but they aren't transitively guaranteed to be visible
- // to other threads unless this is a store-release.
- //
- // However, we can skip this if the value was actually loaded from the
- // cache. This is a simple, if hacky, peephole that's useful for the
- // code in emitInPlaceTypeMetadataAccessFunctionBody.
- if (!isLoadFrom(directResult, cache)) {
- IGF.Builder.CreateStore(directResult, cache)
- ->setAtomic(llvm::Release);
- }
+ // Store it back to the cache variable. The direct metadata lookup is
+ // required to have already dependency-ordered any initialization
+ // it triggered before loads from the pointer it returned.
+ IGF.Builder.CreateStore(directResult, cache);
IGF.Builder.CreateBr(contBB);
auto storeBB = IGF.Builder.GetInsertBlock();
@@ -1159,165 +1056,79 @@
}
-using InPlaceMetadataInitializer =
- llvm::function_ref<llvm::Value*(IRGenFunction &IGF, llvm::Value *metadata)>;
-
-/// Emit a helper function for swift_once that performs in-place
-/// initialization of the given nominal type.
-static llvm::Constant *
-createInPlaceMetadataInitializationFunction(IRGenModule &IGM,
- CanNominalType type,
- llvm::Constant *metadata,
- llvm::Constant *cacheVariable,
- InPlaceMetadataInitializer &&initialize) {
- // There's an ignored i8* parameter.
- auto fnTy = llvm::FunctionType::get(IGM.VoidTy, {IGM.Int8PtrTy},
- /*variadic*/ false);
- llvm::Function *fn = llvm::Function::Create(fnTy,
- llvm::GlobalValue::PrivateLinkage,
- Twine("initialize_metadata_")
- + type->getDecl()->getName().str(),
- &IGM.Module);
- fn->setAttributes(IGM.constructInitialAttributes());
-
- // Set up the function.
- IRGenFunction IGF(IGM, fn);
- if (IGM.DebugInfo)
- IGM.DebugInfo->emitArtificialFunction(IGF, fn);
-
- // Emit the initialization.
- llvm::Value *relocatedMetadata = initialize(IGF, metadata);
-
- // Store back to the cache variable.
- IGF.Builder.CreateStore(relocatedMetadata,
- Address(cacheVariable, IGM.getPointerAlignment()))
- ->setAtomic(llvm::Release);
-
- IGF.Builder.CreateRetVoid();
- return fn;
-}
-
-/// Emit the function body for the type metadata accessor of a nominal type
-/// that might require in-place initialization.
-static llvm::Value *
-emitInPlaceTypeMetadataAccessFunctionBody(IRGenFunction &IGF,
- CanNominalType type,
- llvm::Constant *cacheVariable,
- InPlaceMetadataInitializer &&initializer) {
- llvm::Constant *metadata = IGF.IGM.getAddrOfTypeMetadata(type, false);
-
- // We might not have interesting initialization to do.
- assert((cacheVariable == nullptr) ==
- isTypeMetadataAccessTrivial(IGF.IGM, type));
- if (!cacheVariable)
- return metadata;
-
- // Okay, we have non-trivial initialization to do.
- // Ensure that we don't have multiple threads racing to do this.
- llvm::GlobalVariable *onceGuard =
- new llvm::GlobalVariable(IGF.IGM.Module, IGF.IGM.OnceTy, /*constant*/ false,
- llvm::GlobalValue::PrivateLinkage,
- llvm::Constant::getNullValue(IGF.IGM.OnceTy),
- Twine(IGF.CurFn->getName()) + ".once_token");
-
- // There's no point in performing the fast-path token check here
- // because we've already checked the cache variable. We're just using
- // swift_once to guarantee thread safety.
- assert(cacheVariable && "lazy initialization but no cache variable");
-
- // Create the protected function. swift_once wants this as an i8*.
- llvm::Value *onceFn =
- createInPlaceMetadataInitializationFunction(IGF.IGM, type, metadata,
- cacheVariable,
- std::move(initializer));
- onceFn = IGF.Builder.CreateBitCast(onceFn, IGF.IGM.Int8PtrTy);
-
- auto onceCall = IGF.Builder.CreateCall(IGF.IGM.getOnceFn(),
- {onceGuard, onceFn});
- onceCall->setCallingConv(IGF.IGM.DefaultCC);
-
- // We can just load the cache now.
- // TODO: this should be consume-ordered when LLVM supports it.
- Address cacheAddr = Address(cacheVariable, IGF.IGM.getPointerAlignment());
- llvm::Value *relocatedMetadata = IGF.Builder.CreateLoad(cacheAddr);
-
- // emitLazyCacheAccessFunction will see that the value was loaded from
- // the guard variable and skip the redundant store back.
- return relocatedMetadata;
-}
-
/// Emit the body of a metadata accessor function for the given type.
-///
-/// This function is appropriate for ordinary situations where the
-/// construction of the metadata value just involves calling idempotent
-/// metadata-construction functions. It is not used for the in-place
-/// initialization of non-generic nominal type metadata.
-static llvm::Value *emitTypeMetadataAccessFunctionBody(IRGenFunction &IGF,
- CanType type) {
- assert(!type->hasArchetype() &&
- "cannot emit metadata accessor for context-dependent type");
+static llvm::Value *emitMetadataAccessFunction(IRGenFunction &IGF,
+ CanType type) {
+ if (auto nominal = type->getAnyNominal()) {
+ if (nominal->isGenericContext()) {
+ // This is a metadata accessor for a fully substituted generic type.
+ assert(!type->hasArchetype() &&
+ "partially substituted types do not have accessors");
+ return emitDirectTypeMetadataRef(IGF, type);
+ }
- // We only take this path for That means
- // everything except non-generic nominal types.
- auto nominalType = dyn_cast<NominalType>(type);
- if (!nominalType)
- return emitDirectTypeMetadataRef(IGF, type);
+ // We should not be emitting metadata accessors for types unless
+ // we have full knowledge of their layout.
+ assert(!IGF.IGM.isResilient(nominal, ResilienceExpansion::Maximal));
- auto typeDecl = nominalType->getDecl();
- if (typeDecl->isGenericContext()) {
- // This is a metadata accessor for a fully substituted generic type.
- return emitDirectTypeMetadataRef(IGF, type);
- }
+ // We will still have a metadata pattern if the type is not generic,
+ // but contains resiliently-sized fields.
+ bool isPattern = IGF.IGM.hasMetadataPattern(nominal);
- // We should never be emitting a metadata accessor for resilient nominal
- // types outside of their defining module. We'd only do that anyway for
- // types that don't guarantee the existence of a non-unique access
- // function, and that should never be true of a resilient type with
- // external availability.
- //
- // (The type might still not have a statically-known layout. It just
- // can't be resilient at the top level: we have to know its immediate
- // members, or we can't even begin to approach the problem of emitting
- // metadata for it.)
- assert(!IGF.IGM.isResilient(typeDecl, ResilienceExpansion::Maximal));
+ // Non-native Swift classes need to be handled differently.
+ if (auto classDecl = dyn_cast<ClassDecl>(nominal)) {
+ // We emit a completely different pattern for foreign classes.
+ if (classDecl->isForeign()) {
+ return emitForeignTypeMetadataRef(IGF, type);
+ }
- // Non-native types are just wrapped in various ways.
- if (auto classDecl = dyn_cast<ClassDecl>(typeDecl)) {
- // We emit a completely different pattern for foreign classes.
- if (classDecl->isForeign()) {
+ // Classes that might not have Swift metadata use a different
+ // symbol name.
+ if (!hasKnownSwiftMetadata(IGF.IGM, classDecl)) {
+ assert(!classDecl->isGenericContext() &&
+ "ObjC class cannot be generic");
+ return emitObjCMetadataRef(IGF, classDecl);
+ }
+
+ // If this is a class with constant metadata, we still need to
+ // force ObjC initialization if we're doing Objective-C interop.
+ if (IGF.IGM.ObjCInterop && !isPattern) {
+ llvm::Value *metadata = IGF.IGM.getAddrOfTypeMetadata(type, false);
+ metadata = IGF.Builder.CreateBitCast(metadata, IGF.IGM.ObjCClassPtrTy);
+ metadata = IGF.Builder.CreateCall(IGF.IGM.getGetInitializedObjCClassFn(),
+ metadata);
+ return IGF.Builder.CreateBitCast(metadata, IGF.IGM.TypeMetadataPtrTy);
+ }
+
+ // Imported value types require foreign metadata uniquing too.
+ } else if (nominal->hasClangNode()) {
return emitForeignTypeMetadataRef(IGF, type);
}
- // Classes that might not have Swift metadata use a different
- // symbol name.
- if (!hasKnownSwiftMetadata(IGF.IGM, classDecl)) {
- assert(!classDecl->isGenericContext() &&
- "ObjC class cannot be generic");
- return emitObjCMetadataRef(IGF, classDecl);
+ // If we have a pattern but no generic substitutions, we're just
+ // doing resilient type layout.
+ if (isPattern) {
+ llvm::Constant *getter = IGF.IGM.getGetResilientMetadataFn();
+
+ llvm::Value *metadata = IGF.IGM.getAddrOfTypeMetadata(type, true);
+ auto result = IGF.Builder.CreateCall(getter, {metadata});
+ result->setDoesNotThrow();
+ result->addAttribute(llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::ReadNone);
+ return result;
}
- // Imported value types require foreign metadata uniquing.
- } else if (typeDecl->hasClangNode()) {
- return emitForeignTypeMetadataRef(IGF, type);
+ // Accessor is trivial, just return pointer to constant metadata.
+ return IGF.IGM.getAddrOfTypeMetadata(type, false);
}
- // Okay, everything else is built from a Swift metadata object.
- llvm::Constant *metadata = IGF.IGM.getAddrOfTypeMetadata(type, false);
-
- // We should not be doing more serious work along this path.
- assert(isTypeMetadataAccessTrivial(IGF.IGM, type));
-
- return metadata;
+ return emitDirectTypeMetadataRef(IGF, type);
}
-using MetadataAccessGenerator =
- llvm::function_ref<llvm::Value*(IRGenFunction &IGF, llvm::Constant *cache)>;
-
/// Get or create an accessor function to the given non-dependent type.
static llvm::Function *getTypeMetadataAccessFunction(IRGenModule &IGM,
- CanType type,
- ForDefinition_t shouldDefine,
- MetadataAccessGenerator &&generator) {
+ CanType type,
+ ForDefinition_t shouldDefine) {
assert(!type->hasArchetype());
assert(!isa<UnboundGenericType>(type));
@@ -1341,25 +1152,12 @@
emitLazyCacheAccessFunction(IGM, accessor, cacheVariable,
[&](IRGenFunction &IGF) -> llvm::Value* {
- return generator(IGF, cacheVariable);
+ return emitMetadataAccessFunction(IGF, type);
});
return accessor;
}
-/// Get or create an accessor function to the given non-dependent type.
-static llvm::Function *getTypeMetadataAccessFunction(IRGenModule &IGM,
- CanType type,
- ForDefinition_t shouldDefine) {
- return getTypeMetadataAccessFunction(IGM, type, shouldDefine,
- [&](IRGenFunction &IGF,
- llvm::Constant *cacheVariable) {
- // We should not be called with ForDefinition for nominal types
- // that require in-place initialization.
- return emitTypeMetadataAccessFunctionBody(IGF, type);
- });
-}
-
/// Get or create an accessor function to the given generic type.
static llvm::Function *getGenericTypeMetadataAccessFunction(IRGenModule &IGM,
NominalTypeDecl *nominal,
@@ -1386,33 +1184,17 @@
return accessor;
}
-/// Return the type metadata access function for the given type, if it
-/// is guaranteed to exist.
-static llvm::Constant *
-getRequiredTypeMetadataAccessFunction(IRGenModule &IGM,
- NominalTypeDecl *theDecl,
- ForDefinition_t shouldDefine) {
- if (!hasRequiredTypeMetadataAccessFunction(IGM, theDecl))
- return nullptr;
-
+/// Force a public metadata access function into existence if necessary
+/// for the given type.
+static void maybeEmitTypeMetadataAccessFunction(IRGenModule &IGM,
+ NominalTypeDecl *theDecl) {
if (theDecl->isGenericContext()) {
- return getGenericTypeMetadataAccessFunction(IGM, theDecl, shouldDefine);
+ (void) getGenericTypeMetadataAccessFunction(IGM, theDecl, ForDefinition);
+ return;
}
CanType declaredType = theDecl->getDeclaredType()->getCanonicalType();
- return getTypeMetadataAccessFunction(IGM, declaredType, shouldDefine);
-}
-
-/// Force a public metadata access function into existence if necessary
-/// for the given type.
-template <class BuilderTy>
-static void maybeEmitNominalTypeMetadataAccessFunction(IRGenModule &IGM,
- NominalTypeDecl *theDecl,
- BuilderTy &builder) {
- if (!hasRequiredTypeMetadataAccessFunction(IGM, theDecl))
- return;
-
- builder.createMetadataAccessFunction();
+ (void) getTypeMetadataAccessFunction(IGM, declaredType, ForDefinition);
}
/// Emit a call to the type metadata accessor for the given function.
@@ -2040,39 +1822,30 @@
asImpl().addName();
asImpl().addKindDependentFields();
asImpl().addGenericMetadataPatternAndKind();
- asImpl().addAccessFunction();
asImpl().addGenericParams();
}
- CanType getAbstractType() {
- return asImpl().getTarget()->getDeclaredType()->getCanonicalType();
- }
-
void addName() {
- addRelativeAddress(getMangledTypeName(IGM, getAbstractType(),
+ NominalTypeDecl *ntd = asImpl().getTarget();
+ addRelativeAddress(getMangledTypeName(IGM,
+ ntd->getDeclaredType()->getCanonicalType(),
/*willBeRelativelyAddressed*/ true));
}
void addGenericMetadataPatternAndKind() {
NominalTypeDecl *ntd = asImpl().getTarget();
auto kind = asImpl().getKind();
- if (!ntd->isGenericContext()) {
+ if (!IGM.hasMetadataPattern(ntd)) {
// There's no pattern to link.
addConstantInt32(kind);
return;
}
addRelativeAddressWithTag(
- IGM.getAddrOfTypeMetadata(getAbstractType(), /*pattern*/ true),
+ IGM.getAddrOfTypeMetadata(ntd->getDeclaredType()->getCanonicalType(),
+ /*pattern*/ true),
kind);
}
-
- void addAccessFunction() {
- NominalTypeDecl *typeDecl = asImpl().getTarget();
- llvm::Constant *accessFn =
- getRequiredTypeMetadataAccessFunction(IGM, typeDecl, NotForDefinition);
- addRelativeAddressOrNull(accessFn);
- }
void addGenericParams() {
NominalTypeDecl *ntd = asImpl().getTarget();
@@ -2657,7 +2430,7 @@
// If the type is not generic, we can use a global variable to cache the
// address of the field type vector for the single instance.
- if (!type->isGenericContext()) {
+ if (!type->getGenericParamsOfContext()) {
vectorPtr = new llvm::GlobalVariable(*IGM.getModule(),
metadataArrayPtrTy,
/*constant*/ false,
@@ -2746,10 +2519,6 @@
zero, builtVectorInt,
llvm::AtomicOrdering::SequentiallyConsistent,
llvm::AtomicOrdering::SequentiallyConsistent);
-
- // We might have added internal control flow above.
- buildBB = IGF.Builder.GetInsertBlock();
-
// The pointer in the slot should still have been null.
auto didStore = IGF.Builder.CreateExtractValue(raceVectorInt, 1);
raceVectorInt = IGF.Builder.CreateExtractValue(raceVectorInt, 0);
@@ -2792,7 +2561,6 @@
CanType Type;
Optional<ProtocolConformanceRef> Conformance;
Size ToOffset;
- bool IsRelative;
};
SmallVector<FillOp, 8> FillOps;
@@ -2807,7 +2575,6 @@
IRGenModule &IGM = super::IGM;
using super::asImpl;
- using super::Target;
/// Set to true if the metadata record for the generic type has fields
/// outside of the generic parameter vector.
@@ -2835,7 +2602,7 @@
llvm::Function *f = llvm::Function::Create(ty,
llvm::GlobalValue::PrivateLinkage,
llvm::Twine("create_generic_metadata_")
- + Target->getName().str(),
+ + super::Target->getName().str(),
&IGM.Module);
f->setAttributes(IGM.constructInitialAttributes());
@@ -2848,9 +2615,9 @@
llvm::Value *args = params.claimNext();
// Bind the generic arguments.
- if (Target->isGenericContext()) {
+ if (super::Target->isGenericContext()) {
Address argsArray(args, IGM.getPointerAlignment());
- emitPolymorphicParametersFromArray(IGF, Target, argsArray);
+ emitPolymorphicParametersFromArray(IGF, super::Target, argsArray);
}
// Allocate the metadata.
@@ -2869,22 +2636,10 @@
} else {
value = IGF.emitTypeMetadataRef(fillOp.Type);
}
-
+ value = IGF.Builder.CreateBitCast(value, IGM.Int8PtrTy);
auto dest = createPointerSizedGEP(IGF, metadataWords,
fillOp.ToOffset - AddressPoint);
-
- // A far relative indirectable pointer.
- if (fillOp.IsRelative) {
- dest = IGF.Builder.CreateElementBitCast(dest,
- IGM.FarRelativeAddressTy);
- IGF.emitStoreOfRelativeIndirectablePointer(value, dest,
- /*isFar*/ true);
-
- // A direct pointer.
- } else {
- value = IGF.Builder.CreateBitCast(value, IGM.Int8PtrTy);
- IGF.Builder.CreateStore(value, dest);
- }
+ IGF.Builder.CreateStore(value, dest);
}
// Initialize the instantiated dependent value witness table, if we have
@@ -2918,17 +2673,8 @@
return f;
}
-
- void addFillOp(CanType type, Optional<ProtocolConformanceRef> conf,
- bool isRelative) {
- FillOps.push_back({type, conf, getNextOffset(), isRelative });
- }
public:
- void createMetadataAccessFunction() {
- (void) getGenericTypeMetadataAccessFunction(IGM, Target, ForDefinition);
- }
-
void layout() {
TemplateHeaderSize =
((NumPrivateDataWords + 1) * IGM.getPointerSize()) + Size(8);
@@ -2971,7 +2717,7 @@
// TODO: ultimately, this should be the number of actual template
// arguments, not the number of witness tables required.
unsigned numGenericArguments =
- GenericArguments::getNumGenericArguments(IGM, Target);
+ GenericArguments::getNumGenericArguments(IGM, super::Target);
headerFields[Field++]
= llvm::ConstantInt::get(IGM.Int16Ty, numGenericArguments);
@@ -3001,7 +2747,7 @@
template <class... T>
void addGenericArgument(CanType type, T &&...args) {
NumGenericWitnesses++;
- addFillOp(type, None, /*relative*/ false);
+ FillOps.push_back({ type, None, getNextOffset() });
super::addGenericArgument(type, std::forward<T>(args)...);
}
@@ -3009,7 +2755,7 @@
void addGenericWitnessTable(CanType type, ProtocolConformanceRef conf,
T &&...args) {
NumGenericWitnesses++;
- addFillOp(type, conf, /*relative*/ false);
+ FillOps.push_back({ type, conf, getNextOffset() });
super::addGenericWitnessTable(type, conf, std::forward<T>(args)...);
}
@@ -3045,87 +2791,6 @@
// Classes
-static Address
-emitAddressOfFieldOffsetVectorInClassMetadata(IRGenFunction &IGF,
- ClassDecl *theClass,
- llvm::Value *metadata) {
- BEGIN_METADATA_SEARCHER_0(GetOffsetToFieldOffsetVector, Class)
- void noteStartOfFieldOffsets(ClassDecl *whichClass) {
- if (whichClass == Target)
- setTargetOffset();
- }
- END_METADATA_SEARCHER()
-
- auto offset =
- GetOffsetToFieldOffsetVector(IGF.IGM, theClass).getTargetOffset();
-
- Address addr(metadata, IGF.IGM.getPointerAlignment());
- addr = IGF.Builder.CreateBitCast(addr,
- IGF.IGM.SizeTy->getPointerTo());
- return createPointerSizedGEP(IGF, addr, offset);
-}
-
-static llvm::Value *emitInitializeFieldOffsetVector(IRGenFunction &IGF,
- ClassDecl *target,
- llvm::Value *metadata) {
- llvm::Value *fieldVector
- = emitAddressOfFieldOffsetVectorInClassMetadata(IGF, target, metadata)
- .getAddress();
-
- // Collect the stored properties of the type.
- llvm::SmallVector<VarDecl*, 4> storedProperties;
- for (auto prop : target->getStoredProperties()) {
- storedProperties.push_back(prop);
- }
-
- // Fill out an array with the field type metadata records.
- Address fields = IGF.createAlloca(
- llvm::ArrayType::get(IGF.IGM.SizeTy,
- storedProperties.size() * 2),
- IGF.IGM.getPointerAlignment(), "classFields");
- IGF.Builder.CreateLifetimeStart(fields,
- IGF.IGM.getPointerSize() * storedProperties.size() * 2);
-
- Address firstField;
- unsigned index = 0;
- for (auto prop : storedProperties) {
- auto propFormalTy = prop->getType()->getCanonicalType();
- SILType propLoweredTy = IGF.IGM.SILMod->Types.getLoweredType(propFormalTy);
- auto &propTI = IGF.getTypeInfo(propLoweredTy);
- auto sizeAndAlignMask
- = propTI.getSizeAndAlignmentMask(IGF, propLoweredTy);
-
- llvm::Value *size = sizeAndAlignMask.first;
- Address sizeAddr =
- IGF.Builder.CreateStructGEP(fields, index, IGF.IGM.getPointerSize());
- IGF.Builder.CreateStore(size, sizeAddr);
- if (index == 0) firstField = sizeAddr;
-
- llvm::Value *alignMask = sizeAndAlignMask.second;
- Address alignMaskAddr =
- IGF.Builder.CreateStructGEP(fields, index + 1,
- IGF.IGM.getPointerSize());
- IGF.Builder.CreateStore(alignMask, alignMaskAddr);
-
- index += 2;
- }
-
- if (storedProperties.empty()) {
- firstField = IGF.Builder.CreateStructGEP(fields, 0, Size(0));
- }
-
- // Ask the runtime to lay out the class. This can relocate it if it
- // wasn't allocated with swift_allocateGenericClassMetadata.
- auto numFields = IGF.IGM.getSize(Size(storedProperties.size()));
- metadata = IGF.Builder.CreateCall(IGF.IGM.getInitClassMetadataUniversalFn(),
- {metadata, numFields,
- firstField.getAddress(), fieldVector});
- IGF.Builder.CreateLifetimeEnd(fields,
- IGF.IGM.getPointerSize() * storedProperties.size() * 2);
-
- return metadata;
-}
-
namespace {
/// An adapter for laying out class metadata.
template <class Impl>
@@ -3136,8 +2801,8 @@
Optional<MetadataSize> ClassObjectExtents;
protected:
- using super::IGM;
- using super::Target;
+ IRGenModule &IGM = super::IGM;
+ ClassDecl * const& Target = super::Target;
using super::setRelativeAddressBase;
using super::addWord;
using super::addConstantWord;
@@ -3167,6 +2832,8 @@
ClassObjectExtents = getSizeOfMetadata(IGM, Target);
}
+ bool HasRuntimeParent = false;
+
public:
/// The 'metadata flags' field in a class is actually a pointer to
/// the metaclass object for the class.
@@ -3237,9 +2904,18 @@
}
}
- bool addReferenceToHeapMetadata(CanType type, bool allowUninitialized) {
+ void addParentMetadataRef(ClassDecl *forClass) {
+ // FIXME: this is wrong for multiple levels of generics; we need
+ // to apply substitutions through.
+ Type parentType =
+ forClass->getDeclContext()->getDeclaredTypeInContext();
+ if (!addReferenceToType(parentType->getCanonicalType()))
+ HasRuntimeParent = true;
+ }
+
+ bool addReferenceToType(CanType type) {
if (llvm::Constant *metadata
- = tryEmitConstantHeapMetadataRef(IGM, type, allowUninitialized)) {
+ = tryEmitConstantTypeMetadataRef(IGM, type)) {
addWord(metadata);
return true;
} else {
@@ -3428,104 +3104,10 @@
ClassDecl *forClass) {
addWord(llvm::Constant::getNullValue(IGM.WitnessTablePtrTy));
}
-
- protected:
- bool isFinishInitializationIdempotent() {
- if (!Layout.isFixedLayout())
- return false;
-
- if (doesClassMetadataRequireDynamicInitialization(IGM, Target))
- return false;
-
- return true;
- }
-
- llvm::Value *emitFinishIdempotentInitialization(IRGenFunction &IGF,
- llvm::Value *metadata) {
- if (IGF.IGM.ObjCInterop) {
- metadata =
- IGF.Builder.CreateBitCast(metadata, IGF.IGM.ObjCClassPtrTy);
- metadata =
- IGF.Builder.CreateCall(IGF.IGM.getGetInitializedObjCClassFn(),
- metadata);
- metadata =
- IGF.Builder.CreateBitCast(metadata, IGF.IGM.TypeMetadataPtrTy);
- }
- return metadata;
- }
-
- llvm::Value *emitFinishInitializationOfClassMetadata(IRGenFunction &IGF,
- llvm::Value *metadata) {
- // We assume that we've already filled in the class's generic arguments.
- // We need to:
- // - relocate the metadata to accomodate the superclass,
- // if something in our hierarchy is resilient to us;
- // - fill out the subclass's field offset vector, if its layout
- // wasn't fixed;
- // - copy field offsets and generic arguments from higher in the
- // class hierarchy, if
- // - copy the superclass data, if there are generic arguments
- // or field offset vectors there that weren't filled in;
- // - populate the field offset vector, if layout isn't fixed, and
- // - register the class with the ObjC runtime, if ObjC interop is
- // enabled.
- //
- // emitInitializeFieldOffsetVector will do everything in the full case.
- if (doesClassMetadataRequireDynamicInitialization(IGF.IGM, Target)) {
- metadata = emitInitializeFieldOffsetVector(IGF, Target, metadata);
-
- // TODO: do something intermediate when e.g. all we needed to do was
- // set parent metadata pointers.
-
- // Otherwise, all we need to do is register with the ObjC runtime.
- } else {
- metadata = emitFinishIdempotentInitialization(IGF, metadata);
- }
-
- // Realizing the class with the ObjC runtime will copy back to the
- // field offset globals for us; but if ObjC interop is disabled, we
- // have to do that ourselves, assuming we didn't just emit them all
- // correctly in the first place.
- if (!Layout.isFixedLayout() && !IGF.IGM.ObjCInterop)
- emitInitializeFieldOffsets(IGF, metadata);
-
- return metadata;
- }
-
- // The Objective-C runtime will copy field offsets from the field offset
- // vector into field offset globals for us, if present. If there's no
- // Objective-C runtime, we have to do this ourselves.
- void emitInitializeFieldOffsets(IRGenFunction &IGF,
- llvm::Value *metadata) {
- unsigned index = FieldLayout.InheritedStoredProperties.size();
-
- for (auto prop : Target->getStoredProperties()) {
- auto access = FieldLayout.AllFieldAccesses[index];
- if (access == FieldAccess::NonConstantDirect) {
- Address offsetA = IGF.IGM.getAddrOfFieldOffset(prop,
- /*indirect*/ false,
- ForDefinition);
-
- // We can't use emitClassFieldOffset() here because that creates
- // an invariant load, which could be hoisted above the point
- // where the metadata becomes fully initialized
- Size offset = getClassFieldOffset(IGF.IGM, Target, prop);
- int index = IGF.IGM.getOffsetInWords(offset);
- auto offsetVal = emitLoadFromMetadataAtIndex(IGF, metadata, index,
- IGF.IGM.SizeTy);
- IGF.Builder.CreateStore(offsetVal, offsetA);
- }
-
- index++;
- }
- }
};
class ClassMetadataBuilder :
public ClassMetadataBuilderBase<ClassMetadataBuilder> {
-
- bool HasUnfilledSuperclass = false;
- bool HasUnfilledParent = false;
public:
ClassMetadataBuilder(IRGenModule &IGM, ClassDecl *theClass,
const StructLayout &layout,
@@ -3533,6 +3115,13 @@
llvm::GlobalVariable *relativeAddressBase)
: ClassMetadataBuilderBase(IGM, theClass, layout, fieldLayout,
relativeAddressBase) {
+
+ assert(layout.isFixedLayout() &&
+ "non-fixed layout classes require a template");
+ // FIXME: Distinguish Objective-C sliding from resilient layout
+ assert((fieldLayout.MetadataAccess == FieldAccess::ConstantDirect ||
+ fieldLayout.MetadataAccess == FieldAccess::NonConstantDirect) &&
+ "resilient superclasses require a template");
}
llvm::Constant *getInit() {
@@ -3562,101 +3151,32 @@
= ArchetypeBuilder::mapTypeIntoContext(Target,
Target->getSuperclass());
- if (!addReferenceToHeapMetadata(superclassTy->getCanonicalType(),
- /*allowUninit*/ false)) {
- HasUnfilledSuperclass = true;
- }
- }
-
- void addParentMetadataRef(ClassDecl *forClass, Type classType) {
- CanType parentType = classType->getCanonicalType().getNominalParent();
-
- if (auto metadata =
- tryEmitConstantTypeMetadataRef(IGM, parentType,
- SymbolReferenceKind::Absolute)) {
- addWord(metadata.getValue());
- } else {
- // Leave a null pointer placeholder to be filled by in-place
- // initialization.
- addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy));
- if (forClass == Target)
- HasUnfilledParent = true;
- }
- }
-
- bool canBeConstant() {
- // TODO: the metadata global can actually be constant in a very
- // special case: it's not a pattern, ObjC interoperation isn't
- // required, there are no class fields, and there is nothing that
- // needs to be runtime-adjusted.
- return false;
- }
-
- void createMetadataAccessFunction() {
- assert(!Target->isGenericContext());
- auto type =cast<ClassType>(Target->getDeclaredType()->getCanonicalType());
-
- (void) getTypeMetadataAccessFunction(IGM, type, ForDefinition,
- [&](IRGenFunction &IGF, llvm::Constant *cacheVar) -> llvm::Value* {
- // There's an interesting special case where we can do the
- // initialization idempotently and thus avoid the need for a lock.
- if (!HasUnfilledSuperclass && !HasUnfilledParent &&
- isFinishInitializationIdempotent()) {
- auto type = Target->getDeclaredType()->getCanonicalType();
- auto metadata =
- IGF.IGM.getAddrOfTypeMetadata(type, /*pattern*/ false);
- return emitFinishIdempotentInitialization(IGF, metadata);
- }
-
- // Otherwise, use the generic path.
- return emitInPlaceTypeMetadataAccessFunctionBody(IGF, type, cacheVar,
- [&](IRGenFunction &IGF, llvm::Value *metadata) {
- return emitInPlaceMetadataInitialization(IGF, type, metadata);
- });
- });
- }
-
- private:
- llvm::Value *emitInPlaceMetadataInitialization(IRGenFunction &IGF,
- CanClassType type,
- llvm::Value *metadata) {
- // Many of the things done by generic instantiation are unnecessary here:
- // initializing the metaclass pointer
- // initializing the ro-data pointer
-
- // Initialize the superclass if we didn't do so as a constant.
- if (HasUnfilledSuperclass) {
- auto superclass = type->getSuperclass(nullptr)->getCanonicalType();
- llvm::Value *superclassMetadata =
- emitClassHeapMetadataRef(IGF, superclass,
- MetadataValueType::TypeMetadata,
- /*allowUninit*/ false);
- Address superField =
- emitAddressOfSuperclassRefInClassMetadata(IGF, metadata);
- superField = IGF.Builder.CreateElementBitCast(superField,
- IGF.IGM.TypeMetadataPtrTy);
- IGF.Builder.CreateStore(superclassMetadata, superField);
- }
-
- // Initialize the class's own parent pointer if it has one and it
- // wasn't emitted as a constant.
- if (HasUnfilledParent) {
- auto parentType = type.getParent();
- assert(parentType);
- llvm::Value *parentMetadata = IGF.emitTypeMetadataRef(parentType);
-
- int index = getClassParentIndex(IGF.IGM, Target);
- Address slot = emitAddressOfMetadataSlotAtIndex(IGF, metadata, index,
- IGF.IGM.TypeMetadataPtrTy);
- IGF.Builder.CreateStore(parentMetadata, slot);
- }
-
- metadata = emitFinishInitializationOfClassMetadata(IGF, metadata);
-
- return metadata;
+ bool constantSuperclass =
+ addReferenceToType(superclassTy->getCanonicalType());
+ assert(constantSuperclass && "need template if superclass is dependent");
+ (void) constantSuperclass;
}
};
+ Address emitAddressOfFieldOffsetVectorInClassMetadata(IRGenFunction &IGF,
+ ClassDecl *theClass,
+ llvm::Value *metadata) {
+ BEGIN_METADATA_SEARCHER_0(GetOffsetToFieldOffsetVector, Class)
+ void noteStartOfFieldOffsets(ClassDecl *whichClass) {
+ if (whichClass == Target)
+ setTargetOffset();
+ }
+ END_METADATA_SEARCHER()
+
+ auto offset =
+ GetOffsetToFieldOffsetVector(IGF.IGM, theClass).getTargetOffset();
+
+ Address addr(metadata, IGF.IGM.getPointerAlignment());
+ addr = IGF.Builder.CreateBitCast(addr,
+ IGF.IGM.SizeTy->getPointerTo());
+ return createPointerSizedGEP(IGF, addr, offset);
+ }
+
/// A builder for metadata templates.
class GenericClassMetadataBuilder :
public GenericMetadataBuilderBase<GenericClassMetadataBuilder,
@@ -3682,12 +3202,6 @@
HasDependentMetadata = true;
}
- void addParentMetadataRef(ClassDecl *forClass, Type classType) {
- CanType parentType = classType->getCanonicalType().getNominalParent();
- this->addFillOp(parentType, None, /*relative*/ false);
- addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy));
- }
-
void addSuperClass() {
// Filled in by the runtime.
addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy));
@@ -3802,6 +3316,34 @@
}
}
+ // The Objective-C runtime will copy field offsets from the field offset
+ // vector into field offset globals for us, if present. If there's no
+ // Objective-C runtime, we have to do this ourselves.
+ void emitInitializeFieldOffsets(IRGenFunction &IGF,
+ llvm::Value *metadata) {
+ unsigned index = FieldLayout.InheritedStoredProperties.size();
+
+ for (auto prop : Target->getStoredProperties()) {
+ auto access = FieldLayout.AllFieldAccesses[index];
+ if (access == FieldAccess::NonConstantDirect) {
+ Address offsetA = IGF.IGM.getAddrOfFieldOffset(prop,
+ /*indirect*/ false,
+ ForDefinition);
+
+ // We can't use emitClassFieldOffset() here because that creates
+ // an invariant load, which could be hoisted above the point
+ // where the metadata becomes fully initialized
+ Size offset = getClassFieldOffset(IGF.IGM, Target, prop);
+ int index = IGF.IGM.getOffsetInWords(offset);
+ auto offsetVal = emitLoadFromMetadataAtIndex(IGF, metadata, index,
+ IGF.IGM.SizeTy);
+ IGF.Builder.CreateStore(offsetVal, offsetA);
+ }
+
+ index++;
+ }
+ }
+
void emitInitializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
llvm::Value *vwtable) {
@@ -3888,10 +3430,86 @@
metaclassRODataPtr.getAddress(), IGF.IGM.IntPtrTy);
IGF.Builder.CreateStore(rodata, rodataPtrSlot);
}
+
+ // If we have fields that are not fixed-size, ask the runtime to
+ // populate the offset vector.
+ //
+ // FIXME: if only the superclass is resilient, we can get away
+ // with sliding field offsets instead of doing the entire layout all
+ // over again.
+ if (!Layout.isFixedLayout() || Target->isGenericContext()) {
+ llvm::Value *fieldVector
+ = emitAddressOfFieldOffsetVectorInClassMetadata(IGF,
+ Target, metadata)
+ .getAddress();
+
+ // Collect the stored properties of the type.
+ llvm::SmallVector<VarDecl*, 4> storedProperties;
+ for (auto prop : Target->getStoredProperties()) {
+ storedProperties.push_back(prop);
+ }
- // We can assume that this never relocates the metadata because
- // it should have been allocated properly for the class.
- (void) emitFinishInitializationOfClassMetadata(IGF, metadata);
+ // Fill out an array with the field type metadata records.
+ Address fields = IGF.createAlloca(
+ llvm::ArrayType::get(IGF.IGM.SizeTy,
+ storedProperties.size() * 2),
+ IGF.IGM.getPointerAlignment(), "classFields");
+ IGF.Builder.CreateLifetimeStart(fields,
+ IGF.IGM.getPointerSize() * storedProperties.size() * 2);
+
+ Address firstField;
+ unsigned index = 0;
+ for (auto prop : storedProperties) {
+ auto propFormalTy = prop->getType()->getCanonicalType();
+ SILType propLoweredTy = IGM.SILMod->Types.getLoweredType(propFormalTy);
+ auto &propTI = IGF.getTypeInfo(propLoweredTy);
+ auto sizeAndAlignMask
+ = propTI.getSizeAndAlignmentMask(IGF, propLoweredTy);
+
+ llvm::Value *size = sizeAndAlignMask.first;
+ Address sizeAddr =
+ IGF.Builder.CreateStructGEP(fields, index, IGF.IGM.getPointerSize());
+ IGF.Builder.CreateStore(size, sizeAddr);
+ if (index == 0) firstField = sizeAddr;
+
+ llvm::Value *alignMask = sizeAndAlignMask.second;
+ Address alignMaskAddr =
+ IGF.Builder.CreateStructGEP(fields, index + 1,
+ IGF.IGM.getPointerSize());
+ IGF.Builder.CreateStore(alignMask, alignMaskAddr);
+
+ index += 2;
+ }
+
+ if (storedProperties.empty()) {
+ firstField = IGF.Builder.CreateStructGEP(fields, 0, Size(0));
+ }
+
+ // Ask the runtime to lay out the class.
+ auto numFields = IGF.IGM.getSize(Size(storedProperties.size()));
+ IGF.Builder.CreateCall(IGF.IGM.getInitClassMetadataUniversalFn(),
+ {metadata, numFields,
+ firstField.getAddress(), fieldVector});
+ IGF.Builder.CreateLifetimeEnd(fields,
+ IGF.IGM.getPointerSize() * storedProperties.size() * 2);
+
+ } else {
+ // If we have any ancestor generic parameters or field offset vectors,
+ // copy them from the superclass metadata.
+ auto initFn = IGF.IGM.getInitializeSuperclassFn();
+
+ bool copyFieldOffsetVectors = false;
+ if (FieldLayout.MetadataAccess != FieldAccess::ConstantDirect)
+ copyFieldOffsetVectors = true;
+
+ IGF.Builder.CreateCall(initFn,
+ {metadata,
+ llvm::ConstantInt::get(IGF.IGM.Int1Ty,
+ copyFieldOffsetVectors)});
+ }
+
+ if (!IGF.IGM.ObjCInterop)
+ emitInitializeFieldOffsets(IGF, metadata);
}
};
}
@@ -3928,27 +3546,22 @@
// TODO: classes nested within generic types
llvm::Constant *init;
bool isPattern;
- bool canBeConstant;
- if (classDecl->isGenericContext()) {
+ if (IGM.hasMetadataPattern(classDecl)) {
GenericClassMetadataBuilder builder(IGM, classDecl, layout, fieldLayout,
tempBase.get());
builder.layout();
init = builder.getInit();
isPattern = true;
- canBeConstant = false;
-
- maybeEmitNominalTypeMetadataAccessFunction(IGM, classDecl, builder);
} else {
ClassMetadataBuilder builder(IGM, classDecl, layout, fieldLayout,
tempBase.get());
builder.layout();
init = builder.getInit();
isPattern = false;
- canBeConstant = builder.canBeConstant();
-
- maybeEmitNominalTypeMetadataAccessFunction(IGM, classDecl, builder);
}
+ maybeEmitTypeMetadataAccessFunction(IGM, classDecl);
+
CanType declaredType = classDecl->getDeclaredType()->getCanonicalType();
// For now, all type metadata is directly stored.
@@ -3959,12 +3572,14 @@
section = "__DATA,__objc_data, regular";
auto var = IGM.defineTypeMetadata(declaredType, isIndirect, isPattern,
- canBeConstant, init, std::move(tempBase), section);
+ // TODO: the metadata global can actually be constant in a very
+ // special case: it's not a pattern, ObjC interoperation isn't
+ // required, there are no class fields, and there is nothing that
+ // needs to be runtime-adjusted.
+ /*isConstant*/ false, init, std::move(tempBase), section);
- // Add classes that don't require dynamic initialization to the
- // ObjC class list.
- if (IGM.ObjCInterop && !isPattern && !isIndirect &&
- !doesClassMetadataRequireDynamicInitialization(IGM, classDecl)) {
+ // Add non-generic classes to the ObjC class list.
+ if (IGM.ObjCInterop && !isPattern && !isIndirect) {
// Emit the ObjC class symbol to make the class visible to ObjC.
if (classDecl->isObjC()) {
emitObjCClassSymbol(IGM, classDecl, var);
@@ -3988,6 +3603,36 @@
}
/// Emit a load from the given metadata at a constant index.
+static llvm::LoadInst *emitLoadFromMetadataAtIndex(IRGenFunction &IGF,
+ llvm::Value *metadata,
+ int index,
+ llvm::Type *objectTy,
+ const llvm::Twine &suffix) {
+ // Require the metadata to be some type that we recognize as a
+ // metadata pointer.
+ assert(metadata->getType() == IGF.IGM.TypeMetadataPtrTy);
+
+ // We require objectType to be a pointer type so that the GEP will
+ // scale by the right amount. We could load an arbitrary type using
+ // some extra bitcasting.
+ assert(IGF.IGM.DataLayout.getTypeStoreSize(objectTy) ==
+ IGF.IGM.DataLayout.getTypeStoreSize(IGF.IGM.SizeTy));
+
+ // Cast to T*.
+ auto objectPtrTy = objectTy->getPointerTo();
+ auto metadataWords = IGF.Builder.CreateBitCast(metadata, objectPtrTy);
+
+ auto indexV = llvm::ConstantInt::getSigned(IGF.IGM.SizeTy, index);
+
+ // GEP to the slot.
+ Address slot(IGF.Builder.CreateInBoundsGEP(metadataWords, indexV),
+ IGF.IGM.getPointerAlignment());
+
+ // Load.
+ return IGF.Builder.CreateLoad(slot, metadata->getName() + suffix);
+}
+
+/// Emit a load from the given metadata at a constant index.
///
/// The load is marked invariant. This function should not be called
/// on metadata objects that are in the process of being initialized.
@@ -4074,22 +3719,13 @@
namespace {
/// A class for finding the 'parent' index in a class metadata object.
BEGIN_METADATA_SEARCHER_0(FindClassParentIndex, Class)
- void addParentMetadataRef(ClassDecl *forClass, Type classType) {
+ void addParentMetadataRef(ClassDecl *forClass) {
if (forClass == Target) setTargetOffset();
- super::addParentMetadataRef(forClass, classType);
+ super::addParentMetadataRef(forClass);
}
END_METADATA_SEARCHER()
}
-/// Return the index of the parent metadata pointer for the given class.
-static int getClassParentIndex(IRGenModule &IGM, ClassDecl *classDecl) {
- assert(classDecl->getDeclContext()->isTypeContext());
- return FindClassParentIndex(IGM, classDecl).getTargetIndex();
-}
-
-/// In both enums and structs, the parent index is at index 2.
-static constexpr int ValueTypeParentIndex = 2;
-
/// Given a reference to some metadata, derive a reference to the
/// type's parent type.
llvm::Value *irgen::emitParentMetadataRef(IRGenFunction &IGF,
@@ -4108,13 +3744,15 @@
llvm_unreachable("protocols never have parent types!");
case DeclKind::Class: {
- int index = getClassParentIndex(IGF.IGM, cast<ClassDecl>(decl));
+ int index =
+ FindClassParentIndex(IGF.IGM, cast<ClassDecl>(decl)).getTargetIndex();
return emitLoadOfMetadataRefAtIndex(IGF, metadata, index);
}
case DeclKind::Enum:
case DeclKind::Struct:
- return emitLoadOfMetadataRefAtIndex(IGF, metadata, ValueTypeParentIndex);
+ // In both of these cases, 'Parent' is always the third field.
+ return emitLoadOfMetadataRefAtIndex(IGF, metadata, 2);
}
llvm_unreachable("bad decl kind!");
}
@@ -4577,108 +4215,6 @@
}
//===----------------------------------------------------------------------===//
-// Value types (structs and enums)
-//===----------------------------------------------------------------------===//
-
-namespace {
- template <class Impl, class Base>
- class ValueTypeMetadataBuilderBase : public ConstantBuilder<Base> {
- using super = ConstantBuilder<Base>;
-
- protected:
- using super::asImpl;
- using super::IGM;
- using super::Target;
- using super::addWord;
-
- template <class DeclTy>
- ValueTypeMetadataBuilderBase(IRGenModule &IGM, DeclTy *theDecl)
- : super(IGM, theDecl) {}
-
- CanType getParentType() const {
- Type parentType =
- Target->getDeclContext()->getDeclaredTypeInContext();
- return (parentType ? parentType->getCanonicalType() : CanType());
- }
-
- public:
- void addParentMetadataRef() {
- llvm::Constant *parentMetadata = nullptr;
- if (auto parentType = getParentType()) {
- parentMetadata =
- tryEmitConstantTypeMetadataRef(IGM, parentType,
- SymbolReferenceKind::Absolute)
- .getDirectValue();
- if (!parentMetadata) {
- asImpl().flagUnfilledParent();
- }
- }
-
- if (!parentMetadata)
- parentMetadata = llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy);
- addWord(parentMetadata);
- }
- };
-}
-
-static llvm::Value *
-emitInPlaceValueTypeMetadataInitialization(IRGenFunction &IGF,
- CanNominalType type,
- llvm::Value *metadata,
- bool hasUnfilledParent) {
- // All the value types are basically similar.
- assert(isa<StructType>(type) || isa<EnumType>(type));
-
- // Initialize the parent-metadata field if it wasn't done statically.
- if (hasUnfilledParent) {
- CanType parentType = type.getParent();
- assert(parentType);
-
- // Value types hold the parent metadata as a far relative
- // indirectable pointer.
- llvm::Value *parentMetadata = IGF.emitTypeMetadataRef(parentType);
- Address addr =
- emitAddressOfMetadataSlotAtIndex(IGF, metadata, ValueTypeParentIndex,
- IGF.IGM.TypeMetadataPtrTy);
- IGF.Builder.CreateStore(parentMetadata, addr);
- }
-
- // Set up the value witness table if it's dependent.
- SILType loweredType = IGF.IGM.getLoweredType(AbstractionPattern(type), type);
- auto &ti = IGF.IGM.getTypeInfo(loweredType);
- if (!ti.isFixedSize()) {
- // We assume that that value witness table will already have been written
- // into the metadata; just load it.
- llvm::Value *vwtable = IGF.emitValueWitnessTableRefForMetadata(metadata);
-
- // Initialize the metadata.
- ti.initializeMetadata(IGF, metadata, vwtable, loweredType.getAddressType());
- }
-
- return metadata;
-}
-
-/// Create an access function for the type metadata of the given
-/// non-generic nominal type.
-static void createInPlaceValueTypeMetadataAccessFunction(IRGenModule &IGM,
- NominalTypeDecl *typeDecl,
- bool hasUnfilledParent) {
- assert(!typeDecl->isGenericContext());
- auto type =
- cast<NominalType>(typeDecl->getDeclaredType()->getCanonicalType());
-
- (void) getTypeMetadataAccessFunction(IGM, type, ForDefinition,
- [&](IRGenFunction &IGF,
- llvm::Constant *cacheVariable) {
- return emitInPlaceTypeMetadataAccessFunctionBody(IGF, type, cacheVariable,
- [&](IRGenFunction &IGF, llvm::Value *metadata) {
- return emitInPlaceValueTypeMetadataInitialization(IGF, type, metadata,
- hasUnfilledParent);
- });
- });
-}
-
-//===----------------------------------------------------------------------===//
// Structs
//===----------------------------------------------------------------------===//
@@ -4686,8 +4222,8 @@
/// An adapter for laying out struct metadata.
template <class Impl>
class StructMetadataBuilderBase
- : public ValueTypeMetadataBuilderBase<Impl,StructMetadataLayout<Impl>>{
- using super = ValueTypeMetadataBuilderBase<Impl,StructMetadataLayout<Impl>>;
+ : public ConstantBuilder<StructMetadataLayout<Impl>> {
+ using super = ConstantBuilder<StructMetadataLayout<Impl>>;
protected:
using super::IGM;
@@ -4715,6 +4251,11 @@
addFarRelativeAddress(descriptor);
}
+ void addParentMetadataRef() {
+ // FIXME: populate
+ addFarRelativeAddressOrNull(nullptr);
+ }
+
void addFieldOffset(VarDecl *var) {
assert(var->hasStorage() &&
"storing field offset for computed property?!");
@@ -4748,30 +4289,15 @@
class StructMetadataBuilder :
public StructMetadataBuilderBase<StructMetadataBuilder> {
-
- bool HasUnfilledParent = false;
public:
StructMetadataBuilder(IRGenModule &IGM, StructDecl *theStruct,
llvm::GlobalVariable *relativeAddressBase)
: StructMetadataBuilderBase(IGM, theStruct, relativeAddressBase) {}
- void flagUnfilledParent() {
- HasUnfilledParent = true;
- }
-
- bool canBeConstant() {
- return !HasUnfilledParent;
- }
-
void addValueWitnessTable() {
auto type = this->Target->getDeclaredType()->getCanonicalType();
addWord(emitValueWitnessTable(IGM, type));
}
-
- void createMetadataAccessFunction() {
- createInPlaceValueTypeMetadataAccessFunction(IGM, Target,
- HasUnfilledParent);
- }
};
/// Emit a value witness table for a fixed-layout generic type, or a null
@@ -4810,15 +4336,6 @@
{metadataPattern, arguments});
}
- void addParentMetadataRef() {
- // Override to always use a fill op instead of a relocation.
- if (CanType parentType = getParentType()) {
- addFillOp(parentType, None, /*relative*/ false);
- }
-
- addConstantWord(0);
- }
-
void addValueWitnessTable() {
addWord(getValueWitnessTableForGenericValueType(IGM, Target,
HasDependentVWT));
@@ -4854,32 +4371,27 @@
// TODO: structs nested within generic types
llvm::Constant *init;
bool isPattern;
- bool canBeConstant;
- if (structDecl->isGenericContext()) {
+ if (IGM.hasMetadataPattern(structDecl)) {
GenericStructMetadataBuilder builder(IGM, structDecl, tempBase.get());
builder.layout();
init = builder.getInit();
isPattern = true;
- canBeConstant = false;
-
- maybeEmitNominalTypeMetadataAccessFunction(IGM, structDecl, builder);
} else {
StructMetadataBuilder builder(IGM, structDecl, tempBase.get());
builder.layout();
init = builder.getInit();
isPattern = false;
- canBeConstant = builder.canBeConstant();
-
- maybeEmitNominalTypeMetadataAccessFunction(IGM, structDecl, builder);
}
+ maybeEmitTypeMetadataAccessFunction(IGM, structDecl);
+
CanType declaredType = structDecl->getDeclaredType()->getCanonicalType();
// For now, all type metadata is directly stored.
bool isIndirect = false;
IGM.defineTypeMetadata(declaredType, isIndirect, isPattern,
- canBeConstant, init,
+ /*isConstant*/!isPattern, init,
std::move(tempBase));
}
@@ -4889,8 +4401,9 @@
template<class Impl>
class EnumMetadataBuilderBase
- : public ValueTypeMetadataBuilderBase<Impl, EnumMetadataLayout<Impl>> {
- using super = ValueTypeMetadataBuilderBase<Impl, EnumMetadataLayout<Impl>>;
+ : public ConstantBuilder<EnumMetadataLayout<Impl>>
+{
+ using super = ConstantBuilder<EnumMetadataLayout<Impl>>;
protected:
using super::IGM;
@@ -4918,7 +4431,12 @@
addFarRelativeAddress(descriptor);
}
-
+
+ void addParentMetadataRef() {
+ // FIXME: populate
+ addFarRelativeAddressOrNull(nullptr);
+ }
+
void addGenericArgument(CanType type) {
addWord(llvm::Constant::getNullValue(IGM.TypeMetadataPtrTy));
}
@@ -4929,9 +4447,8 @@
};
class EnumMetadataBuilder
- : public EnumMetadataBuilderBase<EnumMetadataBuilder> {
- bool HasUnfilledParent = false;
-
+ : public EnumMetadataBuilderBase<EnumMetadataBuilder>
+{
public:
EnumMetadataBuilder(IRGenModule &IGM, EnumDecl *theEnum,
llvm::GlobalVariable *relativeAddressBase)
@@ -4945,29 +4462,15 @@
void addPayloadSize() {
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();
auto &enumTI = IGM.getTypeInfoForLowered(enumTy);
- if (!enumTI.isFixedSize(ResilienceExpansion::Maximal)) {
- addConstantWord(0);
- return;
- }
-
+ (void) enumTI;
+ assert(enumTI.isFixedSize(ResilienceExpansion::Maximal) &&
+ "emitting constant enum metadata for resilient-sized type?");
assert(!enumTI.isFixedSize(ResilienceExpansion::Minimal) &&
"non-generic, non-resilient enums don't need payload size in metadata");
+
auto &strategy = getEnumImplStrategy(IGM, enumTy);
addConstantWord(strategy.getPayloadSizeForMetadata());
}
-
- void flagUnfilledParent() {
- HasUnfilledParent = true;
- }
-
- bool canBeConstant() {
- return !HasUnfilledParent;
- }
-
- void createMetadataAccessFunction() {
- createInPlaceValueTypeMetadataAccessFunction(IGM, Target,
- HasUnfilledParent);
- }
};
class GenericEnumMetadataBuilder
@@ -4985,15 +4488,6 @@
return IGF.Builder.CreateCall(IGM.getAllocateGenericValueMetadataFn(),
{metadataPattern, arguments});
}
-
- void addParentMetadataRef() {
- // Override to always use a fill op instead of a relocation.
- if (CanType parentType = getParentType()) {
- addFillOp(parentType, None, /*relative*/ false);
- }
-
- addConstantWord(0);
- }
void addValueWitnessTable() {
addWord(getValueWitnessTableForGenericValueType(IGM, Target,
@@ -5042,25 +4536,20 @@
llvm::Constant *init;
bool isPattern;
- bool canBeConstant;
- if (theEnum->isGenericContext()) {
+ if (IGM.hasMetadataPattern(theEnum)) {
GenericEnumMetadataBuilder builder(IGM, theEnum, tempBase.get());
builder.layout();
init = builder.getInit();
isPattern = true;
- canBeConstant = false;
-
- maybeEmitNominalTypeMetadataAccessFunction(IGM, theEnum, builder);
} else {
EnumMetadataBuilder builder(IGM, theEnum, tempBase.get());
builder.layout();
init = builder.getInit();
isPattern = false;
- canBeConstant = builder.canBeConstant();
-
- maybeEmitNominalTypeMetadataAccessFunction(IGM, theEnum, builder);
}
+ maybeEmitTypeMetadataAccessFunction(IGM, theEnum);
+
CanType declaredType = theEnum->getDeclaredType()->getCanonicalType();
// For now, all type metadata is directly stored.
@@ -5229,10 +4718,6 @@
auto type = this->Target->getDeclaredType()->getCanonicalType();
addWord(emitValueWitnessTable(IGM, type));
}
-
- void flagUnfilledParent() {
- llvm_unreachable("foreign type with parent type metadata?");
- }
};
/// A builder for ForeignEnumMetadata.
@@ -5260,10 +4745,6 @@
void addPayloadSize() const {
llvm_unreachable("nongeneric enums shouldn't need payload size in metadata");
}
-
- void flagUnfilledParent() {
- llvm_unreachable("foreign type with parent type metadata?");
- }
};
}
diff --git a/lib/IRGen/GenMeta.h b/lib/IRGen/GenMeta.h
index 7f61d89..8a2b663 100644
--- a/lib/IRGen/GenMeta.h
+++ b/lib/IRGen/GenMeta.h
@@ -39,7 +39,6 @@
namespace irgen {
class Callee;
- class ConstantReference;
class Explosion;
class FieldTypeInfo;
class GenericTypeRequirements;
@@ -47,7 +46,6 @@
class IRGenModule;
class Size;
class StructLayout;
- enum class SymbolReferenceKind : unsigned char;
struct ClassLayout;
/// Is the given class known to have Swift-compatible metadata?
@@ -81,16 +79,8 @@
/// Emit a reference to a compile-time constant piece of type metadata, or
/// return a null pointer if the type's metadata cannot be represented by a
/// constant.
- ConstantReference tryEmitConstantTypeMetadataRef(IRGenModule &IGM,
- CanType type,
- SymbolReferenceKind refKind);
-
- /// Emit a reference to a compile-time constant piece of heap metadata, or
- /// return a null pointer if the type's heap metadata cannot be represented
- /// by a constant.
- llvm::Constant *tryEmitConstantHeapMetadataRef(IRGenModule &IGM,
- CanType type,
- bool allowUninitialized);
+ llvm::Constant *tryEmitConstantTypeMetadataRef(IRGenModule &IGM,
+ CanType type);
enum class MetadataValueType { ObjCClass, TypeMetadata };
diff --git a/lib/IRGen/GenValueWitness.cpp b/lib/IRGen/GenValueWitness.cpp
index 8d3b8a3..747e15e 100644
--- a/lib/IRGen/GenValueWitness.cpp
+++ b/lib/IRGen/GenValueWitness.cpp
@@ -1361,6 +1361,10 @@
assert(!isa<BoundGenericType>(abstractType) &&
"emitting VWT for generic instance");
+ // We shouldn't emit global value witness tables for non-fixed-layout types.
+ assert(!hasDependentValueWitnessTable(IGM, abstractType) &&
+ "emitting global VWT for dynamic-layout type");
+
SmallVector<llvm::Constant*, MaxNumValueWitnesses> witnesses;
addValueWitnessesForAbstractType(IGM, abstractType, witnesses);
diff --git a/lib/IRGen/IRGen.h b/lib/IRGen/IRGen.h
index e9ff125..46b2317 100644
--- a/lib/IRGen/IRGen.h
+++ b/lib/IRGen/IRGen.h
@@ -143,55 +143,6 @@
IsExact = true
};
-/// Ways in which an object can be referenced.
-///
-/// See the comment in RelativePointer.h.
-
-enum class SymbolReferenceKind : unsigned char {
- /// An absolute reference to the object, i.e. an ordinary pointer.
- ///
- /// Generally well-suited for when C compatibility is a must, dynamic
- /// initialization is the dominant case, or the runtime performance
- /// of accesses is an overriding concern.
- Absolute,
-
- /// A direct relative reference to the object, i.e. the offset of the
- /// object from the address at which the relative reference is stored.
- ///
- /// Generally well-suited for when the reference is always statically
- /// initialized and will always refer to another object within the
- /// same linkage unit.
- Relative_Direct,
-
- /// A direct relative reference that is guaranteed to be as wide as a
- /// pointer.
- ///
- /// Generally well-suited for when the reference may be dynamically
- /// initialized, but will only refer to objects within the linkage unit
- /// when statically initialized.
- Far_Relative_Direct,
-
- /// A relative reference that may be indirect: the direct reference is
- /// either directly to the object or to a variable holding an absolute
- /// reference to the object.
- ///
- /// The low bit of the target offset is used to mark an indirect reference,
- /// and so the low bit of the target address must be zero. This means that,
- /// in general, it is not possible to form this kind of reference to a
- /// function (due to the THUMB bit) or unaligned data (such as a C string).
- ///
- /// Generally well-suited for when the reference is always statically
- /// initialized but may refer to soemthing outside of the linkage unit.
- Relative_Indirectable,
-
- /// An indirectable reference to the object; guaranteed to be as wide
- /// as a pointer.
- ///
- /// Generally well-suited for when the reference may be dynamically
- /// initialized but may also statically refer outside of the linkage unit.
- Far_Relative_Indirectable,
-};
-
/// Destructor variants.
enum class DestructorKind : uint8_t {
/// A deallocating destructor destroys the object and deallocates
diff --git a/lib/IRGen/IRGenFunction.cpp b/lib/IRGen/IRGenFunction.cpp
index e4d112e..17a2243 100644
--- a/lib/IRGen/IRGenFunction.cpp
+++ b/lib/IRGen/IRGenFunction.cpp
@@ -204,73 +204,6 @@
{pointer, size, alignMask});
}
-/// Initialize a relative indirectable pointer to the given value.
-/// This always leaves the value in the direct state; if it's not a
-/// far reference, it's the caller's responsibility to ensure that the
-/// pointer ranges are sufficient.
-void IRGenFunction::emitStoreOfRelativeIndirectablePointer(llvm::Value *value,
- Address addr,
- bool isFar) {
- value = Builder.CreatePtrToInt(value, IGM.IntPtrTy);
- auto addrAsInt =
- Builder.CreatePtrToInt(addr.getAddress(), IGM.IntPtrTy);
-
- auto difference = Builder.CreateSub(value, addrAsInt);
- if (!isFar) {
- difference = Builder.CreateTrunc(difference, IGM.RelativeAddressTy);
- }
-
- Builder.CreateStore(difference, addr);
-}
-
-llvm::Value *
-IRGenFunction::emitLoadOfRelativeIndirectablePointer(Address addr,
- bool isFar,
- llvm::PointerType *expectedType,
- const llvm::Twine &name) {
- // Load the pointer and turn it back into a pointer.
- llvm::Value *value = Builder.CreateLoad(addr);
- assert(value->getType() == (isFar ? IGM.FarRelativeAddressTy
- : IGM.RelativeAddressTy));
- if (!isFar) {
- value = Builder.CreateSExt(value, IGM.IntPtrTy);
- }
- assert(value->getType() == IGM.IntPtrTy);
-
- llvm::BasicBlock *origBB = Builder.GetInsertBlock();
- llvm::Value *directResult = Builder.CreateIntToPtr(value, expectedType);
-
- // Check whether the low bit is set.
- llvm::Constant *one = llvm::ConstantInt::get(IGM.IntPtrTy, 1);
- llvm::BasicBlock *indirectBB = createBasicBlock("relptr.indirect");
- llvm::BasicBlock *contBB = createBasicBlock("relptr.cont");
- llvm::Value *isIndirect = Builder.CreateAnd(value, one);
- isIndirect = Builder.CreateIsNotNull(isIndirect);
- Builder.CreateCondBr(isIndirect, indirectBB, contBB);
-
- // In the indirect block, clear the low bit and perform an additional load.
- llvm::Value *indirectResult; {
- Builder.emitBlock(indirectBB);
-
- // Clear the low bit.
- llvm::Value *ptr = Builder.CreateSub(value, one);
- ptr = Builder.CreateIntToPtr(ptr, expectedType->getPointerTo());
-
- // Load.
- Address indirectAddr(ptr, IGM.getPointerAlignment());
- indirectResult = Builder.CreateLoad(indirectAddr);
-
- Builder.CreateBr(contBB);
- }
-
- Builder.emitBlock(contBB);
- auto phi = Builder.CreatePHI(expectedType, 2, name);
- phi->addIncoming(directResult, origBB);
- phi->addIncoming(indirectResult, indirectBB);
-
- return phi;
-}
-
void IRGenFunction::emitFakeExplosion(const TypeInfo &type,
Explosion &explosion) {
if (!isa<LoadableTypeInfo>(type)) {
diff --git a/lib/IRGen/IRGenFunction.h b/lib/IRGen/IRGenFunction.h
index cb3e0a3..06f5ebb 100644
--- a/lib/IRGen/IRGenFunction.h
+++ b/lib/IRGen/IRGenFunction.h
@@ -140,16 +140,6 @@
const TypeInfo &type,
const llvm::Twine &name = "");
- void emitStoreOfRelativeIndirectablePointer(llvm::Value *value,
- Address addr,
- bool isFar);
-
- llvm::Value *
- emitLoadOfRelativeIndirectablePointer(Address addr, bool isFar,
- llvm::PointerType *expectedType,
- const llvm::Twine &name = "");
-
-
llvm::Value *emitAllocObjectCall(llvm::Value *metadata, llvm::Value *size,
llvm::Value *alignMask,
const llvm::Twine &name = "");
diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h
index a5749b0..98a5deb 100644
--- a/lib/IRGen/IRGenModule.h
+++ b/lib/IRGen/IRGenModule.h
@@ -31,7 +31,6 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/IR/CallingConv.h"
-#include "llvm/IR/Constant.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/IR/Attributes.h"
#include "llvm/Target/TargetMachine.h"
@@ -306,29 +305,6 @@
friend class CurrentIGMPtr;
};
-class ConstantReference {
-public:
- enum Directness : bool { Direct, Indirect };
-private:
- llvm::PointerIntPair<llvm::Constant *, 1, Directness> ValueAndIsIndirect;
-public:
- ConstantReference() {}
- ConstantReference(llvm::Constant *value, Directness isIndirect)
- : ValueAndIsIndirect(value, isIndirect) {}
-
- Directness isIndirect() const { return ValueAndIsIndirect.getInt(); }
- llvm::Constant *getValue() const { return ValueAndIsIndirect.getPointer(); }
-
- llvm::Constant *getDirectValue() const {
- assert(!isIndirect());
- return getValue();
- }
-
- explicit operator bool() const {
- return ValueAndIsIndirect.getPointer() != nullptr;
- }
-};
-
/// IRGenModule - Primary class for emitting IR for global declarations.
///
class IRGenModule {
@@ -821,8 +797,6 @@
llvm::StringRef section = {});
llvm::Constant *getAddrOfTypeMetadata(CanType concreteType, bool isPattern);
- ConstantReference getAddrOfTypeMetadata(CanType concreteType, bool isPattern,
- SymbolReferenceKind kind);
llvm::Function *getAddrOfTypeMetadataAccessFunction(CanType type,
ForDefinition_t forDefinition);
llvm::Function *getAddrOfGenericTypeMetadataAccessFunction(
@@ -881,16 +855,22 @@
StringRef mangleType(CanType type, SmallVectorImpl<char> &buffer);
+ bool hasMetadataPattern(NominalTypeDecl *theDecl);
+
// Get the ArchetypeBuilder for the currently active generic context. Crashes
// if there is no generic context.
ArchetypeBuilder &getContextArchetypes();
- ConstantReference
+ enum class DirectOrGOT {
+ Direct, GOT,
+ };
+
+ std::pair<llvm::Constant *, DirectOrGOT>
getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity, Alignment alignment,
llvm::Type *defaultType);
llvm::Constant *
- emitRelativeReference(ConstantReference target,
+ emitRelativeReference(std::pair<llvm::Constant *, DirectOrGOT> target,
llvm::Constant *base,
ArrayRef<unsigned> baseIndices);
@@ -914,12 +894,6 @@
ForDefinition_t forDefinition,
llvm::Type *defaultType,
DebugTypeInfo debugType);
- ConstantReference getAddrOfLLVMVariable(LinkEntity entity,
- Alignment alignment,
- llvm::Type *definitionType,
- llvm::Type *defaultType,
- DebugTypeInfo debugType,
- SymbolReferenceKind refKind);
void emitLazyPrivateDefinitions();
void addRuntimeResolvableType(CanType type);
diff --git a/lib/IRGen/StructLayout.h b/lib/IRGen/StructLayout.h
index c8454e5..12335a0 100644
--- a/lib/IRGen/StructLayout.h
+++ b/lib/IRGen/StructLayout.h
@@ -416,8 +416,8 @@
/// Lazily-initialized metadata access method. See the comment in
/// ClassLayoutBuilder.
FieldAccess MetadataAccess;
- /// Does the class metadata require dynamic initialization.
- bool MetadataRequiresDynamicInitialization;
+ /// Does the class require a metadata pattern.
+ bool HasMetadataPattern;
unsigned getFieldIndex(VarDecl *field) const {
// FIXME: This is algorithmically terrible.
diff --git a/lib/SIL/Linker.cpp b/lib/SIL/Linker.cpp
index ea7c4eb..08f28ea 100644
--- a/lib/SIL/Linker.cpp
+++ b/lib/SIL/Linker.cpp
@@ -83,10 +83,7 @@
return false;
// If F is a declaration, first deserialize it.
- auto *NewFn =
- isAvailableExternally(Decl.getLinkage(ForDefinition_t::NotForDefinition))
- ? Loader->lookupSILFunction(Decl)
- : nullptr;
+ auto *NewFn = Loader->lookupSILFunction(Decl);
if (!NewFn || NewFn->isExternalDeclaration())
return false;
diff --git a/lib/SIL/SILDeclRef.cpp b/lib/SIL/SILDeclRef.cpp
index 3239c36..6aa33d2 100644
--- a/lib/SIL/SILDeclRef.cpp
+++ b/lib/SIL/SILDeclRef.cpp
@@ -240,34 +240,6 @@
return AnyFunctionRef(loc.get<AbstractClosureExpr*>());
}
-static SILLinkage getLinkageForLocalContext(DeclContext *dc) {
- auto isClangImported = [](AbstractFunctionDecl *fn) -> bool {
- if (fn->hasClangNode())
- return true;
- if (auto func = dyn_cast<FuncDecl>(fn))
- if (auto storage = func->getAccessorStorageDecl())
- return storage->hasClangNode();
- return false;
- };
-
- while (!dc->isModuleScopeContext()) {
- // Local definitions in transparent contexts are forced public because
- // external references to them can be exposed by mandatory inlining.
- // For Clang-imported decls, though, the closure should get re-synthesized
- // on use.
- if (auto fn = dyn_cast<AbstractFunctionDecl>(dc))
- if (fn->isTransparent() && !isClangImported(fn))
- return SILLinkage::Public;
- // Check that this local context is not itself in a local transparent
- // context.
- dc = dc->getParent();
- }
-
- // FIXME: Once we have access control at the AST level, we should not assume
- // shared always, but rather base it off of the local decl context.
- return SILLinkage::Shared;
-}
-
bool SILDeclRef::isThunk() const {
return isCurried || isForeignToNativeThunk() || isNativeToForeignThunk();
}
@@ -300,6 +272,8 @@
auto clangNode = getDecl()->getClangNode().getAsDecl();
if (auto nd = dyn_cast_or_null<clang::NamedDecl>(clangNode)) {
+ // ie, 'static inline' functions for which we must ask Clang to emit a body
+ // for explicitly
if (!nd->isExternallyVisible())
return true;
}
@@ -308,25 +282,26 @@
}
SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const {
- // Anonymous functions have local linkage.
- if (auto closure = getAbstractClosureExpr())
- return getLinkageForLocalContext(closure->getParent());
+ // Anonymous functions have shared linkage.
+ // FIXME: This should really be the linkage of the parent function.
+ if (getAbstractClosureExpr())
+ return SILLinkage::Shared;
- // Native function-local declarations have local linkage.
+ // Native function-local declarations have shared linkage.
// FIXME: @objc declarations should be too, but we currently have no way
// of marking them "used" other than making them external.
ValueDecl *d = getDecl();
DeclContext *moduleContext = d->getDeclContext();
while (!moduleContext->isModuleScopeContext()) {
if (!isForeign && moduleContext->isLocalContext())
- return getLinkageForLocalContext(moduleContext);
+ return SILLinkage::Shared;
moduleContext = moduleContext->getParent();
}
// Currying and calling convention thunks have shared linkage.
if (isThunk())
- // If a function declares a @_cdecl name, its native-to-foreign thunk is
- // exported with the visibility of the function.
+ // If a function declares a @_cdecl name, its native-to-foreign thunk
+ // is exported with the visibility of the function.
if (!isNativeToForeignThunk() || !d->getAttrs().hasAttribute<CDeclAttr>())
return SILLinkage::Shared;
@@ -383,6 +358,36 @@
return hasDecl() ? getDecl()->isTransparent() : false;
}
+/// \brief True if the function should have its body serialized.
+bool SILDeclRef::isFragile() const {
+ DeclContext *dc;
+ if (auto closure = getAbstractClosureExpr())
+ dc = closure->getLocalContext();
+ else
+ dc = getDecl()->getDeclContext();
+
+ while (!dc->isModuleScopeContext()) {
+ // Local definitions in transparent contexts are fragile because
+ // external references to them can be exposed by mandatory inlining.
+ if (auto fn = dyn_cast<AbstractFunctionDecl>(dc))
+ if (fn->isTransparent() &&
+ fn->getEffectiveAccess() == Accessibility::Public)
+ return true;
+ // Check that this local context is not itself in a local transparent
+ // context.
+ dc = dc->getParent();
+ }
+
+ // Externally-visible transparent functions are fragile.
+ if (hasDecl())
+ if (auto fn = dyn_cast<AbstractFunctionDecl>(getDecl()))
+ if (fn->isTransparent() &&
+ fn->getEffectiveAccess() == Accessibility::Public)
+ return true;
+
+ return false;
+}
+
/// \brief True if the function has noinline attribute.
bool SILDeclRef::isNoinline() const {
if (!hasDecl())
diff --git a/lib/SIL/SILModule.cpp b/lib/SIL/SILModule.cpp
index 195fa61..ae7ae7b 100644
--- a/lib/SIL/SILModule.cpp
+++ b/lib/SIL/SILModule.cpp
@@ -328,16 +328,16 @@
return fn;
}
- IsTransparent_t IsTrans = constant.isTransparent()?
- IsTransparent : IsNotTransparent;
- IsFragile_t IsFrag = IsNotFragile;
- if (IsTrans == IsTransparent && (linkage == SILLinkage::Public
- || linkage == SILLinkage::PublicExternal)) {
- IsFrag = IsFragile;
- }
+ IsTransparent_t IsTrans = constant.isTransparent()
+ ? IsTransparent
+ : IsNotTransparent;
+ IsFragile_t IsFrag = constant.isFragile()
+ ? IsFragile
+ : IsNotFragile;
- EffectsKind EK = constant.hasEffectsAttribute() ?
- constant.getEffectsAttribute() : EffectsKind::Unspecified;
+ EffectsKind EK = constant.hasEffectsAttribute()
+ ? constant.getEffectsAttribute()
+ : EffectsKind::Unspecified;
Inline_t inlineStrategy = InlineDefault;
if (constant.isNoinline())
diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp
index 2d5537b..fd46f7c 100644
--- a/lib/SIL/SILVerifier.cpp
+++ b/lib/SIL/SILVerifier.cpp
@@ -912,11 +912,9 @@
case SILLinkage::Shared:
case SILLinkage::SharedExternal:
- // This handles some kind of generated functions, like constructors
- // of clang imported types.
- // TODO: check why those functions are not fragile anyway and make
- // a less conservative check here.
- return true;
+ // This allows fragile functions to reference thunks, generated
+ // methods on Clang types, and optimizer specializations.
+ return true;
case SILLinkage::Public:
case SILLinkage::PublicExternal:
@@ -924,6 +922,31 @@
}
}
+ bool isValidLinkageForFragileRef(const SILFunction *RefF) {
+ if (RefF->isFragile() ||
+ RefF->isExternalDeclaration()) {
+ return true;
+ }
+
+ return isValidLinkageForFragileRef(RefF->getLinkage());
+ }
+
+ /// Returns true if \p FRI is only used as a callee and will always be
+ /// inlined at those call sites.
+ static bool isAlwaysInlined(FunctionRefInst *FRI) {
+ if (FRI->getReferencedFunction()->getInlineStrategy() != AlwaysInline &&
+ !FRI->getReferencedFunction()->isTransparent()) {
+ return false;
+ }
+
+ for (auto use : FRI->getUses()) {
+ auto site = FullApplySite::isa(use->getUser());
+ if (!site || site.getCallee() != FRI)
+ return false;
+ }
+ return true;
+ }
+
void checkFunctionRefInst(FunctionRefInst *FRI) {
auto fnType = requireObjectType(SILFunctionType, FRI,
"result of function_ref");
@@ -931,9 +954,8 @@
"function_ref should have a context-free function result");
if (F.isFragile()) {
SILFunction *RefF = FRI->getReferencedFunction();
- require(RefF->isFragile()
- || isValidLinkageForFragileRef(RefF->getLinkage())
- || RefF->isExternalDeclaration(),
+ require(isAlwaysInlined(FRI)
+ || isValidLinkageForFragileRef(RefF),
"function_ref inside fragile function cannot "
"reference a private or hidden symbol");
}
diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp
index 25f7b3a..5a158d7 100644
--- a/lib/SILGen/SILGen.cpp
+++ b/lib/SILGen/SILGen.cpp
@@ -585,6 +585,8 @@
SILDeclRef nextEntryPoint) {
// Thunks are always emitted by need, so don't need delayed emission.
SILFunction *f = getFunction(entryPoint, ForDefinition);
+ f->setThunk(IsThunk);
+
preEmitFunction(entryPoint, fd, f, fd);
PrettyStackTraceSILFunction X("silgen emitCurryThunk", f);
@@ -597,6 +599,7 @@
// Thunks are always emitted by need, so don't need delayed emission.
assert(!thunk.isForeign && "foreign-to-native thunks only");
SILFunction *f = getFunction(thunk, ForDefinition);
+ f->setThunk(IsThunk);
preEmitFunction(thunk, thunk.getDecl(), f, thunk.getDecl());
PrettyStackTraceSILFunction X("silgen emitForeignToNativeThunk", f);
SILGenFunction(*this, *f).emitForeignToNativeThunk(thunk);
@@ -615,6 +618,7 @@
thunk.getAbstractClosureExpr());
PrettyStackTraceSILFunction X("silgen emitNativeToForeignThunk", f);
f->setBare(IsBare);
+ f->setThunk(IsThunk);
SILGenFunction(*this, *f).emitNativeToForeignThunk(thunk);
postEmitFunction(thunk, f);
}
diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp
index bd71b81..9b8fdc9 100644
--- a/lib/SILGen/SILGenType.cpp
+++ b/lib/SILGen/SILGenType.cpp
@@ -47,6 +47,7 @@
// an ObjC method. This would change if we introduced a native
// runtime-hookable mechanism.
SILGenFunction SGF(*this, *F);
+ F->setThunk(IsThunk);
SGF.emitForeignToNativeThunk(constant);
}
diff --git a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp
index 8a8cd93..dd71001 100644
--- a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp
+++ b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp
@@ -1173,6 +1173,36 @@
break;
}
+ if (FAS.getReferencedFunction() &&
+ FAS.getReferencedFunction()->hasSemanticsAttr(
+ "self_no_escaping_closure") &&
+ ((FAS.hasIndirectResults() && FAS.getNumArguments() == 3) ||
+ (!FAS.hasIndirectResults() && FAS.getNumArguments() == 2)) &&
+ FAS.hasSelfArgument()) {
+ // The programmer has guaranteed that the closure will not capture the
+ // self pointer passed to it or anything that is transitively reachable
+ // from the pointer.
+ auto Args = FAS.getArgumentsWithoutIndirectResults();
+ // The first not indirect result argument is the closure.
+ setEscapesGlobal(ConGraph, Args[0]);
+ return;
+ }
+
+ if (FAS.getReferencedFunction() &&
+ FAS.getReferencedFunction()->hasSemanticsAttr(
+ "pair_no_escaping_closure") &&
+ ((FAS.hasIndirectResults() && FAS.getNumArguments() == 4) ||
+ (!FAS.hasIndirectResults() && FAS.getNumArguments() == 3)) &&
+ FAS.hasSelfArgument()) {
+ // The programmer has guaranteed that the closure will not capture the
+ // self pointer passed to it or anything that is transitively reachable
+ // from the pointer.
+ auto Args = FAS.getArgumentsWithoutIndirectResults();
+ // The second not indirect result argument is the closure.
+ setEscapesGlobal(ConGraph, Args[1]);
+ return;
+ }
+
if (RecursionDepth < MaxRecursionDepth) {
CalleeList Callees = BCA->getCalleeList(FAS);
if (Callees.allCalleesVisible()) {
diff --git a/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp b/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp
index 4a5d0f5..5420b9d 100644
--- a/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp
+++ b/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp
@@ -40,6 +40,7 @@
bool HasChanged = false;
typedef SmallVector<SILInstruction *, 8> Instructions;
+ typedef SmallVector<VarDecl *, 4> Properties;
// Map each let property to a set of instructions accessing it.
llvm::MapVector<VarDecl *, Instructions> AccessMap;
@@ -48,8 +49,15 @@
// Properties in this set should not be processed by this pass
// anymore.
llvm::SmallPtrSet<VarDecl *, 16> SkipProcessing;
+ // Types in this set should not be processed by this pass
+ // anymore.
+ llvm::SmallPtrSet<NominalTypeDecl *, 16> SkipTypeProcessing;
// Properties in this set cannot be removed.
llvm::SmallPtrSet<VarDecl *, 16> CannotRemove;
+ // Set of let propeties in a given nominal type.
+ llvm::MapVector<NominalTypeDecl *, Properties> NominalTypeLetProperties;
+ // Set of properties whose initializer functions were processed already.
+ llvm::SmallPtrSet<VarDecl *, 16> ProcessedPropertyInitializers;
public:
LetPropertiesOpt(SILModule *M): Module(M) {}
@@ -59,10 +67,12 @@
protected:
bool isConstantLetProperty(VarDecl *Property);
void collectPropertyAccess(SILInstruction *I, VarDecl *Property, bool NonRemovable);
+ void collectStructPropertiesAccess(StructInst *SI, bool NonRemovable);
void optimizeLetPropertyAccess(VarDecl *SILG,
SmallVectorImpl<SILInstruction *> &Init);
bool getInitializer(NominalTypeDecl *NTD, VarDecl *Property,
SmallVectorImpl<SILInstruction *> &Init);
+ bool analyzeInitValue(SILInstruction *I, VarDecl *Prop);
};
/// Helper class to copy only a set of SIL instructions providing in the
@@ -120,9 +130,12 @@
return;
auto *Ty = dyn_cast<NominalTypeDecl>(Property->getDeclContext());
- DEBUG(llvm::dbgs() << "Replacing access to property "
+ if (SkipTypeProcessing.count(Ty))
+ return;
+
+ DEBUG(llvm::dbgs() << "Replacing access to property '"
<< Ty->getName() << "::" << Property->getName()
- << " by its constant initializer\n");
+ << "' by its constant initializer\n");
auto PropertyAccess = Property->getEffectiveAccess();
auto TypeAccess = Ty->getEffectiveAccess();
@@ -137,9 +150,9 @@
PropertyAccess == Accessibility::Internal) &&
Module->isWholeModule())) {
CanRemove = true;
- DEBUG(llvm::dbgs() << "Storage for property "
+ DEBUG(llvm::dbgs() << "Storage for property '"
<< Ty->getName() << "::" << Property->getName()
- << " can be eliminated\n");
+ << "' can be eliminated\n");
}
if (CannotRemove.count(Property))
@@ -288,6 +301,55 @@
return ResultValue;
}
+// Find a statically known constant init value stored by the
+// instruction into a property.
+SILValue findStoredValue(SILInstruction *I, VarDecl *Property,
+ SmallVectorImpl<SILInstruction *> &Insns) {
+ SILValue ResultValue;
+
+ if (auto *SI = dyn_cast<StructInst>(I)) {
+ auto Value = SI->getFieldValue(Property);
+ SmallVector<SILInstruction *, 8> ReverseInsns;
+ if (!analyzeStaticInitializer(Value, ReverseInsns))
+ return SILValue();
+ // Produce a correct order of instructions.
+ while (!ReverseInsns.empty()) {
+ Insns.push_back(ReverseInsns.pop_back_val());
+ }
+ return Value;
+ }
+
+ if (auto *SI = dyn_cast<StoreInst>(I)) {
+ auto Dest = SI->getDest();
+
+ // Is it a store to a required property?
+ if (auto *REAI = dyn_cast<RefElementAddrInst>(Dest))
+ if (REAI->getField() != Property)
+ return SILValue();
+
+ if (auto *SEAI = dyn_cast<StructElementAddrInst>(Dest))
+ if (SEAI->getField() != Property)
+ return SILValue();
+
+ // Bail, if it is not the only assignment to the
+ // required property.
+ if (ResultValue)
+ return SILValue();
+
+ auto Value = SI->getSrc();
+ SmallVector<SILInstruction *, 8> ReverseInsns;
+ if (!analyzeStaticInitializer(Value, ReverseInsns))
+ return SILValue();
+ // Produce a correct order of instructions.
+ while (!ReverseInsns.empty()) {
+ Insns.push_back(ReverseInsns.pop_back_val());
+ }
+ ResultValue = Value;
+ }
+
+ return ResultValue;
+}
+
/// Try to find a sequence of instructions which initializes
/// a given property \p Property with a constant value.
/// If all initializers of a type enclosing this property
@@ -301,6 +363,11 @@
// Iterate over all initializers of this struct and check
// if a given property is initialized in the same way.
+ // Analyze initializers only once.
+ if (ProcessedPropertyInitializers.count(Property))
+ return !Insns.empty();
+ ProcessedPropertyInitializers.insert(Property);
+
SmallVector<SmallVector<SILInstruction *, 8>, 4> ConstrPropertyInit;
SILFunction *Init = nullptr;
@@ -333,8 +400,8 @@
// Check that all collected instruction sequences are equivalent.
for(int i = 1, e = ConstrPropertyInit.size(); i < e; i++) {
if (!compareInsnSequences(ConstrPropertyInit[i-1], ConstrPropertyInit[i])) {
- DEBUG(llvm::dbgs() << "Not all initializers are the same for "
- << Property->getNameStr() << "\n");
+ DEBUG(llvm::dbgs() << "Not all initializers are the same for '"
+ << Property->getNameStr() << "'\n");
return false;
}
}
@@ -342,8 +409,16 @@
if (ConstrPropertyInit.empty())
return false;
- DEBUG(llvm::dbgs() << "All initializers are the same for "
- << Property->getNameStr() << "\n");
+ // If we have seen an initialization of this property elsewhere outside of
+ // initializers, check that initializers produce the same value.
+ if (!Insns.empty() && !compareInsnSequences(Insns, ConstrPropertyInit[0])) {
+ DEBUG(llvm::dbgs() << "Not all initializers are the same for '"
+ << Property->getNameStr() << "'\n");
+ return false;
+ }
+
+ DEBUG(llvm::dbgs() << "All initializers are the same for '"
+ << Property->getNameStr() << "' so far\n");
Insns = ConstrPropertyInit[0];
return true;
@@ -357,9 +432,6 @@
return false;
// Do not re-process already known properties.
- if (InitMap.count(Property))
- return true;
-
if (SkipProcessing.count(Property))
return false;
@@ -373,7 +445,7 @@
bool Init = false;
- if (Ty) {
+ if (Ty && !SkipTypeProcessing.count(Ty)) {
if (StructDecl *SD = dyn_cast<StructDecl>(Ty)) {
Init = getInitializer(SD, Property, InitMap[Property]);
}
@@ -392,10 +464,114 @@
return true;
}
+// Analyze the init value being stored by the instruction into a property.
+bool
+LetPropertiesOpt::analyzeInitValue(SILInstruction *I, VarDecl *Prop) {
+ SmallVector<SILInstruction *, 8> Insns;
+ if (!findStoredValue(I, Prop, Insns)) {
+ // The value of a property is not a statically known constant init.
+ return false;
+ }
+ auto &InitInsns = InitMap[Prop];
+ if (!InitInsns.empty() && !compareInsnSequences(InitInsns, Insns)) {
+ // The found init value is different from the already seen init value.
+ return false;
+ } else {
+ DEBUG(llvm::dbgs() << "The value of property '" << Prop->getName()
+ << "' is statically known so far\n");
+ // Remember the statically known value.
+ InitInsns = Insns;
+ return true;
+ }
+}
+
+// Analyze the 'struct' instruction and check if it initializes
+// any let properties by statically known constant initializers.
+void LetPropertiesOpt::collectStructPropertiesAccess(StructInst *SI,
+ bool NonRemovable) {
+ auto structDecl = SI->getStructDecl();
+ // Check if this struct has any let properties.
+
+ // Bail, if this struct is known to contain nothing interesting.
+ if (SkipTypeProcessing.count(structDecl))
+ return;
+
+ // Get the set of let properties defined by this struct.
+ if (!NominalTypeLetProperties.count(structDecl)) {
+ // Compute the let properties of this struct.
+ SmallVector<VarDecl *, 4> LetProps;
+
+ for (auto Prop : structDecl->getStoredProperties()) {
+ if (!isConstantLetProperty(Prop))
+ continue;
+ LetProps.push_back(Prop);
+ }
+
+ if (LetProps.empty()) {
+ // No interesting let propeties in this struct.
+ SkipTypeProcessing.insert(structDecl);
+ return;
+ }
+
+ NominalTypeLetProperties[structDecl] = LetProps;
+ DEBUG(llvm::dbgs() << "Computed set of let properties for struct '"
+ << structDecl->getName() << "'\n");
+ }
+
+ auto &Props = NominalTypeLetProperties[structDecl];
+
+ DEBUG(llvm::dbgs()
+ << "Found a struct instruction intializing some let properties: ";
+ SI->dumpInContext());
+ // Figure out the initializing sequence for each
+ // of the properties.
+ for (auto Prop : Props) {
+ if (SkipProcessing.count(Prop))
+ continue;
+ SILValue PropValue = SI->getOperandForField(Prop)->get();
+ DEBUG(llvm::dbgs() << "Check the value of property '" << Prop->getName()
+ << "' :" << PropValue << "\n");
+ if (!analyzeInitValue(SI, Prop)) {
+ SkipProcessing.insert(Prop);
+ DEBUG(llvm::dbgs() << "The value of a let propertiy '"
+ << structDecl->getName() << "::" << Prop->getName()
+ << "' is not statically known\n");
+ }
+ }
+}
+
/// Remember where this property is accessed.
void LetPropertiesOpt::collectPropertyAccess(SILInstruction *I,
VarDecl *Property,
bool NonRemovable) {
+ if (!isConstantLetProperty(Property))
+ return;
+
+ DEBUG(llvm::dbgs()
+ << "Collecting propery access for property '"
+ << dyn_cast<NominalTypeDecl>(Property->getDeclContext())->getName()
+ << "::" << Property->getName() << "':\n";
+ llvm::dbgs() << "The instructions are:\n"; I->dumpInContext());
+
+ if (isa<RefElementAddrInst>(I) || isa<StructElementAddrInst>(I)) {
+ // Check if there is a store to this property.
+ for (auto UI = I->use_begin(), E = I->use_end(); UI != E;) {
+ auto *User = UI->getUser();
+ ++UI;
+ if (!isa<StoreInst>(User))
+ continue;
+ auto *SI = cast<StoreInst>(User);
+ if (SI->getDest() != I)
+ continue;
+ // There is a store into this property.
+ // Analyze the assigned value.
+ if(!analyzeInitValue(SI, Property)) {
+ SkipProcessing.insert(Property);
+ return;
+ }
+ }
+ }
+
AccessMap[Property].push_back(I);
// If any property is marked as non-removable, their initialization
// and storage cannot be completely removed. But their constant
@@ -415,18 +591,17 @@
for (auto &BB : F) {
for (auto &I : BB)
// Look for any instructions accessing let properties.
+ // It includes referencing this specific property (both reads and
+ // stores), as well as implicit stores by means of e.g.
+ // a struct instruction.
if (auto *REAI = dyn_cast<RefElementAddrInst>(&I)) {
- if (!isConstantLetProperty(REAI->getField()))
- continue;
collectPropertyAccess(REAI, REAI->getField(), NonRemovable);
} else if (auto *SEI = dyn_cast<StructExtractInst>(&I)) {
- if (!isConstantLetProperty(SEI->getField()))
- continue;
collectPropertyAccess(SEI, SEI->getField(), NonRemovable);
} else if (auto *SEAI = dyn_cast<StructElementAddrInst>(&I)) {
- if (!isConstantLetProperty(SEAI->getField()))
- continue;
collectPropertyAccess(SEAI, SEAI->getField(), NonRemovable);
+ } else if (auto *SI = dyn_cast<StructInst>(&I)) {
+ collectStructPropertiesAccess(SI, NonRemovable);
}
}
}
diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp
index 3984d9a..5d0849d 100644
--- a/lib/Sema/TypeCheckAttr.cpp
+++ b/lib/Sema/TypeCheckAttr.cpp
@@ -79,6 +79,7 @@
IGNORED_ATTR(Testable)
IGNORED_ATTR(UIApplicationMain)
IGNORED_ATTR(UnsafeNoObjCTaggedPointer)
+ IGNORED_ATTR(Versioned)
IGNORED_ATTR(WarnUnusedResult)
IGNORED_ATTR(ShowInInterface)
#undef IGNORED_ATTR
@@ -652,6 +653,9 @@
IGNORED_ATTR(Testable)
IGNORED_ATTR(WarnUnqualifiedAccess)
IGNORED_ATTR(ShowInInterface)
+
+ // FIXME: We actually do have things to enforce for versioned API.
+ IGNORED_ATTR(Versioned)
#undef IGNORED_ATTR
void visitAvailableAttr(AvailableAttr *attr);
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index a3a7aa3..3cfd7b9 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -5084,6 +5084,7 @@
UNINTERESTING_ATTR(Semantics)
UNINTERESTING_ATTR(SetterAccessibility)
UNINTERESTING_ATTR(UIApplicationMain)
+ UNINTERESTING_ATTR(Versioned)
UNINTERESTING_ATTR(ObjCNonLazyRealization)
UNINTERESTING_ATTR(UnsafeNoObjCTaggedPointer)
UNINTERESTING_ATTR(SwiftNativeObjCRuntimeBase)
diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp
index e32b05f..26e6f40 100644
--- a/lib/Serialization/SerializeSIL.cpp
+++ b/lib/Serialization/SerializeSIL.cpp
@@ -157,10 +157,14 @@
uint32_t /*DeclID*/ NextDefaultWitnessTableID = 1;
/// Give each SILBasicBlock a unique ID.
- llvm::DenseMap<const SILBasicBlock*, unsigned> BasicBlockMap;
+ llvm::DenseMap<const SILBasicBlock *, unsigned> BasicBlockMap;
- /// Functions that we've emitted a reference to.
- llvm::SmallSet<const SILFunction *, 16> FuncsToDeclare;
+ /// Functions that we've emitted a reference to. If the key maps
+ /// to true, we want to emit a declaration only.
+ llvm::DenseMap<const SILFunction *, bool> FuncsToEmit;
+
+ /// Additional functions we might need to serialize.
+ llvm::SmallVector<const SILFunction *, 16> Worklist;
std::array<unsigned, 256> SILAbbrCodes;
template <typename Layout>
@@ -175,6 +179,12 @@
bool ShouldSerializeAll;
+ void addMandatorySILFunction(const SILFunction *F,
+ bool emitDeclarationsForOnoneSupport);
+ void addReferencedSILFunction(const SILFunction *F,
+ bool DeclOnly = false);
+ void processSILFunctionWorklist();
+
/// Helper function to update ListOfValues for MethodInst. Format:
/// Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC), and an operand.
void handleMethodInst(const MethodInst *MI, SILValue operand,
@@ -207,7 +217,7 @@
/// Helper function to determine if given the current state of the
/// deserialization if the function body for F should be deserialized.
- bool shouldEmitFunctionBody(const SILFunction &F);
+ bool shouldEmitFunctionBody(const SILFunction *F);
public:
SILSerializer(Serializer &S, ASTContext &Ctx,
@@ -218,6 +228,69 @@
};
} // end anonymous namespace
+void SILSerializer::addMandatorySILFunction(const SILFunction *F,
+ bool emitDeclarationsForOnoneSupport) {
+ // If this function is not fragile, don't do anything.
+ if (!shouldEmitFunctionBody(F))
+ return;
+
+ auto iter = FuncsToEmit.find(F);
+ if (iter != FuncsToEmit.end()) {
+ // We've already visited this function. Make sure that we decided
+ // to emit its body the first time around.
+ assert(iter->second == emitDeclarationsForOnoneSupport
+ && "Already emitting declaration");
+ return;
+ }
+
+ // We haven't seen this function before. Record that we want to
+ // emit its body, and add it to the worklist.
+ FuncsToEmit[F] = emitDeclarationsForOnoneSupport;
+ if (!emitDeclarationsForOnoneSupport)
+ Worklist.push_back(F);
+}
+
+void SILSerializer::addReferencedSILFunction(const SILFunction *F,
+ bool DeclOnly) {
+ assert(F != nullptr);
+
+ if (FuncsToEmit.count(F) > 0)
+ return;
+
+ // We haven't seen this function before. Let's see if we should
+ // serialize the body or just the declaration.
+ if (shouldEmitFunctionBody(F)) {
+ FuncsToEmit[F] = false;
+ Worklist.push_back(F);
+ return;
+ }
+
+ // If we referenced a non-fragile shared function from a fragile
+ // function, serialize it too. In practice, it will either be a
+ // thunk, or an optimizer specialization. In both cases, we don't
+ // have enough information at the time we emit the function to
+ // know if it should be marked fragile or not.
+ if (F->getLinkage() == SILLinkage::Shared && !DeclOnly) {
+ FuncsToEmit[F] = false;
+ Worklist.push_back(F);
+ return;
+ }
+
+ // Ok, we just need to emit a declaration.
+ FuncsToEmit[F] = true;
+}
+
+void SILSerializer::processSILFunctionWorklist() {
+ while(Worklist.size() > 0) {
+ const SILFunction *F = Worklist.back();
+ Worklist.pop_back();
+ assert(F != nullptr);
+
+ assert(FuncsToEmit.count(F) > 0);
+ writeSILFunction(*F, FuncsToEmit[F]);
+ }
+}
+
/// We enumerate all values in a SILFunction beforehand to correctly
/// handle forward references of values.
ValueID SILSerializer::addValueRef(const ValueBase *Val) {
@@ -943,7 +1016,7 @@
S.addIdentifierRef(Ctx.getIdentifier(ReferencedFunction->getName())));
// Make sure we declare the referenced function.
- FuncsToDeclare.insert(ReferencedFunction);
+ addReferencedSILFunction(ReferencedFunction);
break;
}
case ValueKind::DeallocPartialRefInst:
@@ -1558,7 +1631,7 @@
for (auto &entry : vt.getEntries()) {
SmallVector<ValueID, 4> ListOfValues;
handleSILDeclRef(S, entry.first, ListOfValues);
- FuncsToDeclare.insert(entry.second);
+ addReferencedSILFunction(entry.second, true);
// Each entry is a pair of SILDeclRef and SILFunction.
VTableEntryLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[VTableEntryLayout::Code],
@@ -1619,9 +1692,9 @@
auto &methodWitness = entry.getMethodWitness();
SmallVector<ValueID, 4> ListOfValues;
handleSILDeclRef(S, methodWitness.Requirement, ListOfValues);
- FuncsToDeclare.insert(methodWitness.Witness);
IdentifierID witnessID = 0;
if (SILFunction *witness = methodWitness.Witness) {
+ addReferencedSILFunction(witness, true);
witnessID = S.addIdentifierRef(Ctx.getIdentifier(witness->getName()));
}
WitnessMethodEntryLayout::emitRecord(Out, ScratchRecord,
@@ -1656,7 +1729,7 @@
SmallVector<ValueID, 4> ListOfValues;
handleSILDeclRef(S, entry.getRequirement(), ListOfValues);
SILFunction *witness = entry.getWitness();
- FuncsToDeclare.insert(witness);
+ addReferencedSILFunction(witness, true);
IdentifierID witnessID = S.addIdentifierRef(
Ctx.getIdentifier(witness->getName()));
DefaultWitnessTableEntryLayout::emitRecord(Out, ScratchRecord,
@@ -1668,17 +1741,19 @@
}
/// Helper function for whether to emit a function body.
-bool SILSerializer::shouldEmitFunctionBody(const SILFunction &F) {
+bool SILSerializer::shouldEmitFunctionBody(const SILFunction *F) {
+ // If we are asked to serialize everything, go ahead and do it.
+ if (ShouldSerializeAll)
+ return true;
+
// If F is a declaration, it has no body to emit...
- if (F.isExternalDeclaration())
+ if (F->isExternalDeclaration())
return false;
// If F is transparent, we should always emit its body.
- if (F.isFragile())
+ if (F->isFragile())
return true;
- // Otherwise serialize the body of the function only if we are asked to
- // serialize everything.
return false;
}
@@ -1769,29 +1844,33 @@
// Go through all the SILFunctions in SILMod and write out any
// mandatory function bodies.
for (const SILFunction &F : *SILMod) {
- if (shouldEmitFunctionBody(F) || ShouldSerializeAll) {
- if (emitDeclarationsForOnoneSupport) {
- // Only declarations of whitelisted pre-specializations from with
- // public linkage need to be serialized as they will be used
- // by UsePrespecializations pass during -Onone compilation to
- // check for availability of concrete pre-specializations.
- if (!hasPublicVisibility(F.getLinkage()) ||
- !isWhitelistedSpecialization(F.getName()))
- continue;
- }
- writeSILFunction(F, emitDeclarationsForOnoneSupport);
+ if (emitDeclarationsForOnoneSupport) {
+ // Only declarations of whitelisted pre-specializations from with
+ // public linkage need to be serialized as they will be used
+ // by UsePrespecializations pass during -Onone compilation to
+ // check for availability of concrete pre-specializations.
+ if (!hasPublicVisibility(F.getLinkage()) ||
+ !isWhitelistedSpecialization(F.getName()))
+ continue;
}
- }
- if (ShouldSerializeAll)
- return;
+ addMandatorySILFunction(&F, emitDeclarationsForOnoneSupport);
+ processSILFunctionWorklist();
+ }
// Now write function declarations for every function we've
// emitted a reference to without emitting a function body for.
for (const SILFunction &F : *SILMod) {
- if (!shouldEmitFunctionBody(F) && FuncsToDeclare.count(&F))
+ auto iter = FuncsToEmit.find(&F);
+ if (iter != FuncsToEmit.end() && iter->second) {
+ assert((emitDeclarationsForOnoneSupport ||
+ !shouldEmitFunctionBody(&F)) &&
+ "Should have emitted function body earlier");
writeSILFunction(F, true);
+ }
}
+
+ assert(Worklist.empty() && "Did not emit everything in worklist");
}
void SILSerializer::writeSILModule(const SILModule *SILMod) {
diff --git a/stdlib/public/core/String.swift b/stdlib/public/core/String.swift
index 7a20fa4..7aa84dc 100644
--- a/stdlib/public/core/String.swift
+++ b/stdlib/public/core/String.swift
@@ -314,6 +314,11 @@
public func _stdlib_compareNSStringDeterministicUnicodeCollation(
lhs: AnyObject, _ rhs: AnyObject
) -> Int32
+
+@_silgen_name("swift_stdlib_compareNSStringDeterministicUnicodeCollationPtr")
+public func _stdlib_compareNSStringDeterministicUnicodeCollationPointer(
+ lhs: OpaquePointer, _ rhs: OpaquePointer
+) -> Int32
#endif
extension String : Equatable {
@@ -372,6 +377,15 @@
// Note: this operation should be consistent with equality comparison of
// Character.
#if _runtime(_ObjC)
+ if self._core.hasContiguousStorage && rhs._core.hasContiguousStorage {
+ let lhsStr = _NSContiguousString(self._core)
+ let rhsStr = _NSContiguousString(rhs._core)
+ let res = lhsStr._unsafeWithNotEscapedSelfPointerPair(rhsStr) {
+ return Int(
+ _stdlib_compareNSStringDeterministicUnicodeCollationPointer($0, $1))
+ }
+ return res
+ }
return Int(_stdlib_compareNSStringDeterministicUnicodeCollation(
_bridgeToObjectiveCImpl(), rhs._bridgeToObjectiveCImpl()))
#else
@@ -445,12 +459,12 @@
#if _runtime(_ObjC)
@warn_unused_result
-@_silgen_name("swift_stdlib_NSStringNFDHashValue")
-func _stdlib_NSStringNFDHashValue(str: AnyObject) -> Int
+@_silgen_name("swift_stdlib_NSStringHashValue")
+func _stdlib_NSStringHashValue(str: AnyObject, _ isASCII: Bool) -> Int
@warn_unused_result
-@_silgen_name("swift_stdlib_NSStringASCIIHashValue")
-func _stdlib_NSStringASCIIHashValue(str: AnyObject) -> Int
+@_silgen_name("swift_stdlib_NSStringHashValuePointer")
+func _stdlib_NSStringHashValuePointer(str: OpaquePointer, _ isASCII: Bool) -> Int
#endif
extension String : Hashable {
@@ -470,16 +484,18 @@
#else
let hashOffset = Int(bitPattern: 0x429b_1266_88dd_cc21)
#endif
- // FIXME(performance): constructing a temporary NSString is extremely
- // wasteful and inefficient.
- let cocoaString = unsafeBitCast(
- self._bridgeToObjectiveCImpl(), to: _NSStringCore.self)
-
- // If we have an ASCII string, we do not need to normalize.
- if self._core.isASCII {
- return hashOffset ^ _stdlib_NSStringASCIIHashValue(cocoaString)
+ // If we have a contigous string then we can use the stack optimization.
+ let core = self._core
+ let isASCII = core.isASCII
+ if core.hasContiguousStorage {
+ let stackAllocated = _NSContiguousString(core)
+ return hashOffset ^ stackAllocated._unsafeWithNotEscapedSelfPointer {
+ return _stdlib_NSStringHashValuePointer($0, isASCII )
+ }
} else {
- return hashOffset ^ _stdlib_NSStringNFDHashValue(cocoaString)
+ let cocoaString = unsafeBitCast(
+ self._bridgeToObjectiveCImpl(), to: _NSStringCore.self)
+ return hashOffset ^ _stdlib_NSStringHashValue(cocoaString, isASCII)
}
#else
if self._core.isASCII {
diff --git a/stdlib/public/core/StringBridge.swift b/stdlib/public/core/StringBridge.swift
index db0ea9b..b14b991 100644
--- a/stdlib/public/core/StringBridge.swift
+++ b/stdlib/public/core/StringBridge.swift
@@ -269,6 +269,39 @@
return self
}
+ /// The caller of this function guarantees that the closure 'body' does not
+ /// escape the object referenced by the opaque pointer passed to it or
+ /// anything transitively reachable form this object. Doing so
+ /// will result in undefined behavior.
+ @_semantics("self_no_escaping_closure")
+ func _unsafeWithNotEscapedSelfPointer<Result>(
+ @noescape body: (OpaquePointer) throws -> Result
+ ) rethrows -> Result {
+ let selfAsPointer = unsafeBitCast(self, to: OpaquePointer.self)
+ defer {
+ _fixLifetime(self)
+ }
+ return try body(selfAsPointer)
+ }
+
+ /// The caller of this function guarantees that the closure 'body' does not
+ /// escape either object referenced by the opaque pointer pair passed to it or
+ /// transitively reachable objects. Doing so will result in undefined
+ /// behavior.
+ @_semantics("pair_no_escaping_closure")
+ func _unsafeWithNotEscapedSelfPointerPair<Result>(
+ rhs: _NSContiguousString,
+ @noescape body: (OpaquePointer, OpaquePointer) throws -> Result
+ ) rethrows -> Result {
+ let selfAsPointer = unsafeBitCast(self, to: OpaquePointer.self)
+ let rhsAsPointer = unsafeBitCast(rhs, to: OpaquePointer.self)
+ defer {
+ _fixLifetime(self)
+ _fixLifetime(rhs)
+ }
+ return try body(selfAsPointer, rhsAsPointer)
+ }
+
public let _core: _StringCore
}
diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp
index 8d95af3..2f1f0be 100644
--- a/stdlib/public/runtime/Metadata.cpp
+++ b/stdlib/public/runtime/Metadata.cpp
@@ -243,11 +243,28 @@
pattern->AddressPoint;
auto patternMetadata = reinterpret_cast<const ValueMetadata*>(patternBytes);
metadata->Description = patternMetadata->Description.get();
- metadata->Parent = patternMetadata->Parent;
+ metadata->Parent = patternMetadata->Parent.get();
return metadata;
}
+/// Entrypoint for non-generic types with resilient layout.
+const Metadata *
+swift::swift_getResilientMetadata(GenericMetadata *pattern) {
+ assert(pattern->NumKeyArguments == 0);
+
+ auto entry = getCache(pattern).findOrAdd(nullptr, 0,
+ [&]() -> GenericCacheEntry* {
+ // Create new metadata to cache.
+ auto metadata = pattern->CreateFunction(pattern, nullptr);
+ auto entry = GenericCacheEntry::getFromMetadata(pattern, metadata);
+ entry->Value = metadata;
+ return entry;
+ });
+
+ return entry->Value;
+}
+
/// The primary entrypoint.
SWIFT_RT_ENTRY_VISIBILITY
const Metadata *
@@ -1456,13 +1473,8 @@
}
#endif
-/// Initialize the invariant superclass components of a class metadata,
-/// such as the generic type arguments, field offsets, and so on.
-///
-/// This may also relocate the metadata object if it wasn't allocated
-/// with enough space.
-static ClassMetadata *_swift_initializeSuperclass(ClassMetadata *theClass,
- bool copyFieldOffsetVectors) {
+static void _swift_initializeSuperclass(ClassMetadata *theClass,
+ bool copyFieldOffsetVectors) {
#if SWIFT_OBJC_INTEROP
// If the class is generic, we need to give it a name for Objective-C.
if (theClass->getDescription()->GenericParams.isGeneric())
@@ -1471,43 +1483,7 @@
const ClassMetadata *theSuperclass = theClass->SuperClass;
if (theSuperclass == nullptr)
- return theClass;
-
- // Relocate the metadata if necessary.
- //
- // For now, we assume that relocation is only required when the parent
- // class has prefix matter we didn't know about. This isn't consistent
- // with general class resilience, however.
- if (theSuperclass->isTypeMetadata()) {
- auto superAP = theSuperclass->getClassAddressPoint();
- auto oldClassAP = theClass->getClassAddressPoint();
- if (superAP > oldClassAP) {
- size_t extraPrefixSize = superAP - oldClassAP;
- size_t oldClassSize = theClass->getClassSize();
-
- // Allocate a new metadata object.
- auto rawNewClass = (char*) malloc(extraPrefixSize + oldClassSize);
- auto rawOldClass = (const char*) theClass;
- auto rawSuperclass = (const char*) theSuperclass;
-
- // Copy the extra prefix from the superclass.
- memcpy((void**) (rawNewClass),
- (void* const *) (rawSuperclass - superAP),
- extraPrefixSize);
- // Copy the rest of the data from the derived class.
- memcpy((void**) (rawNewClass + extraPrefixSize),
- (void* const *) (rawOldClass - oldClassAP),
- oldClassSize);
-
- // Update the class extents on the new metadata object.
- theClass = reinterpret_cast<ClassMetadata*>(rawNewClass + oldClassAP);
- theClass->setClassAddressPoint(superAP);
- theClass->setClassSize(extraPrefixSize + oldClassSize);
-
- // The previous metadata should be global data, so we have no real
- // choice but to drop it on the floor.
- }
- }
+ return;
// If any ancestor classes have generic parameters or field offset
// vectors, inherit them.
@@ -1552,24 +1528,15 @@
= (const ClassMetadata *)object_getClass((id)theSuperclass);
theMetaclass->SuperClass = theSuperMetaclass;
#endif
-
- return theClass;
-}
-
-static MetadataAllocator &getResilientMetadataAllocator() {
- // This should be constant-initialized, but this is safe.
- static MetadataAllocator allocator;
- return allocator;
}
/// Initialize the field offset vector for a dependent-layout class, using the
/// "Universal" layout strategy.
-ClassMetadata *
-swift::swift_initClassMetadata_UniversalStrategy(ClassMetadata *self,
- size_t numFields,
- const ClassFieldLayout *fieldLayouts,
- size_t *fieldOffsets) {
- self = _swift_initializeSuperclass(self, /*copyFieldOffsetVectors=*/true);
+void swift::swift_initClassMetadata_UniversalStrategy(ClassMetadata *self,
+ size_t numFields,
+ const ClassFieldLayout *fieldLayouts,
+ size_t *fieldOffsets) {
+ _swift_initializeSuperclass(self, /*copyFieldOffsetVectors=*/true);
// Start layout by appending to a standard heap object header.
size_t size, alignMask;
@@ -1658,10 +1625,9 @@
// even if Swift doesn't, because of SwiftObject.)
rodata->InstanceStart = size;
- auto genericPattern = self->getDescription()->getGenericMetadataPattern();
- auto &allocator =
- genericPattern ? unsafeGetInitializedCache(genericPattern).getAllocator()
- : getResilientMetadataAllocator();
+ auto &allocator = unsafeGetInitializedCache(
+ self->getDescription()->getGenericMetadataPattern())
+ .getAllocator();
// Always clone the ivar descriptors.
if (numFields) {
@@ -1737,8 +1703,6 @@
}
}
#endif
-
- return self;
}
/// \brief Fetch the type metadata associated with the formal dynamic
@@ -2496,6 +2460,19 @@
}
#endif
+SWIFT_RUNTIME_EXPORT
+extern "C"
+void swift_initializeSuperclass(ClassMetadata *theClass,
+ bool copyFieldOffsetVectors) {
+ // Copy generic parameters and field offset vectors from the superclass.
+ _swift_initializeSuperclass(theClass, copyFieldOffsetVectors);
+
+#if SWIFT_OBJC_INTEROP
+ // Register the class pair with the ObjC runtime.
+ swift_instantiateObjCClass(theClass);
+#endif
+}
+
/*** Protocol witness tables *************************************************/
namespace {
diff --git a/stdlib/public/runtime/MetadataCache.h b/stdlib/public/runtime/MetadataCache.h
index 0324037..a2a2344 100644
--- a/stdlib/public/runtime/MetadataCache.h
+++ b/stdlib/public/runtime/MetadataCache.h
@@ -26,31 +26,6 @@
namespace swift {
-/// A bump pointer for metadata allocations. Since metadata is (currently)
-/// never released, it does not support deallocation. This allocator by itself
-/// is not thread-safe; in concurrent uses, allocations must be guarded by
-/// a lock, such as the per-metadata-cache lock used to guard metadata
-/// instantiations. All allocations are pointer-aligned.
-class MetadataAllocator {
- /// Address of the next available space. The allocator grabs a page at a time,
- /// so the need for a new page can be determined by page alignment.
- ///
- /// Initializing to -1 instead of nullptr ensures that the first allocation
- /// triggers a page allocation since it will always span a "page" boundary.
- char *next = (char*)(~(uintptr_t)0U);
-
-public:
- constexpr MetadataAllocator() = default;
-
- // Don't copy or move, please.
- MetadataAllocator(const MetadataAllocator &) = delete;
- MetadataAllocator(MetadataAllocator &&) = delete;
- MetadataAllocator &operator=(const MetadataAllocator &) = delete;
- MetadataAllocator &operator=(MetadataAllocator &&) = delete;
-
- void *alloc(size_t size);
-};
-
// A wrapper around a pointer to a metadata cache entry that provides
// DenseMap semantics that compare values in the key vector for the metadata
// instance.
diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp
index 632f4e8..c3425ee 100644
--- a/stdlib/public/runtime/MetadataLookup.cpp
+++ b/stdlib/public/runtime/MetadataLookup.cpp
@@ -220,10 +220,11 @@
if (ntd == nullptr || ntd->Name.get() != typeName)
return nullptr;
- // Call the accessor if there is one.
- if (metadata == nullptr && !ntd->GenericParams.isGeneric()) {
- if (auto accessFn = ntd->getAccessFunction())
- accessFn();
+ // Instantiate resilient types.
+ if (metadata == nullptr &&
+ ntd->getGenericMetadataPattern() &&
+ !ntd->GenericParams.isGeneric()) {
+ return swift_getResilientMetadata(ntd->getGenericMetadataPattern());
}
return metadata;
diff --git a/stdlib/public/runtime/Reflection.mm b/stdlib/public/runtime/Reflection.mm
index f4e8775..3c8e8d3 100644
--- a/stdlib/public/runtime/Reflection.mm
+++ b/stdlib/public/runtime/Reflection.mm
@@ -390,18 +390,7 @@
auto isa = _swift_getClass(object);
return swift_getObjCClassMetadata(isa);
}
-
-// -- Tuple destructuring.
-
-SWIFT_RUNTIME_STDLIB_INTERFACE
-extern "C"
-intptr_t swift_TupleMirror_count(HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type) {
- auto Tuple = static_cast<const TupleTypeMetadata *>(type);
- return Tuple->NumElements;
-}
-
+
static std::tuple<const _ReflectableWitnessTable *, const Metadata *,
const OpaqueValue *>
getReflectableConformance(const Metadata *T, const OpaqueValue *Value) {
@@ -497,7 +486,18 @@
::new (&result) MagicMirror(owner, mirrorValue, mirrorType);
return result;
}
+
+// -- Tuple destructuring.
+SWIFT_RUNTIME_STDLIB_INTERFACE
+extern "C"
+intptr_t swift_TupleMirror_count(HeapObject *owner,
+ const OpaqueValue *value,
+ const Metadata *type) {
+ auto Tuple = static_cast<const TupleTypeMetadata *>(type);
+ return Tuple->NumElements;
+}
+
/// \param owner passed at +1, consumed.
/// \param value passed unowned.
SWIFT_RUNTIME_STDLIB_INTERFACE
diff --git a/stdlib/public/stubs/SwiftNativeNSXXXBase.mm.gyb b/stdlib/public/stubs/SwiftNativeNSXXXBase.mm.gyb
index c5c7e34..ed59f01 100644
--- a/stdlib/public/stubs/SwiftNativeNSXXXBase.mm.gyb
+++ b/stdlib/public/stubs/SwiftNativeNSXXXBase.mm.gyb
@@ -117,22 +117,37 @@
}
SWIFT_RUNTIME_STDLIB_INTERFACE
+extern "C" int32_t
+swift_stdlib_compareNSStringDeterministicUnicodeCollationPtr(void *Lhs,
+ void *Rhs) {
+ NSString *lhs = (NSString *)Lhs;
+ NSString *rhs = (NSString *)Rhs;
+
+ // 'kCFCompareNonliteral' actually means "normalize to NFD".
+ int Result = CFStringCompare((__bridge CFStringRef)lhs,
+ (__bridge CFStringRef)rhs, kCFCompareNonliteral);
+ return Result;
+}
+
+SWIFT_RUNTIME_STDLIB_INTERFACE
extern "C" size_t
-swift_stdlib_NSStringNFDHashValue(NSString *NS_RELEASES_ARGUMENT str) {
- size_t Result = str.decomposedStringWithCanonicalMapping.hash;
+swift_stdlib_NSStringHashValue(NSString *NS_RELEASES_ARGUMENT str,
+ bool isASCII) {
+ size_t Result =
+ isASCII ? str.hash : str.decomposedStringWithCanonicalMapping.hash;
+
swift_unknownRelease(str);
return Result;
}
-// For strings we know only have ASCII
SWIFT_RUNTIME_STDLIB_INTERFACE
extern "C" size_t
-swift_stdlib_NSStringASCIIHashValue(NSString *NS_RELEASES_ARGUMENT str) {
- size_t Result = str.hash;
- swift_unknownRelease(str);
- return Result;
+swift_stdlib_NSStringHashValuePointer(void *opaque, bool isASCII) {
+ NSString *str = (NSString *)opaque;
+ return isASCII ? str.hash : str.decomposedStringWithCanonicalMapping.hash;
}
+
SWIFT_RUNTIME_STDLIB_INTERFACE
extern "C" bool swift_stdlib_NSStringHasPrefixNFD(NSString *theString,
NSString *prefix) {
diff --git a/test/1_stdlib/RuntimeObjC.swift b/test/1_stdlib/RuntimeObjC.swift
index c7d0713..90a1001 100644
--- a/test/1_stdlib/RuntimeObjC.swift
+++ b/test/1_stdlib/RuntimeObjC.swift
@@ -543,22 +543,12 @@
expectEqual(0, nsStringCanaryCount)
}
-RuntimeFoundationWrappers.test("_stdlib_NSStringNFDHashValue/NoLeak") {
+RuntimeFoundationWrappers.test("_stdlib_NSStringHashValue/NoLeak") {
nsStringCanaryCount = 0
autoreleasepool {
let a = NSStringCanary()
expectEqual(1, nsStringCanaryCount)
- _stdlib_NSStringNFDHashValue(a)
- }
- expectEqual(0, nsStringCanaryCount)
-}
-
-RuntimeFoundationWrappers.test("_stdlib_NSStringASCIIHashValue/NoLeak") {
- nsStringCanaryCount = 0
- autoreleasepool {
- let a = NSStringCanary()
- expectEqual(1, nsStringCanaryCount)
- _stdlib_NSStringASCIIHashValue(a)
+ _stdlib_NSStringHashValue(a, true)
}
expectEqual(0, nsStringCanaryCount)
}
diff --git a/test/IRGen/class_resilience.swift b/test/IRGen/class_resilience.swift
index c7514e2..0173cbe 100644
--- a/test/IRGen/class_resilience.swift
+++ b/test/IRGen/class_resilience.swift
@@ -119,14 +119,15 @@
// CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont
// CHECK: cacheIsNull:
-// CHECK-NEXT: call void @swift_once(i64* @_TMaC16class_resilience26ClassWithResilientProperty.once_token, i8* bitcast (void (i8*)* @initialize_metadata_ClassWithResilientProperty to i8*))
-// CHECK-NEXT: [[METADATA:%.*]] = load %swift.type*, %swift.type** @_TMLC16class_resilience26ClassWithResilientProperty
+// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_getResilientMetadata(
+// CHECK-NEXT: store %swift.type* [[METADATA]], %swift.type** @_TMLC16class_resilience26ClassWithResilientProperty
// CHECK-NEXT: br label %cont
// CHECK: cont:
// CHECK-NEXT: [[RESULT:%.*]] = phi %swift.type* [ [[CACHE]], %entry ], [ [[METADATA]], %cacheIsNull ]
// CHECK-NEXT: ret %swift.type* [[RESULT]]
+
// ClassWithResilientProperty.color getter
// CHECK-LABEL: define{{( protected)?}} i32 @_TFC16class_resilience26ClassWithResilientPropertyg5colorVs5Int32(%C16class_resilience26ClassWithResilientProperty*)
@@ -147,8 +148,8 @@
// CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont
// CHECK: cacheIsNull:
-// CHECK-NEXT: call void @swift_once(i64* @_TMaC16class_resilience33ClassWithResilientlySizedProperty.once_token, i8* bitcast (void (i8*)* @initialize_metadata_ClassWithResilientlySizedProperty to i8*))
-// CHECK-NEXT: [[METADATA:%.*]] = load %swift.type*, %swift.type** @_TMLC16class_resilience33ClassWithResilientlySizedProperty
+// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_getResilientMetadata(
+// CHECK-NEXT: store %swift.type* [[METADATA]], %swift.type** @_TMLC16class_resilience33ClassWithResilientlySizedProperty
// CHECK-NEXT: br label %cont
// CHECK: cont:
@@ -223,12 +224,13 @@
// CHECK-NEXT: ret i32 [[RESULT]]
-// ClassWithResilientProperty metadata initialization function
+// ClassWithResilientProperty metadata instantiation function
-// CHECK-LABEL: define{{( protected)?}} private void @initialize_metadata_ClassWithResilientProperty
+// CHECK-LABEL: define{{( protected)?}} private %swift.type* @create_generic_metadata_ClassWithResilientProperty(%swift.type_pattern*, i8**)
+// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(
// CHECK: [[SIZE_METADATA:%.*]] = call %swift.type* @_TMaV16resilient_struct4Size()
-// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_initClassMetadata_UniversalStrategy(
+// CHECK: call void @swift_initClassMetadata_UniversalStrategy(
// CHECK-native: [[METADATA_PTR:%.*]] = bitcast %swift.type* [[METADATA]] to [[INT]]*
// CHECK-native-NEXT: [[FIELD_OFFSET_PTR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_PTR]], [[INT]] {{12|15}}
// CHECK-native-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_PTR]]
@@ -237,15 +239,15 @@
// CHECK-native-NEXT: [[FIELD_OFFSET_PTR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_PTR]], [[INT]] {{13|16}}
// CHECK-native-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_PTR]]
// CHECK-native-NEXT: store [[INT]] [[FIELD_OFFSET]], [[INT]]* @_TWvdvC16class_resilience26ClassWithResilientProperty5colorVs5Int32
-// CHECK: store atomic %swift.type* [[METADATA]], %swift.type** @_TMLC16class_resilience26ClassWithResilientProperty release,
-// CHECK: ret void
+// CHECK: ret %swift.type* [[METADATA]]
-// ClassWithResilientlySizedProperty metadata initialization function
+// ClassWithResilientlySizedProperty metadata instantiation function
-// CHECK-LABEL: define{{( protected)?}} private void @initialize_metadata_ClassWithResilientlySizedProperty
+// CHECK-LABEL: define{{( protected)?}} private %swift.type* @create_generic_metadata_ClassWithResilientlySizedProperty(%swift.type_pattern*, i8**)
+// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(
// CHECK: [[RECTANGLE_METADATA:%.*]] = call %swift.type* @_TMaV16resilient_struct9Rectangle()
-// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_initClassMetadata_UniversalStrategy(
+// CHECK: call void @swift_initClassMetadata_UniversalStrategy(
// CHECK-native: [[METADATA_PTR:%.*]] = bitcast %swift.type* [[METADATA]] to [[INT]]*
// CHECK-native-NEXT: [[FIELD_OFFSET_PTR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_PTR]], [[INT]] {{11|14}}
// CHECK-native-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_PTR]]
@@ -254,6 +256,4 @@
// CHECK-native-NEXT: [[FIELD_OFFSET_PTR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_PTR]], [[INT]] {{12|15}}
// CHECK-native-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_PTR]]
// CHECK-native-NEXT: store [[INT]] [[FIELD_OFFSET]], [[INT]]* @_TWvdvC16class_resilience33ClassWithResilientlySizedProperty5colorVs5Int32
-// CHECK: store atomic %swift.type* [[METADATA]], %swift.type** @_TMLC16class_resilience33ClassWithResilientlySizedProperty release,
-// CHECK: ret void
-
+// CHECK: ret %swift.type* [[METADATA]]
diff --git a/test/IRGen/concrete_inherits_generic_base.swift b/test/IRGen/concrete_inherits_generic_base.swift
index 6d5846c..3f9faa5 100644
--- a/test/IRGen/concrete_inherits_generic_base.swift
+++ b/test/IRGen/concrete_inherits_generic_base.swift
@@ -23,8 +23,8 @@
// CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont
// CHECK: cacheIsNull:
-// CHECK-NEXT: call void @swift_once(i64* @_TMaC3foo12SuperDerived.once_token, i8* bitcast (void (i8*)* @initialize_metadata_SuperDerived to i8*))
-// CHECK-NEXT: [[METADATA:%.*]] = load %swift.type*, %swift.type** @_TMLC3foo12SuperDerived
+// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_getResilientMetadata(
+// CHECK-NEXT: store %swift.type* [[METADATA]], %swift.type** @_TMLC3foo12SuperDerived
// CHECK-NEXT: br label %cont
// CHECK: cont:
// CHECK-NEXT: [[RESULT:%.*]] = phi %swift.type* [ [[CACHE]], %entry ], [ [[METADATA]], %cacheIsNull ]
@@ -39,8 +39,8 @@
// CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont
// CHECK: cacheIsNull:
-// CHECK-NEXT: call void @swift_once(i64* @_TMaC3foo7Derived.once_token, i8* bitcast (void (i8*)* @initialize_metadata_Derived to i8*))
-// CHECK-NEXT: [[METADATA:%.*]] = load %swift.type*, %swift.type** @_TMLC3foo7Derived
+// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_getResilientMetadata(
+// CHECK-NEXT: store %swift.type* [[METADATA]], %swift.type** @_TMLC3foo7Derived
// CHECK-NEXT: br label %cont
// CHECK: cont:
// CHECK-NEXT: [[RESULT:%.*]] = phi %swift.type* [ [[CACHE]], %entry ], [ [[METADATA]], %cacheIsNull ]
@@ -69,9 +69,9 @@
presentBase(Base(x: "two"))
presentBase(Base(x: 2))
-// CHECK-LABEL: define{{( protected)?}} private void @initialize_metadata_SuperDerived(i8*)
+// CHECK-LABEL: define{{( protected)?}} private %swift.type* @create_generic_metadata_SuperDerived(%swift.type_pattern*, i8**)
// CHECK: [[TMP:%.*]] = call %swift.type* @_TMaC3foo7Derived()
-// CHECK-NEXT: store %swift.type* [[TMP]], %swift.type** getelementptr inbounds ({{.*}} @_TMfC3foo12SuperDerived{{.*}}, i32 1), align
-// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_initClassMetadata_UniversalStrategy(
-// CHECK: store atomic %swift.type* [[METADATA]], %swift.type** @_TMLC3foo12SuperDerived release,
-// CHECK: ret void
+// CHECK-NEXT: [[SUPER:%.*]] = bitcast %swift.type* [[TMP:%.*]] to %objc_class*
+// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_pattern* %0, i8** %1, %objc_class* [[SUPER]])
+// CHECK: call void @swift_initializeSuperclass(%swift.type* [[METADATA]], i1 false)
+// CHECK-NEXT: ret %swift.type* [[METADATA]]
diff --git a/test/IRGen/enum.sil b/test/IRGen/enum.sil
index d4081a6..dc52fb6 100644
--- a/test/IRGen/enum.sil
+++ b/test/IRGen/enum.sil
@@ -2570,8 +2570,8 @@
// CHECK: [[T:%T]] = load %swift.type*, %swift.type** [[T0]],
// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_pattern* %0, i8** %1)
// CHECK: [[METADATA_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8**
-// CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 3
// CHECK: [[T0:%.*]] = bitcast %swift.type* [[T]] to i8*
+// CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 3
// CHECK: store i8* [[T0]], i8** [[T1]]
// CHECK: [[VWT:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 5
// CHECK: [[T0:%.*]] = bitcast i8** [[VWT]] to i8*
@@ -2613,7 +2613,7 @@
// -- Fill function for dynamic single-payload. Call into the runtime to
// calculate the size.
-// CHECK-LABEL: define{{( protected)?}} private %swift.type* @create_generic_metadata_DynamicSinglePayload(%swift.type_pattern*, i8**) {{.*}} {
+// CHECK: define{{( protected)?}} private %swift.type* @create_generic_metadata_DynamicSinglePayload(%swift.type_pattern*, i8**) {{.*}} {
// CHECK: call void @swift_initEnumValueWitnessTableSinglePayload
// CHECK-64-LABEL: define linkonce_odr hidden void @_TwxsV4enum17StructWithWeakVar(%swift.opaque* %dest, i32 %index, %swift.type* %StructWithWeakVar)
diff --git a/test/IRGen/enum_resilience.swift b/test/IRGen/enum_resilience.swift
index 596add6..37c9e51 100644
--- a/test/IRGen/enum_resilience.swift
+++ b/test/IRGen/enum_resilience.swift
@@ -229,12 +229,15 @@
// CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont
// CHECK: cacheIsNull:
-// CHECK-NEXT: call void @swift_once(i64* @_TMaO15enum_resilience24EnumWithResilientPayload.once_token, i8* bitcast (void (i8*)* @initialize_metadata_EnumWithResilientPayload to i8*))
-// CHECK-NEXT: [[METADATA2:%.*]] = load %swift.type*, %swift.type** @_TMLO15enum_resilience24EnumWithResilientPayload
+// CHECK-NEXT: [[METADATA2:%.*]] = call %swift.type* @swift_getResilientMetadata
+// CHECK-NEXT: store %swift.type* [[METADATA2]], %swift.type** @_TMLO15enum_resilience24EnumWithResilientPayload
// CHECK-NEXT: br label %cont
// CHECK: cont:
// CHECK-NEXT: [[RESULT:%.*]] = phi %swift.type* [ [[METADATA]], %entry ], [ [[METADATA2]], %cacheIsNull ]
// CHECK-NEXT: ret %swift.type* [[RESULT]]
-// CHECK-LABEL: define{{( protected)?}} private void @initialize_metadata_EnumWithResilientPayload(i8*)
+
+// FIXME: this is bogus
+
+// CHECK-LABEL: define{{( protected)?}} private %swift.type* @create_generic_metadata_EnumWithResilientPayload(%swift.type_pattern*, i8**)
diff --git a/test/IRGen/enum_value_semantics.sil b/test/IRGen/enum_value_semantics.sil
index ab4eabc..f70c361 100644
--- a/test/IRGen/enum_value_semantics.sil
+++ b/test/IRGen/enum_value_semantics.sil
@@ -122,13 +122,12 @@
// CHECK: ]
-// CHECK-LABEL: @_TMfO20enum_value_semantics20SinglePayloadTrivial =
-// CHECK-SAME: internal constant {{.*}} <{
-// CHECK-SAME: i8** getelementptr inbounds ([26 x i8*], [26 x i8*]* @_TWVO20enum_value_semantics20SinglePayloadTrivial, i32 0, i32 0),
-// CHECK-SAME: i64 2,
-// CHECK-SAME: {{.*}}* @_TMnO20enum_value_semantics20SinglePayloadTrivial
-// CHECK-SAME: %swift.type* null
-// CHECK-SAME: }>
+// CHECK-LABEL: @_TMfO20enum_value_semantics20SinglePayloadTrivial = internal constant <{ {{.*i(32|64)}} }> <{
+// CHECK: i8** getelementptr inbounds ([26 x i8*], [26 x i8*]* @_TWVO20enum_value_semantics20SinglePayloadTrivial, i32 0, i32 0),
+// CHECK: i64 2,
+// CHECK: {{.*}}* @_TMnO20enum_value_semantics20SinglePayloadTrivial
+// CHECK: i64 0
+// CHECK: }>
// CHECK-LABEL: @_TWVO20enum_value_semantics23SinglePayloadNontrivial = {{(protected )?}}constant [26 x i8*] [
@@ -164,13 +163,12 @@
// CHECK: ]
-// CHECK-LABEL: @_TMfO20enum_value_semantics23SinglePayloadNontrivial =
-// CHECK-SAME: internal constant {{.*}} <{
-// CHECK-SAME: i8** getelementptr inbounds ([26 x i8*], [26 x i8*]* @_TWVO20enum_value_semantics23SinglePayloadNontrivial, i32 0, i32 0),
-// CHECK-SAME: i64 2,
-// CHECK-SAME: {{.*}}* @_TMnO20enum_value_semantics23SinglePayloadNontrivial
-// CHECK-SAME: %swift.type* null
-// CHECK-SAME: }>
+// CHECK-LABEL: @_TMfO20enum_value_semantics23SinglePayloadNontrivial = internal constant <{ {{.*i(32|64)}} }> <{
+// CHECK: i8** getelementptr inbounds ([26 x i8*], [26 x i8*]* @_TWVO20enum_value_semantics23SinglePayloadNontrivial, i32 0, i32 0),
+// CHECK: i64 2,
+// CHECK: {{.*}}* @_TMnO20enum_value_semantics23SinglePayloadNontrivial
+// CHECK: i64 0
+// CHECK: }>
// CHECK-LABEL: @_TMPO20enum_value_semantics18GenericFixedLayout = {{(protected )?}}global <{{[{].*\* [}]}}> <{
diff --git a/test/IRGen/generic_classes.sil b/test/IRGen/generic_classes.sil
index ed615cd..0ea9d90 100644
--- a/test/IRGen/generic_classes.sil
+++ b/test/IRGen/generic_classes.sil
@@ -308,11 +308,11 @@
// CHECK: define{{( protected)?}} private %swift.type* @create_generic_metadata_RootGeneric(%swift.type_pattern*, i8**) {{.*}} {
// -- initialize the dependent field offsets
-// CHECK: call %swift.type* @swift_initClassMetadata_UniversalStrategy(%swift.type* {{%.*}}, i64 3, i64* {{%.*}}, i64* {{%.*}})
+// CHECK: call void @swift_initClassMetadata_UniversalStrategy(%swift.type* {{%.*}}, i64 3, i64* {{%.*}}, i64* {{%.*}})
// CHECK: }
// CHECK: define{{( protected)?}} private %swift.type* @create_generic_metadata_RootGenericFixedLayout(%swift.type_pattern*, i8**) {{.*}} {
-// CHECK: call %swift.type* @swift_initClassMetadata_UniversalStrategy(%swift.type* {{%.*}}, i64 3, i64* {{%.*}}, i64* {{%.*}})
+// CHECK: call void @swift_initClassMetadata_UniversalStrategy(%swift.type* {{%.*}}, i64 3, i64* {{%.*}}, i64* {{%.*}})
// CHECK: }
// CHECK: define{{( protected)?}} private %swift.type* @create_generic_metadata_GenericInheritsGeneric(%swift.type_pattern*, i8**) {{.*}} {
@@ -327,11 +327,11 @@
// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_pattern* %0, i8** %1, %objc_class* [[T0]])
// CHECK: [[METADATA_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8**
// Put the generic arguments in their correct positions.
-// CHECK: [[A_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY:%.*]], i32 18
// CHECK: [[T0:%.*]] = bitcast %swift.type* %A to i8*
+// CHECK: [[A_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY:%.*]], i32 18
// CHECK: store i8* [[T0]], i8** [[A_ADDR]], align 8
-// CHECK: [[B_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY:%.*]], i32 19
// CHECK: [[T0:%.*]] = bitcast %swift.type* %B to i8*
+// CHECK: [[B_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY:%.*]], i32 19
// CHECK: store i8* [[T0]], i8** [[B_ADDR]], align 8
// Set up the isa.
// CHECK-objc: [[METADATA_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8**
@@ -370,6 +370,6 @@
// CHECK: store i64 [[SIZE]], i64* [[SIZE_ADDR]], align 8
// CHECK: [[ALIGN_ADDR:%.*]] = getelementptr inbounds [2 x i64], [2 x i64]* [[TYPES]], i32 0, i32 1
// CHECK: store i64 [[ALIGN]], i64* [[ALIGN_ADDR]], align 8
-// CHECK: call %swift.type* @swift_initClassMetadata_UniversalStrategy(%swift.type* [[METADATA]], i64 1, i64* [[SIZE_ADDR]], i64* [[OFFSETS]])
+// CHECK: call void @swift_initClassMetadata_UniversalStrategy(%swift.type* [[METADATA]], i64 1, i64* [[SIZE_ADDR]], i64* [[OFFSETS]])
// CHECK: ret %swift.type* [[METADATA]]
// CHECK: }
diff --git a/test/IRGen/generic_structs.sil b/test/IRGen/generic_structs.sil
index 1f068b9..117ff8f 100644
--- a/test/IRGen/generic_structs.sil
+++ b/test/IRGen/generic_structs.sil
@@ -284,8 +284,8 @@
// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_pattern* %0, i8** %1)
// CHECK: [[SELF_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8**
// Fill type argument.
-// CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 4
// CHECK: [[T0:%.*]] = bitcast %swift.type* %T to i8*
+// CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 4
// CHECK: store i8* [[T0]], i8** [[T1]], align 8
// Fill vwtable reference.
// CHECK: [[VWTABLE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 6
diff --git a/test/IRGen/generic_types.swift b/test/IRGen/generic_types.swift
index 44b57f3..5d277bf 100644
--- a/test/IRGen/generic_types.swift
+++ b/test/IRGen/generic_types.swift
@@ -90,8 +90,8 @@
// CHECK-objc: [[SUPER:%.*]] = call %objc_class* @rt_swift_getInitializedObjCClass(%objc_class* @"OBJC_CLASS_$_SwiftObject")
// CHECK-objc: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_pattern* %0, i8** %1, %objc_class* [[SUPER]])
// CHECK: [[SELF_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8**
-// CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 10
// CHECK: [[T0:%.*]] = bitcast %swift.type* %T to i8*
+// CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 10
// CHECK: store i8* [[T0]], i8** [[T1]], align 8
// CHECK: ret %swift.type* [[METADATA]]
// CHECK: }
@@ -103,8 +103,8 @@
// CHECK-objc: [[SUPER:%.*]] = call %objc_class* @rt_swift_getInitializedObjCClass(%objc_class* @"OBJC_CLASS_$_SwiftObject")
// CHECK-objc: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_pattern* %0, i8** %1, %objc_class* [[SUPER]])
// CHECK: [[SELF_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8**
-// CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 10
// CHECK: [[T0:%.*]] = bitcast %swift.type* %T to i8*
+// CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 10
// CHECK: store i8* [[T0]], i8** [[T1]], align 8
// CHECK: ret %swift.type* [[METADATA]]
// CHECK: }
diff --git a/test/IRGen/nested_types.sil b/test/IRGen/nested_types.sil
deleted file mode 100644
index cfd8ab5..0000000
--- a/test/IRGen/nested_types.sil
+++ /dev/null
@@ -1,38 +0,0 @@
-// RUN: %target-swift-frontend -emit-ir %s | FileCheck %s
-
-sil_stage canonical
-
-import Builtin
-
-class Outer {
- struct Inner {
- }
-}
-
-sil_vtable Outer {}
-
-sil @test0 : $@convention(thin) (@thick Outer.Inner.Type) -> (@thick Outer.Type) {
-bb0(%0 : $@thick Outer.Inner.Type):
- %1 = metatype $@thick Outer.Type
- return %1 : $@thick Outer.Type
-}
-// CHECK-LABEL: define %swift.type* @test0(%swift.type*)
-// TODO: it would be more efficient to get this type from the parent metadata field
-// CHECK: [[T0:%.*]] = call %swift.type* @_TMaC12nested_types5Outer()
-// CHECK-NEXT: ret %swift.type* [[T0]]
-
-// CHECK-LABEL: define %swift.type* @_TMaVC12nested_types5Outer5Inner()
-// CHECK: [[T0:%.*]] = load %swift.type*, %swift.type** @_TMLVC12nested_types5Outer5Inner
-// CHECK-NEXT: [[T1:%.*]] = icmp eq %swift.type* [[T0]], null
-// CHECK-NEXT: br i1 [[T1]]
-// CHECK: call void @swift_once({{.*}}* @_TMaVC12nested_types5Outer5Inner.once_token, i8* bitcast (void (i8*)* @initialize_metadata_Inner to i8*))
-// CHECK-NEXT: [[T2:%.*]] = load %swift.type*, %swift.type** @_TMLVC12nested_types5Outer5Inner
-// CHECK-NEXT: br label
-// CHECK: [[T4:%.*]] = phi %swift.type* [ [[T0]], {{.*}} ], [ [[T2]], {{.*}} ]
-// CHECK-NEXT: ret %swift.type* [[T4]]
-
-// CHECK-LABEL: define private void @initialize_metadata_Inner
-// CHECK: [[T0:%.*]] = call %swift.type* @_TMaC12nested_types5Outer()
-// CHECK-NEXT: store %swift.type* [[T0]], %swift.type** getelementptr inbounds (%swift.type*, %swift.type** bitcast ({{.*}} @_TMfVC12nested_types5Outer5Inner{{.*}}, i64 2), align
-// CHECK-NEXT: store atomic %swift.type* bitcast ({{.*}} @_TMfVC12nested_types5Outer5Inner{{.*}} to %swift.type*), %swift.type** @_TMLVC12nested_types5Outer5Inner release, align
-// CHECK-NEXT: ret void
diff --git a/test/IRGen/protocol_conformance_records.swift b/test/IRGen/protocol_conformance_records.swift
index 43e14bc..eac99ae 100644
--- a/test/IRGen/protocol_conformance_records.swift
+++ b/test/IRGen/protocol_conformance_records.swift
@@ -72,11 +72,11 @@
// -- protocol descriptor
// CHECK: [[RUNCIBLE]]
// -- nominal type descriptor
-// CHECK: @got._TMV16resilient_struct4Size
+// CHECK: @got._TMnV16resilient_struct4Size
// -- witness table
// CHECK: @_TWPurGV28protocol_conformance_records17NativeGenericTypex_S_8RuncibleS_
-// -- flags 0x04: unique direct metadata
-// CHECK: i32 1
+// -- flags 0x04: unique nominal type descriptor
+// CHECK: i32 4
// CHECK: }
// CHECK: ]
diff --git a/test/IRGen/protocol_resilience.sil b/test/IRGen/protocol_resilience.sil
index 9ae9f4e..342639d 100644
--- a/test/IRGen/protocol_resilience.sil
+++ b/test/IRGen/protocol_resilience.sil
@@ -276,7 +276,7 @@
// CHECK: cacheIsNull:
// CHECK: [[WTABLE:%.*]] = call i8** @_TWaV19protocol_resilience23ResilientConformingType18resilient_protocol22OtherResilientProtocolS_()
-// CHECK-NEXT: store atomic i8** [[WTABLE]], i8*** @_TWLV19protocol_resilience23ResilientConformingTypeS0_18resilient_protocol22OtherResilientProtocolS_ release
+// CHECK-NEXT: store i8** [[WTABLE]], i8*** @_TWLV19protocol_resilience23ResilientConformingTypeS0_18resilient_protocol22OtherResilientProtocolS_
// CHECK-NEXT: br label %cont
// CHECK: cont:
diff --git a/test/IRGen/struct_resilience.swift b/test/IRGen/struct_resilience.swift
index d4c3e89..b0f96fa 100644
--- a/test/IRGen/struct_resilience.swift
+++ b/test/IRGen/struct_resilience.swift
@@ -6,7 +6,7 @@
// CHECK: %Si = type <{ [[INT:i32|i64]] }>
-// CHECK-LABEL: @_TMfV17struct_resilience26StructWithResilientStorage = internal constant
+// CHECK-LABEL: @_TMPV17struct_resilience26StructWithResilientStorage = {{(protected )?}}global
// Resilient structs from outside our resilience domain are manipulated via
// value witnesses
@@ -146,10 +146,17 @@
// CHECK: ret %swift.type* bitcast ([[INT]]* getelementptr inbounds {{.*}} @_TMfV17struct_resilience6MySize, i32 0, i32 1) to %swift.type*)
-// CHECK-LABEL: define{{( protected)?}} private void @initialize_metadata_StructWithResilientStorage(i8*)
-// CHECK: [[FIELDS:%.*]] = alloca [4 x i8**]
-// CHECK: [[VWT:%.*]] = load i8**, i8*** getelementptr inbounds ({{.*}} @_TMfV17struct_resilience26StructWithResilientStorage{{.*}}, i64 -1)
+// FIXME: this should modify the template in-place instead of copying it
+// CHECK-LABEL: define{{( protected)?}} private %swift.type* @create_generic_metadata_StructWithResilientStorage(%swift.type_pattern*, i8**)
+// CHECK: [[FIELDS:%.*]] = alloca [4 x i8**]
+// CHECK: [[RESULT:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_pattern* %0, i8** %1)
+// CHECK: [[RESULT_ADDR:%.*]] = bitcast %swift.type* [[RESULT]] to i8**
+// CHECK: [[VWT:%.*]] = getelementptr inbounds i8*, i8** [[RESULT_ADDR]], i32 8
+// CHECK: [[VWT_ADDR:%.*]] = bitcast i8** [[VWT]] to i8*
+
+// CHECK: [[RESULT_ADDR2:%.*]] = bitcast %swift.type* %2 to [[INT]]*
+// CHECK: [[FIELD_OFFSETS_ADDR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[RESULT_ADDR:%.*]], i32 3
// CHECK: [[FIELDS_ADDR:%.*]] = getelementptr inbounds [4 x i8**], [4 x i8**]* [[FIELDS]], i32 0, i32 0
// public let s: Size
@@ -173,6 +180,5 @@
// CHECK: [[FIELD_4:%.*]] = getelementptr inbounds i8**, i8*** [[FIELDS_ADDR]], i32 3
// CHECK: store i8** [[SIZE_AND_ALIGNMENT:%.*]], i8*** [[FIELD_4]]
-// CHECK: call void @swift_initStructMetadata_UniversalStrategy([[INT]] 4, i8*** [[FIELDS_ADDR]], [[INT]]* {{.*}}, i8** [[VWT]])
-// CHECK: store atomic %swift.type* {{.*}} @_TMfV17struct_resilience26StructWithResilientStorage{{.*}}, %swift.type** @_TMLV17struct_resilience26StructWithResilientStorage release,
-// CHECK: ret void
+// CHECK: call void @swift_initStructMetadata_UniversalStrategy([[INT]] 4, i8*** [[FIELDS_ADDR]], [[INT]]* [[FIELD_OFFSETS_ADDR]], i8** [[VWT]])
+// CHECK: ret %swift.type* [[RESULT]]
diff --git a/test/IRGen/typemetadata.sil b/test/IRGen/typemetadata.sil
index 477d5e5..a9f785f 100644
--- a/test/IRGen/typemetadata.sil
+++ b/test/IRGen/typemetadata.sil
@@ -31,7 +31,7 @@
// CHECK-NEXT: br i1 [[T1]]
// CHECK: [[T0:%.*]] = call %objc_class* @rt_swift_getInitializedObjCClass({{.*}} @_TMfC12typemetadata1C, {{.*}})
// CHECK-NEXT: [[T1:%.*]] = bitcast %objc_class* [[T0]] to %swift.type*
-// CHECK: store atomic %swift.type* [[T1]], %swift.type** @_TMLC12typemetadata1C release, align 8
+// CHECK: store %swift.type* [[T1]], %swift.type** @_TMLC12typemetadata1C, align 8
// CHECK-NEXT: br label
// CHECK: [[RES:%.*]] = phi
// CHECK-NEXT: ret %swift.type* [[RES]]
@@ -42,7 +42,7 @@
// CHECK-NEXT: br i1 [[T1]]
// CHECK: [[T0:%.*]] = call %swift.type* @_TMaC12typemetadata1C()
// CHECK-NEXT: [[T1:%.*]] = call %swift.type* @swift_getTupleTypeMetadata2(%swift.type* {{.*}} @_TMfV12typemetadata1S, {{.*}} %swift.type* [[T0]], i8* null, i8** null)
-// CHECK-NEXT: store atomic %swift.type* [[T1]], %swift.type** @_TMLTV12typemetadata1SCS_1C_ release, align 8
+// CHECK-NEXT: store %swift.type* [[T1]], %swift.type** @_TMLTV12typemetadata1SCS_1C_, align 8
// CHECK-NEXT: br label
// CHECK: [[RES:%.*]] = phi
// CHECK-NEXT: ret %swift.type* [[RES]]
diff --git a/test/SILGen/c_materializeForSet_linkage.swift b/test/SILGen/c_materializeForSet_linkage.swift
index 95a1c51..3b62986 100644
--- a/test/SILGen/c_materializeForSet_linkage.swift
+++ b/test/SILGen/c_materializeForSet_linkage.swift
@@ -16,11 +16,11 @@
// Make sure synthesized materializeForSet and its callbacks have shared linkage
// for properties imported from Clang
-// CHECK-LABEL: sil shared [transparent] @_TFVSC7NSPointm1xSf
-// CHECK-LABEL: sil shared [transparent] @_TFVSC7NSPointm1ySf
+// CHECK-LABEL: sil shared [transparent] [fragile] @_TFVSC7NSPointm1xSf
+// CHECK-LABEL: sil shared [transparent] [fragile] @_TFVSC7NSPointm1ySf
-// CHECK-LABEL: sil shared [transparent] @_TFCSo16NSReferencePointm1xSf
-// CHECK-LABEL: sil shared [transparent] @_TFCSo16NSReferencePointm1ySf
+// CHECK-LABEL: sil shared [transparent] [fragile] @_TFCSo16NSReferencePointm1xSf
+// CHECK-LABEL: sil shared [transparent] [fragile] @_TFCSo16NSReferencePointm1ySf
-// CHECK-LABEL: sil shared [transparent] @_TFFCSo16NSReferencePointm1xSfU_T_
-// CHECK-LABEL: sil shared [transparent] @_TFFCSo16NSReferencePointm1ySfU_T_
+// CHECK-LABEL: sil shared [transparent] [fragile] @_TFFCSo16NSReferencePointm1xSfU_T_
+// CHECK-LABEL: sil shared [transparent] [fragile] @_TFFCSo16NSReferencePointm1ySfU_T_
diff --git a/test/SILGen/cdecl.swift b/test/SILGen/cdecl.swift
index c5344bb..2e691dd 100644
--- a/test/SILGen/cdecl.swift
+++ b/test/SILGen/cdecl.swift
@@ -1,6 +1,6 @@
// RUN: %target-swift-frontend -emit-silgen %s | FileCheck %s
-// CHECK-LABEL: sil hidden @pear : $@convention(c)
+// CHECK-LABEL: sil hidden [thunk] @pear : $@convention(c)
// CHECK: function_ref @_TF5cdecl5apple
// CHECK-LABEL: sil hidden @_TF5cdecl5apple
@_cdecl("pear")
@@ -13,7 +13,7 @@
apple(orange)
}
-// CHECK-LABEL: sil hidden @grapefruit : $@convention(c)
+// CHECK-LABEL: sil hidden [thunk] @grapefruit : $@convention(c)
// CHECK: function_ref @_TF5cdecl6orange
// CHECK-LABEL: sil hidden @_TF5cdecl6orange
@_cdecl("grapefruit")
@@ -21,7 +21,7 @@
return x
}
-// CHECK-LABEL: sil @cauliflower : $@convention(c)
+// CHECK-LABEL: sil [thunk] @cauliflower : $@convention(c)
// CHECK: function_ref @_TF5cdecl8broccoli
// CHECK-LABEL: sil @_TF5cdecl8broccoli
@_cdecl("cauliflower")
@@ -29,7 +29,7 @@
return x
}
-// CHECK-LABEL: sil private @collard_greens : $@convention(c)
+// CHECK-LABEL: sil private [thunk] @collard_greens : $@convention(c)
// CHECK: function_ref @_TF5cdeclP[[PRIVATE:.*]]4kale
// CHECK: sil private @_TF5cdeclP[[PRIVATE:.*]]4kale
@_cdecl("collard_greens")
diff --git a/test/SILGen/cf.swift b/test/SILGen/cf.swift
index 348496d..7cb1fb0 100644
--- a/test/SILGen/cf.swift
+++ b/test/SILGen/cf.swift
@@ -59,9 +59,9 @@
extension CCImpedance: Impedance {}
// CHECK-LABEL: sil hidden [transparent] [thunk] @_TTWVSC11CCImpedance2cf9ImpedanceS0_FS1_g4realwx9Component
-// CHECK-LABEL: sil shared [transparent] @_TFVSC11CCImpedanceg4realSd
+// CHECK-LABEL: sil shared [transparent] [fragile] @_TFVSC11CCImpedanceg4realSd
// CHECK-LABEL: sil hidden [transparent] [thunk] @_TTWVSC11CCImpedance2cf9ImpedanceS0_FS1_g4imagwx9Component
-// CHECK-LABEL: sil shared [transparent] @_TFVSC11CCImpedanceg4imagSd
+// CHECK-LABEL: sil shared [transparent] [fragile] @_TFVSC11CCImpedanceg4imagSd
class MyMagnetism : CCMagnetismModel {
// CHECK-LABEL: sil hidden [thunk] @_TToFC2cf11MyMagnetism15getRefrigerator{{.*}} : $@convention(objc_method) (MyMagnetism) -> @autoreleased CCRefrigerator
diff --git a/test/SILGen/dynamic.swift b/test/SILGen/dynamic.swift
index e9c8e58..8cebbb2 100644
--- a/test/SILGen/dynamic.swift
+++ b/test/SILGen/dynamic.swift
@@ -76,7 +76,7 @@
// TODO: dynamic initializing ctor must be objc dispatched
// CHECK-LABEL: sil hidden @_TFC7dynamic3FooC
// CHECK: function_ref @_TTDFC7dynamic3Fooc
-// CHECK-LABEL: sil shared [transparent] @_TTDFC7dynamic3Fooc
+// CHECK-LABEL: sil shared [transparent] [thunk] @_TTDFC7dynamic3Fooc
// CHECK: class_method [volatile] {{%.*}} : $Foo, #Foo.init!initializer.1.foreign :
// CHECK-LABEL: sil hidden [thunk] @_TToFC7dynamic3Fooc
@@ -115,27 +115,27 @@
// Dynamic witnesses use objc dispatch:
// CHECK-LABEL: sil hidden [transparent] [thunk] @_TTWC7dynamic3FooS_5ProtoS_FS1_13dynamicMethod
// CHECK: function_ref @_TTDFC7dynamic3Foo13dynamicMethod
-// CHECK-LABEL: sil shared [transparent] @_TTDFC7dynamic3Foo13dynamicMethod
+// CHECK-LABEL: sil shared [transparent] [thunk] @_TTDFC7dynamic3Foo13dynamicMethod
// CHECK: class_method [volatile] {{%.*}} : $Foo, #Foo.dynamicMethod!1.foreign :
// CHECK-LABEL: sil hidden [transparent] [thunk] @_TTWC7dynamic3FooS_5ProtoS_FS1_g11dynamicPropSi
// CHECK: function_ref @_TTDFC7dynamic3Foog11dynamicPropSi
-// CHECK-LABEL: sil shared [transparent] @_TTDFC7dynamic3Foog11dynamicPropSi
+// CHECK-LABEL: sil shared [transparent] [thunk] @_TTDFC7dynamic3Foog11dynamicPropSi
// CHECK: class_method [volatile] {{%.*}} : $Foo, #Foo.dynamicProp!getter.1.foreign :
// CHECK-LABEL: sil hidden [transparent] [thunk] @_TTWC7dynamic3FooS_5ProtoS_FS1_s11dynamicPropSi
// CHECK: function_ref @_TTDFC7dynamic3Foos11dynamicPropSi
-// CHECK-LABEL: sil shared [transparent] @_TTDFC7dynamic3Foos11dynamicPropSi
+// CHECK-LABEL: sil shared [transparent] [thunk] @_TTDFC7dynamic3Foos11dynamicPropSi
// CHECK: class_method [volatile] {{%.*}} : $Foo, #Foo.dynamicProp!setter.1.foreign :
// CHECK-LABEL: sil hidden [transparent] [thunk] @_TTWC7dynamic3FooS_5ProtoS_FS1_g9subscriptFT7dynamicSi_Si
// CHECK: function_ref @_TTDFC7dynamic3Foog9subscriptFT7dynamicSi_Si
-// CHECK-LABEL: sil shared [transparent] @_TTDFC7dynamic3Foog9subscriptFT7dynamicSi_Si
+// CHECK-LABEL: sil shared [transparent] [thunk] @_TTDFC7dynamic3Foog9subscriptFT7dynamicSi_Si
// CHECK: class_method [volatile] {{%.*}} : $Foo, #Foo.subscript!getter.1.foreign :
// CHECK-LABEL: sil hidden [transparent] [thunk] @_TTWC7dynamic3FooS_5ProtoS_FS1_s9subscriptFT7dynamicSi_Si
// CHECK: function_ref @_TTDFC7dynamic3Foos9subscriptFT7dynamicSi_Si
-// CHECK-LABEL: sil shared [transparent] @_TTDFC7dynamic3Foos9subscriptFT7dynamicSi_Si
+// CHECK-LABEL: sil shared [transparent] [thunk] @_TTDFC7dynamic3Foos9subscriptFT7dynamicSi_Si
// CHECK: class_method [volatile] {{%.*}} : $Foo, #Foo.subscript!setter.1.foreign :
// Superclass dispatch
diff --git a/test/SILGen/enum.swift b/test/SILGen/enum.swift
index a3a7b62..071ba97 100644
--- a/test/SILGen/enum.swift
+++ b/test/SILGen/enum.swift
@@ -42,7 +42,7 @@
_ = Optionable.mere(x)
}
-// CHECK-LABEL: sil shared [transparent] @_TFOs10Optionable4mereFMS_FSiS_
+// CHECK-LABEL: sil shared [transparent] [thunk] @_TFOs10Optionable4mereFMS_FSiS_
// CHECK: [[FN:%.*]] = function_ref @_TFOs10Optionable4merefMS_FSiS_
// CHECK-NEXT: [[METHOD:%.*]] = partial_apply [[FN]](%0)
// CHECK-NEXT: return [[METHOD]]
@@ -102,7 +102,7 @@
// CHECK: return
}
-// CHECK-LABEL: sil shared [transparent] @_TFOs11AddressOnly4mereFMS_FPs1P_S_
+// CHECK-LABEL: sil shared [transparent] [thunk] @_TFOs11AddressOnly4mereFMS_FPs1P_S_
// CHECK: [[FN:%.*]] = function_ref @_TFOs11AddressOnly4merefMS_FPs1P_S_
// CHECK-NEXT: [[METHOD:%.*]] = partial_apply [[FN]](%0)
// CHECK-NEXT: return [[METHOD]] : $@callee_owned (@in P) -> @out AddressOnly
@@ -169,7 +169,7 @@
enum Foo { case A(P, String) }
-// CHECK-LABEL: sil shared [transparent] @_TFOs3Foo1AFMS_FTPs1P_SS_S_
+// CHECK-LABEL: sil shared [transparent] [thunk] @_TFOs3Foo1AFMS_FTPs1P_SS_S_
// CHECK: [[FN:%.*]] = function_ref @_TFOs3Foo1AfMS_FTPs1P_SS_S_
// CHECK-NEXT: [[METHOD:%.*]] = partial_apply [[FN]](%0)
// CHECK-NEXT: return [[METHOD]]
diff --git a/test/SILGen/extensions.swift b/test/SILGen/extensions.swift
index 31f1171..bbb69d4 100644
--- a/test/SILGen/extensions.swift
+++ b/test/SILGen/extensions.swift
@@ -37,5 +37,5 @@
_ = x.zang
}
-// CHECK-LABEL: sil shared @_TFC10extensions3Foo4zang
+// CHECK-LABEL: sil shared [thunk] @_TFC10extensions3Foo4zang
// CHECK: function_ref @_TFC10extensions3Foo4zang
diff --git a/test/SILGen/extensions_objc.swift b/test/SILGen/extensions_objc.swift
index 8968641..496ff30 100644
--- a/test/SILGen/extensions_objc.swift
+++ b/test/SILGen/extensions_objc.swift
@@ -25,7 +25,7 @@
_ = x.kay
}
-// CHECK-LABEL: sil shared @_TFC15extensions_objc3Foo3kayF
+// CHECK-LABEL: sil shared [thunk] @_TFC15extensions_objc3Foo3kayF
// CHECK: function_ref @_TTDFC15extensions_objc3Foo3kayf
-// CHECK: sil shared [transparent] @_TTDFC15extensions_objc3Foo3kayf
+// CHECK: sil shared [transparent] [thunk] @_TTDFC15extensions_objc3Foo3kayf
// CHECK: class_method [volatile] %0 : $Foo, #Foo.kay!1.foreign
diff --git a/test/SILGen/external_definitions.swift b/test/SILGen/external_definitions.swift
index 40fed45..969f8cf 100644
--- a/test/SILGen/external_definitions.swift
+++ b/test/SILGen/external_definitions.swift
@@ -32,7 +32,7 @@
// CHECK-LABEL: sil shared @_TFCSo8NSObjectC{{.*}} : $@convention(thin) (@thick NSObject.Type) -> @owned NSObject
// -- Native Swift thunk for NSAnse
-// CHECK: sil shared @_TTOFSC6NSAnseFGSQCSo7Ansible_GSQS__ : $@convention(thin) (@owned ImplicitlyUnwrappedOptional<Ansible>) -> @owned ImplicitlyUnwrappedOptional<Ansible> {
+// CHECK: sil shared [thunk] @_TTOFSC6NSAnseFGSQCSo7Ansible_GSQS__ : $@convention(thin) (@owned ImplicitlyUnwrappedOptional<Ansible>) -> @owned ImplicitlyUnwrappedOptional<Ansible> {
// CHECK: bb0(%0 : $ImplicitlyUnwrappedOptional<Ansible>):
// CHECK: %1 = function_ref @NSAnse : $@convention(c) (ImplicitlyUnwrappedOptional<Ansible>) -> @autoreleased ImplicitlyUnwrappedOptional<Ansible>
// CHECK: %2 = apply %1(%0) : $@convention(c) (ImplicitlyUnwrappedOptional<Ansible>) -> @autoreleased ImplicitlyUnwrappedOptional<Ansible>
diff --git a/test/SILGen/foreign_errors.swift b/test/SILGen/foreign_errors.swift
index bd88af9..c9d2841 100644
--- a/test/SILGen/foreign_errors.swift
+++ b/test/SILGen/foreign_errors.swift
@@ -115,12 +115,12 @@
}
let fn = ErrorProne.fail
-// CHECK-LABEL: sil shared @_TTOZFCSo10ErrorProne4fail{{.*}} : $@convention(thin) (@thick ErrorProne.Type) -> @owned @callee_owned () -> @error ErrorProtocol
+// CHECK-LABEL: sil shared [thunk] @_TTOZFCSo10ErrorProne4fail{{.*}} : $@convention(thin) (@thick ErrorProne.Type) -> @owned @callee_owned () -> @error ErrorProtocol
// CHECK: [[T0:%.*]] = function_ref @_TTOZFCSo10ErrorProne4fail{{.*}} : $@convention(thin) (@thick ErrorProne.Type) -> @error ErrorProtocol
// CHECK-NEXT: [[T1:%.*]] = partial_apply [[T0]](%0)
// CHECK-NEXT: return [[T1]]
-// CHECK-LABEL: sil shared @_TTOZFCSo10ErrorProne4fail{{.*}} : $@convention(thin) (@thick ErrorProne.Type) -> @error ErrorProtocol {
+// CHECK-LABEL: sil shared [thunk] @_TTOZFCSo10ErrorProne4fail{{.*}} : $@convention(thin) (@thick ErrorProne.Type) -> @error ErrorProtocol {
// CHECK: [[SELF:%.*]] = thick_to_objc_metatype %0 : $@thick ErrorProne.Type to $@objc_metatype ErrorProne.Type
// CHECK: [[METHOD:%.*]] = class_method [volatile] [[T0]] : $@objc_metatype ErrorProne.Type, #ErrorProne.fail!1.foreign : ErrorProne.Type -> () throws -> () , $@convention(objc_method) (AutoreleasingUnsafeMutablePointer<Optional<NSError>>, @objc_metatype ErrorProne.Type) -> Bool
// CHECK: [[TEMP:%.*]] = alloc_stack $Optional<NSError>
diff --git a/test/SILGen/functions.swift b/test/SILGen/functions.swift
index e986b1a..aab5dfe 100644
--- a/test/SILGen/functions.swift
+++ b/test/SILGen/functions.swift
@@ -302,12 +302,12 @@
}
// -- Curried entry points
-// CHECK-LABEL: sil shared @_TFV9functions10SomeStruct6method{{.*}} : $@convention(thin) (@inout SomeStruct) -> @owned @callee_owned (Builtin.Int64) -> () {
+// CHECK-LABEL: sil shared [thunk] @_TFV9functions10SomeStruct6method{{.*}} : $@convention(thin) (@inout SomeStruct) -> @owned @callee_owned (Builtin.Int64) -> () {
// CHECK: [[UNCURRIED:%.*]] = function_ref @_TFV9functions10SomeStruct6method{{.*}} : $@convention(method) (Builtin.Int64, @inout SomeStruct) -> (){{.*}} // user: %2
// CHECK: [[CURRIED:%.*]] = partial_apply [[UNCURRIED]]
// CHECK: return [[CURRIED]]
-// CHECK-LABEL: sil shared @_TFC9functions9SomeClass6method{{.*}} : $@convention(thin) (@owned SomeClass) -> @owned @callee_owned (Builtin.Int64) -> ()
+// CHECK-LABEL: sil shared [thunk] @_TFC9functions9SomeClass6method{{.*}} : $@convention(thin) (@owned SomeClass) -> @owned @callee_owned (Builtin.Int64) -> ()
// CHECK: bb0(%0 : $SomeClass):
// CHECK: class_method %0 : $SomeClass, #SomeClass.method!1 : (SomeClass) -> (Builtin.Int64) -> ()
// CHECK: %2 = partial_apply %1(%0)
@@ -398,7 +398,7 @@
}
// The curry thunk for the method should not include a class_method instruction.
-// CHECK-LABEL: sil shared @_TFC9functions14r17828355Class6methodF
+// CHECK-LABEL: sil shared [thunk] @_TFC9functions14r17828355Class6methodF
// CHECK: bb0(%0 : $r17828355Class):
// CHECK-NEXT: // function_ref functions.r17828355Class.method (Builtin.Int64) -> ()
// CHECK-NEXT: %1 = function_ref @_TFC9functions14r17828355Class6method{{.*}} : $@convention(method) (Builtin.Int64, @guaranteed r17828355Class) -> ()
@@ -470,12 +470,12 @@
let right2 = right(C())
}
-// CHECK-LABEL: sil shared [transparent] @_TFO9functions23PartialApplyEnumPayload4Left{{.*}}
+// CHECK-LABEL: sil shared [transparent] [thunk] @_TFO9functions23PartialApplyEnumPayload4Left{{.*}}
// CHECK: [[UNCURRIED:%.*]] = function_ref @_TFO9functions23PartialApplyEnumPayload4Left{{.*}}
// CHECK: [[CLOSURE:%.*]] = partial_apply [[UNCURRIED]]<T, U>(%0)
// CHECK: return [[CLOSURE]]
-// CHECK-LABEL: sil shared [transparent] @_TFO9functions23PartialApplyEnumPayload5Right{{.*}}
+// CHECK-LABEL: sil shared [transparent] [thunk] @_TFO9functions23PartialApplyEnumPayload5Right{{.*}}
// CHECK: [[UNCURRIED:%.*]] = function_ref @_TFO9functions23PartialApplyEnumPayload5Right{{.*}}
// CHECK: [[CLOSURE:%.*]] = partial_apply [[UNCURRIED]]<T, U>(%0)
// CHECK: return [[CLOSURE]]
diff --git a/test/SILGen/guaranteed_self.swift b/test/SILGen/guaranteed_self.swift
index 1e48258..75df7a1 100644
--- a/test/SILGen/guaranteed_self.swift
+++ b/test/SILGen/guaranteed_self.swift
@@ -379,7 +379,7 @@
super.init()
}
- // CHECK-LABEL: sil shared [transparent] @_TTDFC15guaranteed_self1D3foo{{.*}} : $@convention(method) (Int, @guaranteed D) -> ()
+ // CHECK-LABEL: sil shared [transparent] [thunk] @_TTDFC15guaranteed_self1D3foo{{.*}} : $@convention(method) (Int, @guaranteed D) -> ()
// CHECK: bb0({{.*}} [[SELF:%.*]]):
// CHECK: retain{{.*}} [[SELF]]
// CHECK: release{{.*}} [[SELF]]
diff --git a/test/SILGen/imported_struct_array_field.swift b/test/SILGen/imported_struct_array_field.swift
index dae6dda..36f0943 100644
--- a/test/SILGen/imported_struct_array_field.swift
+++ b/test/SILGen/imported_struct_array_field.swift
@@ -1,6 +1,6 @@
// RUN: %target-swift-frontend -emit-silgen -import-objc-header %S/Inputs/array_typedef.h %s | FileCheck %s
-// CHECK-LABEL: sil shared [transparent] @_TFVSC4NameC{{.*}} : $@convention(thin) (UInt8, UInt8, UInt8, UInt8, @thin Name.Type) -> Name
+// CHECK-LABEL: sil shared [transparent] [fragile] @_TFVSC4NameC{{.*}} : $@convention(thin) (UInt8, UInt8, UInt8, UInt8, @thin Name.Type) -> Name
func useImportedArrayTypedefInit() -> Name {
return Name(name: (0, 0, 0, 0))
}
diff --git a/test/SILGen/nsmanaged-witness.swift b/test/SILGen/nsmanaged-witness.swift
index 9f548b5..b0d7088 100644
--- a/test/SILGen/nsmanaged-witness.swift
+++ b/test/SILGen/nsmanaged-witness.swift
@@ -61,5 +61,5 @@
// TODO: We can't emit a vtable entry for materializeForSet for ObjC types.
// CHECK-NOT: class_method {{.*}}Foo{{.*}}intProperty{{.*}}materializeForSet
-// CHECK-LABEL: sil shared [transparent] @_TFCSo3Foom11intPropertyVs5Int32
+// CHECK-LABEL: sil shared [transparent] [fragile] @_TFCSo3Foom11intPropertyVs5Int32
diff --git a/test/SILGen/objc_currying.swift b/test/SILGen/objc_currying.swift
index 511e349..ab9eb8f 100644
--- a/test/SILGen/objc_currying.swift
+++ b/test/SILGen/objc_currying.swift
@@ -18,12 +18,12 @@
// CHECK: strong_release [[ARG1]]
// CHECK: return [[FN]]
-// CHECK: sil shared [[THUNK_FOO_1]] : $@convention(thin) (@owned CurryTest) -> @owned @callee_owned (Int) -> Int
+// CHECK: sil shared [thunk] [[THUNK_FOO_1]] : $@convention(thin) (@owned CurryTest) -> @owned @callee_owned (Int) -> Int
// CHECK: [[THUNK:%.*]] = function_ref [[THUNK_FOO_2:@_TTOFCSo9CurryTest3podfSiSi]]
// CHECK: [[FN:%.*]] = partial_apply [[THUNK]](%0)
// CHECK: return [[FN]]
-// CHECK: sil shared [[THUNK_FOO_2]] : $@convention(method) (Int, @guaranteed CurryTest) -> Int
+// CHECK: sil shared [thunk] [[THUNK_FOO_2]] : $@convention(method) (Int, @guaranteed CurryTest) -> Int
// CHECK: bb0([[ARG1:%.*]] : $Int, [[ARG2:%.*]] : $CurryTest):
// CHECK: strong_retain [[ARG2]]
// CHECK: [[METHOD:%.*]] = class_method [volatile] %1 : $CurryTest, #CurryTest.pod!1.foreign
@@ -39,12 +39,12 @@
// CHECK: [[FN:%.*]] = apply [[THUNK]](%0)
// CHECK: return [[FN]]
-// CHECK: sil shared [[THUNK_BAR_1]] : $@convention(thin) (@owned CurryTest) -> @owned @callee_owned (@owned ImplicitlyUnwrappedOptional<String>) -> @owned ImplicitlyUnwrappedOptional<String>
+// CHECK: sil shared [thunk] [[THUNK_BAR_1]] : $@convention(thin) (@owned CurryTest) -> @owned @callee_owned (@owned ImplicitlyUnwrappedOptional<String>) -> @owned ImplicitlyUnwrappedOptional<String>
// CHECK: [[THUNK:%.*]] = function_ref [[THUNK_BAR_2:@_TTOFCSo9CurryTest7bridgedfGSQSS_GSQSS_]]
// CHECK: [[FN:%.*]] = partial_apply [[THUNK]](%0)
// CHECK: return [[FN]]
-// CHECK: sil shared [[THUNK_BAR_2]] : $@convention(method) (@owned ImplicitlyUnwrappedOptional<String>, @guaranteed CurryTest) -> @owned ImplicitlyUnwrappedOptional<String>
+// CHECK: sil shared [thunk] [[THUNK_BAR_2]] : $@convention(method) (@owned ImplicitlyUnwrappedOptional<String>, @guaranteed CurryTest) -> @owned ImplicitlyUnwrappedOptional<String>
// CHECK: function_ref @_TFE10FoundationSS19_bridgeToObjectiveCfT_CSo8NSString
// CHECK: [[METHOD:%.*]] = class_method [volatile] %1 : $CurryTest, #CurryTest.bridged!1.foreign
// CHECK: [[RES:%.*]] = apply [[METHOD]]({{%.*}}, %1) : $@convention(objc_method) (ImplicitlyUnwrappedOptional<NSString>, CurryTest) -> @autoreleased ImplicitlyUnwrappedOptional<NSString>
@@ -60,12 +60,12 @@
// CHECK: [[FN:%.*]] = apply [[THUNK]](%0)
// CHECK: return [[FN]]
-// CHECK: sil shared [[THUNK_RETURNSINNERPOINTER]] : $@convention(thin) (@owned CurryTest) -> @owned @callee_owned () -> UnsafeMutablePointer<()>
+// CHECK: sil shared [thunk] [[THUNK_RETURNSINNERPOINTER]] : $@convention(thin) (@owned CurryTest) -> @owned @callee_owned () -> UnsafeMutablePointer<()>
// CHECK: [[THUNK:%.*]] = function_ref [[THUNK_RETURNSINNERPOINTER_2:@_TTOFCSo9CurryTest19returnsInnerPointerfT_GSpT__]]
// CHECK: [[FN:%.*]] = partial_apply [[THUNK]](%0)
// CHECK: return [[FN]]
-// CHECK: sil shared @_TTOFCSo9CurryTest19returnsInnerPointerfT_GSpT__ : $@convention(method) (@guaranteed CurryTest) -> UnsafeMutablePointer<()>
+// CHECK: sil shared [thunk] @_TTOFCSo9CurryTest19returnsInnerPointerfT_GSpT__ : $@convention(method) (@guaranteed CurryTest) -> UnsafeMutablePointer<()>
// CHECK: bb0([[ARG1:%.*]] :
// CHECK: strong_retain [[ARG1]]
// CHECK: [[METHOD:%.*]] = class_method [volatile] %0 : $CurryTest, #CurryTest.returnsInnerPointer!1.foreign
diff --git a/test/SILGen/objc_extensions.swift b/test/SILGen/objc_extensions.swift
index ccf1828..3623c1b 100644
--- a/test/SILGen/objc_extensions.swift
+++ b/test/SILGen/objc_extensions.swift
@@ -30,9 +30,9 @@
testOverrideProperty(Sub())
-// CHECK-LABEL: sil shared @_TFC15objc_extensions3Sub3fooFT_T_
+// CHECK-LABEL: sil shared [thunk] @_TFC15objc_extensions3Sub3fooFT_T_
// CHECK: function_ref @_TTDFC15objc_extensions3Sub3foofT_T_
-// CHECK: sil shared [transparent] @_TTDFC15objc_extensions3Sub3foofT_T_
+// CHECK: sil shared [transparent] [thunk] @_TTDFC15objc_extensions3Sub3foofT_T_
// CHECK: class_method [volatile] %0 : $Sub, #Sub.foo!1.foreign
func testCurry(x: Sub) {
_ = x.foo
diff --git a/test/SILGen/objc_protocols.swift b/test/SILGen/objc_protocols.swift
index bfe6667..f9e786d 100644
--- a/test/SILGen/objc_protocols.swift
+++ b/test/SILGen/objc_protocols.swift
@@ -58,24 +58,24 @@
_ = T.mince
}
-// CHECK-LABEL: sil shared @_TTOFP14objc_protocols9NSRuncing5runceFT_CSo8NSObject
+// CHECK-LABEL: sil shared [thunk] @_TTOFP14objc_protocols9NSRuncing5runceFT_CSo8NSObject
// CHECK: [[FN:%.*]] = function_ref @_TTOFP14objc_protocols9NSRuncing5runcefT_CSo8NSObject
// CHECK-NEXT: [[METHOD:%.*]] = partial_apply [[FN]]<Self>(%0)
// CHECK-NEXT: return [[METHOD]]
-// CHECK-LABEL: sil shared @_TTOFP14objc_protocols9NSRuncing5runcefT_CSo8NSObject
+// CHECK-LABEL: sil shared [thunk] @_TTOFP14objc_protocols9NSRuncing5runcefT_CSo8NSObject
// CHECK: strong_retain %0
// CHECK-NEXT: [[FN:%.*]] = witness_method $Self, #NSRuncing.runce!1.foreign
// CHECK-NEXT: [[RESULT:%.*]] = apply [[FN]]<Self>(%0)
// CHECK-NEXT: strong_release %0
// CHECK-NEXT: return [[RESULT]]
-// CHECK-LABEL: sil shared @_TTOZFP14objc_protocols9NSRuncing5minceFT_CSo8NSObject
+// CHECK-LABEL: sil shared [thunk] @_TTOZFP14objc_protocols9NSRuncing5minceFT_CSo8NSObject
// CHECK: [[FN:%.*]] = function_ref @_TTOZFP14objc_protocols9NSRuncing5mincefT_CSo8NSObject
// CHECK-NEXT: [[METHOD:%.*]] = partial_apply [[FN]]<Self>(%0)
// CHECK-NEXT: return [[METHOD]]
-// CHECK-LABEL: sil shared @_TTOZFP14objc_protocols9NSRuncing5mincefT_CSo8NSObject
+// CHECK-LABEL: sil shared [thunk] @_TTOZFP14objc_protocols9NSRuncing5mincefT_CSo8NSObject
// CHECK: [[FN:%.*]] = witness_method $Self, #NSRuncing.mince!1.foreign
// CHECK-NEXT: [[RESULT:%.*]] = apply [[FN]]<Self>(%0)
// CHECK-NEXT: return [[RESULT]]
diff --git a/test/SILGen/objc_witnesses.swift b/test/SILGen/objc_witnesses.swift
index 5e791dc..e59bc12 100644
--- a/test/SILGen/objc_witnesses.swift
+++ b/test/SILGen/objc_witnesses.swift
@@ -66,6 +66,6 @@
// CHECK-LABEL: sil hidden [transparent] [thunk] @_TTWCSo7NSArray14objc_witnesses13SubscriptableS0_FS1_g9subscriptFSiPs9AnyObject_ : $@convention(witness_method) (Int, @in_guaranteed NSArray) -> @owned AnyObject {
// CHECK: function_ref @_TTOFCSo7NSArrayg9subscriptFSiPs9AnyObject_ : $@convention(method) (Int, @guaranteed NSArray) -> @owned AnyObject
-// CHECK-LABEL: sil shared @_TTOFCSo7NSArrayg9subscriptFSiPs9AnyObject_ : $@convention(method) (Int, @guaranteed NSArray) -> @owned AnyObject {
+// CHECK-LABEL: sil shared [thunk] @_TTOFCSo7NSArrayg9subscriptFSiPs9AnyObject_ : $@convention(method) (Int, @guaranteed NSArray) -> @owned AnyObject {
// CHECK: class_method [volatile] %1 : $NSArray, #NSArray.subscript!getter.1.foreign
extension NSArray: Subscriptable {}
diff --git a/test/SILGen/partial_apply_generic.swift b/test/SILGen/partial_apply_generic.swift
index 50d6ced..ac9612d 100644
--- a/test/SILGen/partial_apply_generic.swift
+++ b/test/SILGen/partial_apply_generic.swift
@@ -13,7 +13,7 @@
// CHECK-NEXT: return
}
-// CHECK-LABEL: sil shared @_TZFP21partial_apply_generic3Foo10staticFunc
+// CHECK-LABEL: sil shared [thunk] @_TZFP21partial_apply_generic3Foo10staticFunc
// CHECK: [[REF:%.*]] = witness_method $Self, #Foo.staticFunc!1
// CHECK-NEXT: partial_apply [[REF]]<Self>(%0)
// CHECK-NEXT: return
@@ -39,7 +39,7 @@
// CHECK-NEXT: return
}
-// CHECK-LABEL: sil shared @_TFP21partial_apply_generic3Foo12instanceFunc
+// CHECK-LABEL: sil shared [thunk] @_TFP21partial_apply_generic3Foo12instanceFunc
// CHECK: [[REF:%.*]] = witness_method $Self, #Foo.instanceFunc!1
// CHECK-NEXT: partial_apply [[REF]]<Self>(%0)
// CHECK-NEXT: return
diff --git a/test/SILGen/partial_apply_init.swift b/test/SILGen/partial_apply_init.swift
index 3d4de85..1793d06 100644
--- a/test/SILGen/partial_apply_init.swift
+++ b/test/SILGen/partial_apply_init.swift
@@ -34,11 +34,11 @@
let requiredM: Double -> C = c.init
}
-// CHECK-LABEL: sil shared @_TTdFC18partial_apply_init1CC
+// CHECK-LABEL: sil shared [thunk] @_TTdFC18partial_apply_init1CC
// CHECK: function_ref @_TFC18partial_apply_init1CC
-// CHECK-LABEL: sil shared @_TTdFC18partial_apply_init1CC
+// CHECK-LABEL: sil shared [thunk] @_TTdFC18partial_apply_init1CC
// CHECK: function_ref @_TFC18partial_apply_init1CC
-// CHECK-LABEL: sil shared @_TFC18partial_apply_init1CC
+// CHECK-LABEL: sil shared [thunk] @_TFC18partial_apply_init1CC
// CHECK: class_method %0 : $@thick C.Type, #C.init!allocator.1
// CHECK-LABEL: sil hidden @_TF18partial_apply_init28archetype_init_partial_apply
@@ -59,8 +59,8 @@
let protoExtM: Float -> T = t.init
}
-// CHECK-LABEL: sil shared @_TFP18partial_apply_init1PC
+// CHECK-LABEL: sil shared [thunk] @_TFP18partial_apply_init1PC
// CHECK: witness_method $Self, #P.init!allocator.1
-// CHECK-LABEL: sil shared @_TFE18partial_apply_initPS_1PC
+// CHECK-LABEL: sil shared [thunk] @_TFE18partial_apply_initPS_1PC
// CHECK: function_ref @_TFE18partial_apply_initPS_1PC
diff --git a/test/SILGen/transparent_attribute.swift b/test/SILGen/transparent_attribute.swift
index 4ec33e6..ac3ead0 100644
--- a/test/SILGen/transparent_attribute.swift
+++ b/test/SILGen/transparent_attribute.swift
@@ -181,22 +181,32 @@
}
// CHECK: sil hidden [transparent] @_TF21transparent_attributeg22transparentOnGlobalVarSi
-// Local functions in transparent context have public linkage.
-@_transparent func foo() {
- // CHECK-LABEL: sil @_TFF21transparent_attribute3fooFT_T_L_3barFT_T_ : $@convention(thin) () -> ()
+// Local functions in transparent context are fragile.
+@_transparent public func foo() {
+ // CHECK-LABEL: sil shared [fragile] @_TFF21transparent_attribute3fooFT_T_L_3barFT_T_ : $@convention(thin) () -> ()
func bar() {}
bar()
- // CHECK-LABEL: sil @_TFF21transparent_attribute3fooFT_T_U_FT_T_ : $@convention(thin) () -> () {
+ // CHECK-LABEL: sil shared [fragile] @_TFF21transparent_attribute3fooFT_T_U_FT_T_ : $@convention(thin) () -> () {
let f: () -> () = {}
f()
- // CHECK-LABEL: sil @_TFF21transparent_attribute3fooFT_T_L_3zimFT_T_ : $@convention(thin) () -> () {
+ // CHECK-LABEL: sil shared [fragile] @_TFF21transparent_attribute3fooFT_T_L_3zimFT_T_ : $@convention(thin) () -> () {
func zim() {
- // CHECK-LABEL: sil @_TFFF21transparent_attribute3fooFT_T_L_3zimFT_T_L_4zangFT_T_ : $@convention(thin) () -> () {
+ // CHECK-LABEL: sil shared [fragile] @_TFFF21transparent_attribute3fooFT_T_L_3zimFT_T_L_4zangFT_T_ : $@convention(thin) () -> () {
func zang() {
}
zang()
}
zim()
}
+
+
+// Check that @_versioned entities have public linkage.
+// CHECK-LABEL: sil @_TF21transparent_attribute25referencedFromTransparentFT_T_ : $@convention(thin) () -> () {
+@_versioned func referencedFromTransparent() {}
+
+// CHECK-LABEL: sil [transparent] [fragile] @_TF21transparent_attribute23referencesVersionedFuncFT_FT_T_ : $@convention(thin) () -> @owned @callee_owned () -> () {
+@_transparent public func referencesVersionedFunc() -> () -> () {
+ return referencedFromTransparent
+}
diff --git a/test/SILOptimizer/definite_init_objc_factory_init.swift b/test/SILOptimizer/definite_init_objc_factory_init.swift
index e575ec2..b615655 100644
--- a/test/SILOptimizer/definite_init_objc_factory_init.swift
+++ b/test/SILOptimizer/definite_init_objc_factory_init.swift
@@ -4,7 +4,7 @@
import Foundation
-// CHECK-LABEL: sil shared @_TTOFCSo4HiveCfT5queenGSQCSo3Bee__GSQS__ : $@convention(thin) (@owned ImplicitlyUnwrappedOptional<Bee>, @thick Hive.Type) -> @owned ImplicitlyUnwrappedOptional<Hive>
+// CHECK-LABEL: sil shared [thunk] @_TTOFCSo4HiveCfT5queenGSQCSo3Bee__GSQS__ : $@convention(thin) (@owned ImplicitlyUnwrappedOptional<Bee>, @thick Hive.Type) -> @owned ImplicitlyUnwrappedOptional<Hive>
func testInstanceTypeFactoryMethod(queen: Bee) {
// CHECK: bb0([[QUEEN:%[0-9]+]] : $ImplicitlyUnwrappedOptional<Bee>, [[HIVE_META:%[0-9]+]] : $@thick Hive.Type):
// CHECK-NEXT: [[HIVE_META_OBJC:%[0-9]+]] = thick_to_objc_metatype [[HIVE_META]] : $@thick Hive.Type to $@objc_metatype Hive.Type
diff --git a/test/SILOptimizer/escape_analysis.sil b/test/SILOptimizer/escape_analysis.sil
index 65a093c..0e7bd87 100644
--- a/test/SILOptimizer/escape_analysis.sil
+++ b/test/SILOptimizer/escape_analysis.sil
@@ -1214,3 +1214,38 @@
sil [_semantics "array.get_count"] @get_count : $@convention(method) (@guaranteed Array<X>) -> Int32
sil [_semantics "array.get_capacity"] @get_capacity : $@convention(method) (@guaranteed Array<X>) -> Int32
+sil [_semantics "pair_no_escaping_closure"] @unsafeWithNotEscapedSelfPointerPair : $@convention(method) (@owned X, @owned @callee_owned (X, X) -> (@out X, @error ErrorType), @guaranteed X) -> (@out X, @error ErrorType)
+sil [_semantics "self_no_escaping_closure"] @unsafeWithNotEscapedSelfPointer: $@convention(method) (@owned @callee_owned (X, X) -> (@out X, @error ErrorType), @guaranteed X) -> (@out X, @error ErrorType)
+
+// CHECK-LABEL: CG of semantics_pair_no_escaping_closure
+// CHECK-NEXT: Arg %0 Esc: A, Succ:
+// CHECK-NEXT: Arg %1 Esc: A, Succ:
+// CHECK-NEXT: Arg %2 Esc: G, Succ: (%2.1)
+// CHECK-NEXT: Con %2.1 Esc: G, Succ:
+// CHECK-NEXT: Val %4 Esc: %5, Succ:
+// CHECK-NEXT: End
+sil @semantics_pair_no_escaping_closure : $@convention(thin) (@owned X, @guaranteed X, @owned @callee_owned (X, X) -> (@out X, @error ErrorType)) -> () {
+bb(%0 : $X, %1 : $X, %2: $@callee_owned (X, X) -> (@out X, @error ErrorType)):
+ %3 = function_ref @unsafeWithNotEscapedSelfPointerPair : $@convention(method) (@owned X, @owned @callee_owned (X, X) -> (@out X, @error ErrorType), @guaranteed X) -> (@out X, @error ErrorType)
+ %4 = alloc_stack $X
+ %6 = apply [nothrow] %3(%4, %0, %2, %1) : $@convention(method) (@owned X, @owned @callee_owned (X, X) -> (@out X, @error ErrorType), @guaranteed X) -> (@out X, @error ErrorType)
+ dealloc_stack %4 : $*X
+ %7 = tuple()
+ return %7 : $()
+}
+
+// CHECK-LABEL: CG of semantics_self_no_escaping_closure
+// CHECK-NEXT: Arg %0 Esc: A, Succ:
+// CHECK-NEXT: Arg %1 Esc: G, Succ: (%1.1)
+// CHECK-NEXT: Con %1.1 Esc: G, Succ:
+// CHECK-NEXT: Val %3 Esc: %4, Succ:
+// CHECK-NEXT: End
+sil @semantics_self_no_escaping_closure : $@convention(thin) (@guaranteed X, @owned @callee_owned (X, X) -> (@out X, @error ErrorType)) -> () {
+bb(%0 : $X, %1: $@callee_owned (X, X) -> (@out X, @error ErrorType)):
+ %2 = function_ref @unsafeWithNotEscapedSelfPointer : $@convention(method) (@owned @callee_owned (X, X) -> (@out X, @error ErrorType), @guaranteed X) -> (@out X, @error ErrorType)
+ %3 = alloc_stack $X
+ %6 = apply [nothrow] %2(%3, %1, %0) : $@convention(method) (@owned @callee_owned (X, X) -> (@out X, @error ErrorType), @guaranteed X) -> (@out X, @error ErrorType)
+ dealloc_stack %3 : $*X
+ %7 = tuple()
+ return %7 : $()
+}
diff --git a/test/SILOptimizer/let_properties_opts.swift b/test/SILOptimizer/let_properties_opts.swift
index b32f85f..1b60b52 100644
--- a/test/SILOptimizer/let_properties_opts.swift
+++ b/test/SILOptimizer/let_properties_opts.swift
@@ -98,6 +98,31 @@
}
}
+public class C {}
+
+struct Boo3 {
+ //public
+ let Prop0: Int32
+ let Prop1: Int32
+ private let Prop2: Int32
+ internal let Prop3: Int32
+
+ @inline(__always)
+ init(_ f1: C, _ f2: C) {
+ self.Prop0 = 0
+ self.Prop1 = 1
+ self.Prop2 = 2
+ self.Prop3 = 3
+ }
+
+ init(_ v: C) {
+ self.Prop0 = 10
+ self.Prop1 = 11
+ self.Prop2 = 12
+ self.Prop3 = 13
+ }
+}
+
// Check that Foo1.Prop1 is not constant-folded, because its value is unknown, since it is initialized differently
// by Foo1 initializers.
@@ -194,3 +219,35 @@
public func testClassLet2(f: Foo2) -> Int32 {
return f.x + f.x
}
+
+// Check that the sum of properties is not folded into a constant.
+// CHECK-WMO-LABEL: sil hidden [noinline] @_TF19let_properties_opts27testStructWithMultipleInitsFTVS_4Boo3S0__Vs5Int32 : $@convention(thin) (Boo3, Boo3) -> Int32
+// CHECK-WMO: bb0
+// No constant folding should have been performed.
+// CHECK-WMO-NOT: integer_literal $Builtin.Int32, 92
+// CHECK-WMO: struct_extract
+// CHECK-WMO: }
+@inline(never)
+func testStructWithMultipleInits( _ boos1: Boo3, _ boos2: Boo3) -> Int32 {
+ let count1 = boos1.Prop0 + boos1.Prop1 + boos1.Prop2 + boos1.Prop3
+ let count2 = boos2.Prop0 + boos2.Prop1 + boos2.Prop2 + boos2.Prop3
+ return count1 + count2
+}
+
+public func testStructWithMultipleInitsAndInlinedInitializer() {
+ let things = [C()]
+ // This line results in inlinig of the initializer Boo3(C, C) and later
+ // removal of this initializer by the dead function elimination pass.
+ // As a result, only one initializer, Boo3(C) is seen by the Let Properties Propagation
+ // pass. This pass may think that there is only one intializer and take the
+ // values of let properties assigned there as constants and try to propagate
+ // those values into uses. But this is wrong! The pass should be clever enough
+ // to detect all stores to the let properties, including those outside of
+ // initializers, e.g. inside inlined initializers. And if it detects all such
+ // stores it should understand that values of let properties in Boo3 are not
+ // statically known constant initializers with the same value and thus
+ // cannot be propagated.
+ let boos1 = things.map { Boo3($0, C()) }
+ let boos2 = things.map(Boo3.init)
+ print(testStructWithMultipleInits(boos1[0], boos2[0]))
+}
diff --git a/test/SILOptimizer/let_properties_opts_runtime.swift b/test/SILOptimizer/let_properties_opts_runtime.swift
index 67670c7..cbe8fad 100644
--- a/test/SILOptimizer/let_properties_opts_runtime.swift
+++ b/test/SILOptimizer/let_properties_opts_runtime.swift
@@ -1,6 +1,8 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: %target-build-swift -O %s -o %t/a.out
// RUN: %target-run %t/a.out | FileCheck %s -check-prefix=CHECK-OUTPUT
+// RUN: %target-build-swift -O -wmo %s -o %t/a.out
+// RUN: %target-run %t/a.out | FileCheck %s -check-prefix=CHECK-OUTPUT
// REQUIRES: executable_test
// Check that in optimized builds the compiler generates correct code for
@@ -48,3 +50,59 @@
// CHECK-OUTPUT: 400
print(testClassLet(Foo1(10)))
+public class C {}
+
+struct Boo3 {
+ //public
+ let Prop0: Int32
+ let Prop1: Int32
+ private let Prop2: Int32
+ internal let Prop3: Int32
+
+ @inline(__always)
+ init(_ f1: C, _ f2: C) {
+ self.Prop0 = 0
+ self.Prop1 = 1
+ self.Prop2 = 2
+ self.Prop3 = 3
+ }
+
+ init(_ v: C) {
+ self.Prop0 = 10
+ self.Prop1 = 11
+ self.Prop2 = 12
+ self.Prop3 = 13
+ }
+}
+
+// Check that the sum of properties is not folded into a constant.
+@inline(never)
+func testStructWithMultipleInits( _ boos1: Boo3, _ boos2: Boo3) -> Int32 {
+ // count1 = 0 + 1 + 2 + 3 = 6
+ // count2 = 10 + 11 + 12 + 13 = 46
+ // count1 + count2 = 6 + 46 = 52
+ let count1 = boos1.Prop0 + boos1.Prop1 + boos1.Prop2 + boos1.Prop3
+ let count2 = boos2.Prop0 + boos2.Prop1 + boos2.Prop2 + boos2.Prop3
+ return count1 + count2
+}
+
+public func testStructWithMultipleInitsAndInlinedInitializer() {
+ let things = [C()]
+ // This line results in inlinig of the initializer Boo3(C, C) and later
+ // removal of this initializer by the dead function elimination pass.
+ // As a result, only one initializer, Boo3(C) is seen by the Let Properties Propagation
+ // pass. This pass may think that there is only one intializer and take the
+ // values of let properties assigned there as constants and try to propagate
+ // those values into uses. But this is wrong! The pass should be clever enough
+ // to detect all stores to the let properties, including those outside of
+ // initializers, e.g. inside inlined initializers. And if it detects all such
+ // stores it should understand that values of let properties in Boo3 are not
+ // statically known constant initializers with the same value and thus
+ // cannot be propagated.
+ let boos1 = things.map { Boo3($0, C()) }
+ let boos2 = things.map(Boo3.init)
+ // CHECK-OUTPUT: 52
+ print(testStructWithMultipleInits(boos1[0], boos2[0]))
+}
+
+testStructWithMultipleInitsAndInlinedInitializer()
diff --git a/unittests/runtime/Metadata.cpp b/unittests/runtime/Metadata.cpp
index f5581ad..6481f3d 100644
--- a/unittests/runtime/Metadata.cpp
+++ b/unittests/runtime/Metadata.cpp
@@ -249,6 +249,23 @@
}
+TEST(MetadataAllocator, alloc_firstAllocationMoreThanPageSized) {
+ using swift::MetadataAllocator;
+ MetadataAllocator allocator;
+
+ // rdar://problem/21659505 -- if the first allocation from a metadata
+ // allocator was greater than page sized, a typo caused us to incorrectly
+ // flag an error.
+ uintptr_t pagesize = sysconf(_SC_PAGESIZE);
+ void *page = allocator.alloc(pagesize);
+ EXPECT_NE(page, nullptr);
+ EXPECT_NE(page, MAP_FAILED);
+ EXPECT_EQ(uintptr_t(page) & uintptr_t(pagesize-1), uintptr_t(0));
+
+ // Don't leak the page the allocator allocates.
+ munmap(page, pagesize);
+}
+
TEST(MetadataTest, getGenericMetadata) {
auto metadataTemplate = (GenericMetadata*) &MetadataTest1;
diff --git a/utils/build-presets.ini b/utils/build-presets.ini
index 486fff8..869e720 100644
--- a/utils/build-presets.ini
+++ b/utils/build-presets.ini
@@ -41,7 +41,6 @@
compiler-vendor=apple
-darwin-crash-reporter-client=0
install-swift
# Path to the root of the installation filesystem.
@@ -201,9 +200,6 @@
verbose-build
build-ninja
-# Don't build static standard library to speed up the build.
-build-swift-static-stdlib=0
-
build-swift-stdlib-unittest-extra
compiler-vendor=apple
@@ -408,18 +404,12 @@
# Build ninja while we are at it
build-ninja
-# Building a static stdlib would waste time.
-build-swift-static-stdlib=0
-
# We need to build the unittest extras so we can test
build-swift-stdlib-unittest-extra
# Set the vendor to apple
compiler-vendor=apple
-# Disable crash reporter. This will improve build time even more.
-darwin-crash-reporter-client=0
-
# Make sure our stdlib is RA.
swift-stdlib-build-type=RelWithDebInfo
swift-stdlib-enable-assertions=true
@@ -473,8 +463,6 @@
verbose-build
build-ninja
-# Don't build static standard library to speed up the build.
-build-swift-static-stdlib=0
build-swift-stdlib-unittest-extra
skip-build-ios
@@ -517,8 +505,6 @@
reconfigure
verbose-build
build-ninja
-# Don't build static standard library to speed up the build.
-build-swift-static-stdlib=0
build-swift-stdlib-unittest-extra
compiler-vendor=apple
swift-runtime-enable-leak-checker
diff --git a/validation-test/Evolution/Inputs/function_change_transparent_body.swift b/validation-test/Evolution/Inputs/function_change_transparent_body.swift
index 8fafa30..351b191 100644
--- a/validation-test/Evolution/Inputs/function_change_transparent_body.swift
+++ b/validation-test/Evolution/Inputs/function_change_transparent_body.swift
@@ -1,4 +1,12 @@
+public func getVersion() -> Int {
+#if BEFORE
+ return 0
+#else
+ return 1
+#endif
+}
+
@_transparent public func getBuildVersion() -> Int {
#if BEFORE
return 0
@@ -7,3 +15,29 @@
#endif
}
+public func getFunction(x: Int) -> Int -> Int {
+ // Force a re-abstraction thunk for (T -> T) => (Int -> Int) to be
+ // emitted from a non-transparent context first
+
+#if BEFORE
+ func id(y: Int) -> Int { return x * y }
+#else
+ func id<T>(t: T) -> T { return t }
+#endif
+
+ return id
+}
+
+@_transparent public func getTransparentFunction(x: Int) -> Int -> Int {
+ // The mangled name and calling convention of the local function
+ // will change -- so we must serialize it and inline it into
+ // the calling module
+
+#if BEFORE
+ func id(y: Int) -> Int { return x * y }
+#else
+ func id<T>(t: T) -> T { return t }
+#endif
+
+ return id
+}
diff --git a/validation-test/Evolution/test_function_change_transparent_body.swift b/validation-test/Evolution/test_function_change_transparent_body.swift
index 228a51b..81c62c3 100644
--- a/validation-test/Evolution/test_function_change_transparent_body.swift
+++ b/validation-test/Evolution/test_function_change_transparent_body.swift
@@ -21,9 +21,29 @@
ChangeTransparentBodyTest.test("ChangeTransparentBody") {
#if BEFORE
- expectEqual(getBuildVersion(), 0)
+ expectEqual(0, getBuildVersion())
#else
- expectEqual(getBuildVersion(), 1)
+ expectEqual(1, getBuildVersion())
+#endif
+
+}
+
+ChangeTransparentBodyTest.test("ChangeNonTransparentClosure") {
+
+ if getVersion() == 0 {
+ expectEqual(202, getFunction(2)(101))
+ } else {
+ expectEqual(101, getFunction(2)(101))
+ }
+
+}
+
+ChangeTransparentBodyTest.test("ChangeTransparentClosure") {
+
+#if BEFORE
+ expectEqual(202, getTransparentFunction(2)(101))
+#else
+ expectEqual(101, getTransparentFunction(2)(101))
#endif
}