mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Remove the extra-inhabitant value witness functions.
This is essentially a long-belated follow-up to Arnold's #12606. The key observation here is that the enum-tag-single-payload witnesses are strictly more powerful than the XI witnesses: you can simulate the XI witnesses by using an extra case count that's <= the XI count. Of course the result is less efficient than the XI witnesses, but that's less important than overall code size, and we can work on fast-paths for that. The extra inhabitant count is stored in a 32-bit field (always present) following the ValueWitnessFlags, which now occupy a fixed 32 bits. This inflates non-XI VWTs on 32-bit targets by a word, but the net effect on XI VWTs is to shrink them by two words, which is likely to be the more important change. Also, being able to access the XI count directly should be a nice win.
This commit is contained in:
@@ -260,9 +260,7 @@ optimization.
|
||||
0000000000023a40 T _swift_assignExistentialWithCopy
|
||||
000000000001dbf0 T _swift_copyPOD
|
||||
000000000001c560 T _swift_getEnumCaseMultiPayload
|
||||
000000000001be60 T _swift_getEnumCaseSinglePayload
|
||||
000000000001c400 T _swift_storeEnumTagMultiPayload
|
||||
000000000001bf90 T _swift_storeEnumTagSinglePayload
|
||||
```
|
||||
|
||||
## Type metadata lookup
|
||||
|
||||
@@ -295,10 +295,9 @@ public:
|
||||
// Handle the data witnesses explicitly so we can use more specific
|
||||
// types for the flags enums.
|
||||
typedef size_t size;
|
||||
typedef ValueWitnessFlags flags;
|
||||
typedef size_t stride;
|
||||
typedef ExtraInhabitantFlags extraInhabitantFlags;
|
||||
|
||||
typedef ValueWitnessFlags flags;
|
||||
typedef uint32_t extraInhabitantCount;
|
||||
};
|
||||
|
||||
struct TypeLayout;
|
||||
@@ -376,16 +375,9 @@ template <typename Runtime> struct TargetValueWitnessTable {
|
||||
|
||||
/// The number of extra inhabitants, that is, bit patterns that do not form
|
||||
/// valid values of the type, in this type's binary representation.
|
||||
unsigned getNumExtraInhabitants() const;
|
||||
|
||||
/// Assert that this value witness table is an extra-inhabitants
|
||||
/// value witness table and return it as such.
|
||||
///
|
||||
/// This has an awful name because it's supposed to be internal to
|
||||
/// this file. Code outside this file should use LLVM's cast/dyn_cast.
|
||||
/// We don't want to use those here because we need to avoid accidentally
|
||||
/// introducing ABI dependencies on LLVM structures.
|
||||
const struct ExtraInhabitantsValueWitnessTable *_asXIVWT() const;
|
||||
unsigned getNumExtraInhabitants() const {
|
||||
return extraInhabitantCount;
|
||||
}
|
||||
|
||||
/// Assert that this value witness table is an enum value witness table
|
||||
/// and return it as such.
|
||||
@@ -608,13 +600,6 @@ public:
|
||||
#define DATA_VALUE_WITNESS(LOWER, UPPER, TYPE)
|
||||
#include "swift/ABI/ValueWitness.def"
|
||||
|
||||
int vw_getExtraInhabitantIndex(const OpaqueValue *value) const {
|
||||
return getValueWitnesses()->_asXIVWT()->getExtraInhabitantIndex(value, this);
|
||||
}
|
||||
void vw_storeExtraInhabitant(OpaqueValue *value, int index) const {
|
||||
getValueWitnesses()->_asXIVWT()->storeExtraInhabitant(value, index, this);
|
||||
}
|
||||
|
||||
unsigned vw_getEnumTag(const OpaqueValue *value) const {
|
||||
return getValueWitnesses()->_asEVWT()->getEnumTag(const_cast<OpaqueValue*>(value), this);
|
||||
}
|
||||
@@ -637,6 +622,10 @@ public:
|
||||
return getValueWitnesses()->getStride();
|
||||
}
|
||||
|
||||
unsigned vw_getNumExtraInhabitants() const {
|
||||
return getValueWitnesses()->getNumExtraInhabitants();
|
||||
}
|
||||
|
||||
/// Allocate an out-of-line buffer if values of this type don't fit in the
|
||||
/// ValueBuffer.
|
||||
/// NOTE: This is not a box for copy-on-write existentials.
|
||||
|
||||
@@ -121,24 +121,27 @@ public:
|
||||
// flags of the field types can be mostly bitwise-or'ed together to derive the
|
||||
// flags for the struct. (The "non-inline" and "has-extra-inhabitants" bits
|
||||
// still require additional fixup.)
|
||||
enum : int_type {
|
||||
enum : uint32_t {
|
||||
AlignmentMask = 0x000000FF,
|
||||
// unused 0x0000FF00,
|
||||
IsNonPOD = 0x00010000,
|
||||
IsNonInline = 0x00020000,
|
||||
HasExtraInhabitants = 0x00040000,
|
||||
// unused 0x00040000,
|
||||
HasSpareBits = 0x00080000,
|
||||
IsNonBitwiseTakable = 0x00100000,
|
||||
HasEnumWitnesses = 0x00200000,
|
||||
Incomplete = 0x00400000,
|
||||
|
||||
// Everything else is reserved.
|
||||
// unused 0xFF800000,
|
||||
};
|
||||
|
||||
static constexpr const uint32_t MaxNumExtraInhabitants = 0x7FFFFFFF;
|
||||
|
||||
private:
|
||||
int_type Data;
|
||||
uint32_t Data;
|
||||
|
||||
explicit constexpr TargetValueWitnessFlags(uint32_t data) : Data(data) {}
|
||||
|
||||
public:
|
||||
explicit constexpr TargetValueWitnessFlags(int_type data) : Data(data) {}
|
||||
constexpr TargetValueWitnessFlags() : Data(0) {}
|
||||
|
||||
/// The required alignment of the first byte of an object of this
|
||||
@@ -192,22 +195,12 @@ public:
|
||||
return TargetValueWitnessFlags((Data & ~IsNonBitwiseTakable) |
|
||||
(isBT ? 0 : IsNonBitwiseTakable));
|
||||
}
|
||||
/// True if this type's binary representation has extra inhabitants, that is,
|
||||
/// bit patterns that do not form valid values of the type.
|
||||
///
|
||||
/// If true, then the extra inhabitant value witness table entries are
|
||||
/// available in this type's value witness table.
|
||||
bool hasExtraInhabitants() const { return Data & HasExtraInhabitants; }
|
||||
|
||||
/// True if this type's binary representation is that of an enum, and the
|
||||
/// enum value witness table entries are available in this type's value
|
||||
/// witness table.
|
||||
bool hasEnumWitnesses() const { return Data & HasEnumWitnesses; }
|
||||
constexpr TargetValueWitnessFlags
|
||||
withExtraInhabitants(bool hasExtraInhabitants) const {
|
||||
return TargetValueWitnessFlags((Data & ~HasExtraInhabitants) |
|
||||
(hasExtraInhabitants ? HasExtraInhabitants : 0));
|
||||
}
|
||||
constexpr TargetValueWitnessFlags
|
||||
withEnumWitnesses(bool hasEnumWitnesses) const {
|
||||
return TargetValueWitnessFlags((Data & ~HasEnumWitnesses) |
|
||||
(hasEnumWitnesses ? HasEnumWitnesses : 0));
|
||||
@@ -223,44 +216,12 @@ public:
|
||||
(isIncomplete ? Incomplete : 0));
|
||||
}
|
||||
|
||||
constexpr int_type getOpaqueValue() const { return Data; }
|
||||
static constexpr TargetValueWitnessFlags getFromOpaqueValue(int_type data) {
|
||||
return TargetValueWitnessFlags(data);
|
||||
constexpr uint32_t getOpaqueValue() const {
|
||||
return Data;
|
||||
}
|
||||
};
|
||||
using ValueWitnessFlags = TargetValueWitnessFlags<size_t>;
|
||||
|
||||
/// Flags stored in a value-witness table with extra inhabitants.
|
||||
template <typename int_type>
|
||||
class TargetExtraInhabitantFlags {
|
||||
public:
|
||||
enum : int_type {
|
||||
NumExtraInhabitantsMask = 0x7FFFFFFFU,
|
||||
ExtraInhabitantFlags
|
||||
};
|
||||
int_type Data;
|
||||
|
||||
constexpr TargetExtraInhabitantFlags(int_type data) : Data(data) {}
|
||||
|
||||
public:
|
||||
constexpr TargetExtraInhabitantFlags() : Data(0) {}
|
||||
/// The number of extra inhabitants in the type's representation.
|
||||
int getNumExtraInhabitants() const { return Data & NumExtraInhabitantsMask; }
|
||||
|
||||
constexpr TargetExtraInhabitantFlags
|
||||
withNumExtraInhabitants(unsigned numExtraInhabitants) const {
|
||||
return TargetExtraInhabitantFlags((Data & ~NumExtraInhabitantsMask) |
|
||||
numExtraInhabitants);
|
||||
}
|
||||
|
||||
constexpr int_type getOpaqueValue() const { return Data; }
|
||||
static constexpr TargetExtraInhabitantFlags getFromOpaqueValue(int_type data){
|
||||
return TargetExtraInhabitantFlags(data);
|
||||
}
|
||||
};
|
||||
using ExtraInhabitantFlags =
|
||||
TargetExtraInhabitantFlags<size_t>;
|
||||
|
||||
/// Flags for dynamic-cast operations.
|
||||
enum class DynamicCastFlags : size_t {
|
||||
/// All flags clear.
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#if defined(WANT_ALL_VALUE_WITNESSES)
|
||||
#undef WANT_ALL_VALUE_WITNESSES
|
||||
#define WANT_REQUIRED_VALUE_WITNESSES 1
|
||||
#define WANT_EXTRA_INHABITANT_VALUE_WITNESSES 1
|
||||
#define WANT_ENUM_VALUE_WITNESSES 1
|
||||
|
||||
/// WANT_ONLY_REQUIRED_VALUE_WITNESSES
|
||||
@@ -31,15 +30,6 @@
|
||||
#elif defined(WANT_ONLY_REQUIRED_VALUE_WITNESSES)
|
||||
#undef WANT_ONLY_REQUIRED_VALUE_WITNESSES
|
||||
#define WANT_REQUIRED_VALUE_WITNESSES 1
|
||||
#define WANT_EXTRA_INHABITANT_VALUE_WITNESSES 0
|
||||
#define WANT_ENUM_VALUE_WITNESSES 0
|
||||
|
||||
/// WANT_ONLY_EXTRA_INHABITANT_VALUE_WITNESSES
|
||||
/// Define this to expand only the extra-inhabitant value witnesses.
|
||||
#elif defined(WANT_ONLY_EXTRA_INHABITANT_VALUE_WITNESSES)
|
||||
#undef WANT_ONLY_EXTRA_INHABITANT_VALUE_WITNESSES
|
||||
#define WANT_REQUIRED_VALUE_WITNESSES 0
|
||||
#define WANT_EXTRA_INHABITANT_VALUE_WITNESSES 1
|
||||
#define WANT_ENUM_VALUE_WITNESSES 0
|
||||
|
||||
/// WANT_ONLY_ENUM_VALUE_WITNESSES
|
||||
@@ -47,15 +37,13 @@
|
||||
#elif defined(WANT_ONLY_ENUM_VALUE_WITNESSES)
|
||||
#undef WANT_ONLY_ENUM_VALUE_WITNESSES
|
||||
#define WANT_REQUIRED_VALUE_WITNESSES 0
|
||||
#define WANT_EXTRA_INHABITANT_VALUE_WITNESSES 0
|
||||
#define WANT_ENUM_VALUE_WITNESSES 1
|
||||
|
||||
/// WANT_REQUIRED_VALUE_WITNESSES
|
||||
/// WANT_EXTRA_INHABITANT_VALUE_WITNESSES
|
||||
/// WANT_ENUM_VALUE_WITNESSES
|
||||
/// Define all of these to control exactly what to expand.
|
||||
#else
|
||||
#if !defined(WANT_REQUIRED_VALUE_WITNESSES) || !defined(WANT_EXTRA_INHABITANT_VALUE_WITNESSES) || !defined(WANT_ENUM_VALUE_WITNESSES)
|
||||
#if !defined(WANT_REQUIRED_VALUE_WITNESSES) || !defined(WANT_ENUM_VALUE_WITNESSES)
|
||||
#error failed to define a WANT macro; possible typo?
|
||||
#endif
|
||||
#endif
|
||||
@@ -206,7 +194,16 @@ BEGIN_VALUE_WITNESS_RANGE(TypeLayoutWitness,
|
||||
BEGIN_VALUE_WITNESS_RANGE(RequiredTypeLayoutWitness,
|
||||
Size)
|
||||
|
||||
/// SIZE_TYPE flags;
|
||||
/// SIZE_TYPE stride;
|
||||
///
|
||||
/// The required size per element of an array of this type. It is at least
|
||||
/// one, even for zero-sized types, like the empty tuple.
|
||||
DATA_VALUE_WITNESS(stride,
|
||||
Stride,
|
||||
SIZE_TYPE)
|
||||
|
||||
|
||||
/// UINT_TYPE flags;
|
||||
///
|
||||
/// The ValueWitnessAlignmentMask bits represent the required
|
||||
/// alignment of the first byte of an object of this type, expressed
|
||||
@@ -222,10 +219,9 @@ BEGIN_VALUE_WITNESS_RANGE(RequiredTypeLayoutWitness,
|
||||
/// The ValueWitnessIsNonInline bit is set if the type cannot be
|
||||
/// represented in a fixed-size buffer or if it is not bitwise takable.
|
||||
///
|
||||
/// The Enum_HasExtraInhabitants bit is set if the type's binary
|
||||
/// representation has "extra inhabitants" that do not form valid values of
|
||||
/// the type, and the value witness table contains the ExtraInhabitantWitness
|
||||
/// entries.
|
||||
/// The ExtraInhabitantsMask bits represent the number of "extra inhabitants"
|
||||
/// of the bit representation of the value that do not form valid values of
|
||||
/// the type.
|
||||
///
|
||||
/// The Enum_HasSpareBits bit is set if the type's binary representation
|
||||
/// has unused bits.
|
||||
@@ -233,86 +229,25 @@ BEGIN_VALUE_WITNESS_RANGE(RequiredTypeLayoutWitness,
|
||||
/// The HasEnumWitnesses bit is set if the type is an enum type.
|
||||
DATA_VALUE_WITNESS(flags,
|
||||
Flags,
|
||||
SIZE_TYPE)
|
||||
UINT_TYPE)
|
||||
|
||||
/// SIZE_TYPE stride;
|
||||
/// UINT_TYPE extraInhabitantCount;
|
||||
///
|
||||
/// The required size per element of an array of this type. It is at least
|
||||
/// one, even for zero-sized types, like the empty tuple.
|
||||
DATA_VALUE_WITNESS(stride,
|
||||
Stride,
|
||||
SIZE_TYPE)
|
||||
/// The number of extra inhabitants in the type.
|
||||
DATA_VALUE_WITNESS(extraInhabitantCount,
|
||||
ExtraInhabitantCount,
|
||||
UINT_TYPE)
|
||||
|
||||
END_VALUE_WITNESS_RANGE(RequiredTypeLayoutWitness,
|
||||
Stride)
|
||||
ExtraInhabitantCount)
|
||||
|
||||
END_VALUE_WITNESS_RANGE(RequiredValueWitness,
|
||||
Stride)
|
||||
|
||||
#endif /* WANT_REQUIRED_VALUE_WITNESSES */
|
||||
|
||||
#if WANT_EXTRA_INHABITANT_VALUE_WITNESSES
|
||||
|
||||
// The following value witnesses are conditionally present based on
|
||||
// the Enum_HasExtraInhabitants bit of the flags.
|
||||
|
||||
/// SIZE_TYPE extraInhabitantFlags;
|
||||
///
|
||||
/// These bits are always present if the extra inhabitants witnesses are:
|
||||
///
|
||||
/// - The NumExtraInhabitantsMask bits contain the number of extra
|
||||
/// inhabitants of the type representation.
|
||||
///
|
||||
/// If the Enum_HasSpareBits flag is set in the value witness flags, these
|
||||
/// additional flags are available:
|
||||
///
|
||||
/// - The NumSpareBitsMask bits contain the number of (host-endian) contiguous
|
||||
/// spare bits in the type representation.
|
||||
/// - The SpareBitsShiftMask bits contain the (host-endian) bit offset of the
|
||||
/// lowest spare bit.
|
||||
DATA_VALUE_WITNESS(extraInhabitantFlags,
|
||||
ExtraInhabitantFlags,
|
||||
SIZE_TYPE)
|
||||
|
||||
BEGIN_VALUE_WITNESS_RANGE(ExtraInhabitantValueWitness,
|
||||
ExtraInhabitantFlags)
|
||||
ExtraInhabitantCount)
|
||||
|
||||
END_VALUE_WITNESS_RANGE(TypeLayoutWitness,
|
||||
ExtraInhabitantFlags)
|
||||
ExtraInhabitantCount)
|
||||
|
||||
/// void (*storeExtraInhabitant)(T *obj, int index, M *self);
|
||||
///
|
||||
/// Given an invalid object of this type, store the representation of an
|
||||
/// extra inhabitant of the type. The object will remain invalid, because
|
||||
/// an extra inhabitant is by definition an invalid representation of the
|
||||
/// type. index must be less than numExtraInhabitants.
|
||||
FUNCTION_VALUE_WITNESS(storeExtraInhabitant,
|
||||
StoreExtraInhabitant,
|
||||
VOID_TYPE,
|
||||
(MUTABLE_VALUE_TYPE, INT_TYPE, TYPE_TYPE))
|
||||
|
||||
BEGIN_VALUE_WITNESS_RANGE(ExtraInhabitantValueWitnessFunction,
|
||||
StoreExtraInhabitant)
|
||||
|
||||
/// int (*getExtraInhabitantIndex)(T *obj, M *self);
|
||||
///
|
||||
/// Given an invalid object of this type with an extra inhabitant
|
||||
/// representation, returns the index of the extra inhabitant representation.
|
||||
/// Returns -1 if the object is a valid value of the type. If non-negative,
|
||||
/// the return value is the same index that can be passed to
|
||||
/// storeExtraInhabitant to reproduce the representation.
|
||||
FUNCTION_VALUE_WITNESS(getExtraInhabitantIndex,
|
||||
GetExtraInhabitantIndex,
|
||||
INT_TYPE,
|
||||
(IMMUTABLE_VALUE_TYPE, TYPE_TYPE))
|
||||
|
||||
END_VALUE_WITNESS_RANGE(ExtraInhabitantValueWitnessFunction,
|
||||
GetExtraInhabitantIndex)
|
||||
|
||||
END_VALUE_WITNESS_RANGE(ExtraInhabitantValueWitness,
|
||||
GetExtraInhabitantIndex)
|
||||
|
||||
#endif /* WANT_EXTRA_INHABITANT_VALUE_WITNESSES */
|
||||
#endif /* WANT_REQUIRED_VALUE_WITNESSES */
|
||||
|
||||
#if WANT_ENUM_VALUE_WITNESSES
|
||||
|
||||
@@ -372,9 +307,7 @@ END_VALUE_WITNESS_RANGE(ValueWitness,
|
||||
#undef FUNCTION_VALUE_WITNESS
|
||||
#undef VALUE_WITNESS
|
||||
#undef ENUM_VALUE_WITNESS
|
||||
#undef EXTRA_INHABITANT_VALUE_WITNESS
|
||||
#undef NON_REQUIRED_VALUE_WITNESS
|
||||
#undef REQUIRED_VALUE_WITNESS
|
||||
#undef WANT_ENUM_VALUE_WITNESSES
|
||||
#undef WANT_EXTRA_INHABITANT_VALUE_WITNESSES
|
||||
#undef WANT_REQUIRED_VALUE_WITNESSES
|
||||
|
||||
@@ -58,37 +58,42 @@ void swift_initEnumMetadataSinglePayload(EnumMetadata *enumType,
|
||||
const TypeLayout *payload,
|
||||
unsigned emptyCases);
|
||||
|
||||
/// Faster variant of the above which avoids digging into the enum type
|
||||
/// metadata when the caller already has the payload information handy.
|
||||
/// Implement getEnumTagSinglePayload generically in terms of a
|
||||
/// payload type with a getExtraInhabitantIndex function.
|
||||
///
|
||||
/// \param value - pointer to the enum value.
|
||||
/// \param payload - type metadata for the payload case of the enum.
|
||||
/// \param payloadType - type metadata for the payload case of the enum.
|
||||
/// \param emptyCases - the number of empty cases in the enum.
|
||||
///
|
||||
/// \returns 0 if the payload case is inhabited. If an empty case is inhabited,
|
||||
/// returns a value greater than or equal to one and less than or equal
|
||||
/// emptyCases.
|
||||
SWIFT_RUNTIME_EXPORT
|
||||
unsigned swift_getEnumCaseSinglePayload(const OpaqueValue *value,
|
||||
const Metadata *payload,
|
||||
unsigned emptyCases);
|
||||
unsigned swift_getEnumTagSinglePayloadGeneric(const OpaqueValue *value,
|
||||
unsigned emptyCases,
|
||||
const Metadata *payloadType,
|
||||
unsigned (*getExtraInhabitantTag)(const OpaqueValue *value,
|
||||
const Metadata *payloadType));
|
||||
|
||||
/// Store the tag value for the given case into a single-payload enum,
|
||||
/// whose associated payload (if any) has already been initialized.
|
||||
/// Implement storeEnumTagSinglePayload generically in terms of a
|
||||
/// payload type with a storeExtraInhabitant function.
|
||||
///
|
||||
/// \param value - pointer to the enum value. If the case being initialized is
|
||||
/// the payload case (0), then the payload should be
|
||||
/// initialized.
|
||||
/// \param payload - type metadata for the payload case of the enum.
|
||||
/// \param payloadType - type metadata for the payload case of the enum.
|
||||
/// \param whichCase - unique value identifying the case. 0 for the payload
|
||||
/// case, or a value greater than or equal to one and less
|
||||
/// than or equal emptyCases for an empty case.
|
||||
/// \param emptyCases - the number of empty cases in the enum.
|
||||
SWIFT_RUNTIME_EXPORT
|
||||
void swift_storeEnumTagSinglePayload(OpaqueValue *value,
|
||||
const Metadata *payload,
|
||||
unsigned whichCase,
|
||||
unsigned emptyCases);
|
||||
void swift_storeEnumTagSinglePayloadGeneric(OpaqueValue *value,
|
||||
unsigned whichCase,
|
||||
unsigned emptyCases,
|
||||
const Metadata *payloadType,
|
||||
void (*storeExtraInhabitantTag)(OpaqueValue *value,
|
||||
unsigned whichCase,
|
||||
const Metadata *payloadType));
|
||||
|
||||
/// Initialize the type metadata for a generic, multi-payload
|
||||
/// enum instance.
|
||||
|
||||
@@ -90,56 +90,26 @@ OpaqueValue *swift_copyPOD(OpaqueValue *dest,
|
||||
OpaqueValue *src,
|
||||
const Metadata *self);
|
||||
|
||||
/// A value-witness table with extra inhabitants entry points.
|
||||
/// These entry points are available only if the HasExtraInhabitants flag bit is
|
||||
/// set in the 'flags' field.
|
||||
struct ExtraInhabitantsValueWitnessTable : ValueWitnessTable {
|
||||
#define WANT_ONLY_EXTRA_INHABITANT_VALUE_WITNESSES
|
||||
#define VALUE_WITNESS(LOWER_ID, UPPER_ID) \
|
||||
ValueWitnessTypes::LOWER_ID LOWER_ID;
|
||||
#include "swift/ABI/ValueWitness.def"
|
||||
|
||||
#define SET_WITNESS(NAME) base.NAME,
|
||||
|
||||
constexpr ExtraInhabitantsValueWitnessTable()
|
||||
: ValueWitnessTable{}, extraInhabitantFlags(),
|
||||
storeExtraInhabitant(nullptr),
|
||||
getExtraInhabitantIndex(nullptr) {}
|
||||
constexpr ExtraInhabitantsValueWitnessTable(
|
||||
const ValueWitnessTable &base,
|
||||
ValueWitnessTypes::extraInhabitantFlags eif,
|
||||
ValueWitnessTypes::storeExtraInhabitant sei,
|
||||
ValueWitnessTypes::getExtraInhabitantIndex geii)
|
||||
: ValueWitnessTable(base),
|
||||
extraInhabitantFlags(eif),
|
||||
storeExtraInhabitant(sei),
|
||||
getExtraInhabitantIndex(geii) {}
|
||||
|
||||
static bool classof(const ValueWitnessTable *table) {
|
||||
return table->flags.hasExtraInhabitants();
|
||||
}
|
||||
};
|
||||
|
||||
/// A value-witness table with enum entry points.
|
||||
/// These entry points are available only if the HasEnumWitnesses flag bit is
|
||||
/// set in the 'flags' field.
|
||||
struct EnumValueWitnessTable : ExtraInhabitantsValueWitnessTable {
|
||||
struct EnumValueWitnessTable : ValueWitnessTable {
|
||||
#define WANT_ONLY_ENUM_VALUE_WITNESSES
|
||||
#define VALUE_WITNESS(LOWER_ID, UPPER_ID) \
|
||||
ValueWitnessTypes::LOWER_ID LOWER_ID;
|
||||
#include "swift/ABI/ValueWitness.def"
|
||||
|
||||
constexpr EnumValueWitnessTable()
|
||||
: ExtraInhabitantsValueWitnessTable(),
|
||||
: ValueWitnessTable{},
|
||||
getEnumTag(nullptr),
|
||||
destructiveProjectEnumData(nullptr),
|
||||
destructiveInjectEnumTag(nullptr) {}
|
||||
constexpr EnumValueWitnessTable(
|
||||
const ExtraInhabitantsValueWitnessTable &base,
|
||||
const ValueWitnessTable &base,
|
||||
ValueWitnessTypes::getEnumTag getEnumTag,
|
||||
ValueWitnessTypes::destructiveProjectEnumData destructiveProjectEnumData,
|
||||
ValueWitnessTypes::destructiveInjectEnumTag destructiveInjectEnumTag)
|
||||
: ExtraInhabitantsValueWitnessTable(base),
|
||||
: ValueWitnessTable(base),
|
||||
getEnumTag(getEnumTag),
|
||||
destructiveProjectEnumData(destructiveProjectEnumData),
|
||||
destructiveInjectEnumTag(destructiveInjectEnumTag) {}
|
||||
@@ -155,47 +125,44 @@ struct EnumValueWitnessTable : ExtraInhabitantsValueWitnessTable {
|
||||
/// extra inhabitants, and miscellaneous flags about the type.
|
||||
struct TypeLayout {
|
||||
ValueWitnessTypes::size size;
|
||||
ValueWitnessTypes::flags flags;
|
||||
ValueWitnessTypes::stride stride;
|
||||
ValueWitnessTypes::flags flags;
|
||||
ValueWitnessTypes::extraInhabitantCount extraInhabitantCount;
|
||||
|
||||
private:
|
||||
// Only available if the "hasExtraInhabitants" flag is set.
|
||||
ValueWitnessTypes::extraInhabitantFlags extraInhabitantFlags;
|
||||
|
||||
void _static_assert_layout();
|
||||
public:
|
||||
TypeLayout() = default;
|
||||
constexpr TypeLayout(ValueWitnessTypes::size size,
|
||||
ValueWitnessTypes::flags flags,
|
||||
ValueWitnessTypes::stride stride,
|
||||
ValueWitnessTypes::extraInhabitantFlags eiFlags =
|
||||
ValueWitnessTypes::extraInhabitantFlags())
|
||||
: size(size), flags(flags), stride(stride),
|
||||
extraInhabitantFlags(eiFlags) {}
|
||||
|
||||
ValueWitnessTypes::extraInhabitantFlags getExtraInhabitantFlags() const {
|
||||
assert(flags.hasExtraInhabitants());
|
||||
return extraInhabitantFlags;
|
||||
}
|
||||
ValueWitnessTypes::flags flags,
|
||||
ValueWitnessTypes::extraInhabitantCount xiCount)
|
||||
: size(size), stride(stride), flags(flags), extraInhabitantCount(xiCount) {}
|
||||
|
||||
const TypeLayout *getTypeLayout() const { return this; }
|
||||
|
||||
/// The number of extra inhabitants, that is, bit patterns that do not form
|
||||
/// valid values of the type, in this type's binary representation.
|
||||
unsigned getNumExtraInhabitants() const;
|
||||
unsigned getNumExtraInhabitants() const {
|
||||
return extraInhabitantCount;
|
||||
}
|
||||
|
||||
bool hasExtraInhabitants() const {
|
||||
return extraInhabitantCount != 0;
|
||||
}
|
||||
};
|
||||
|
||||
inline void TypeLayout::_static_assert_layout() {
|
||||
#define CHECK_TYPE_LAYOUT_OFFSET(FIELD) \
|
||||
static_assert(offsetof(ExtraInhabitantsValueWitnessTable, FIELD) \
|
||||
- offsetof(ExtraInhabitantsValueWitnessTable, size) \
|
||||
static_assert(offsetof(ValueWitnessTable, FIELD) \
|
||||
- offsetof(ValueWitnessTable, size) \
|
||||
== offsetof(TypeLayout, FIELD), \
|
||||
"layout of " #FIELD " in TypeLayout doesn't match " \
|
||||
"value witness table")
|
||||
CHECK_TYPE_LAYOUT_OFFSET(size);
|
||||
CHECK_TYPE_LAYOUT_OFFSET(flags);
|
||||
CHECK_TYPE_LAYOUT_OFFSET(extraInhabitantCount);
|
||||
CHECK_TYPE_LAYOUT_OFFSET(stride);
|
||||
CHECK_TYPE_LAYOUT_OFFSET(extraInhabitantFlags);
|
||||
|
||||
#undef CHECK_TYPE_LAYOUT_OFFSET
|
||||
}
|
||||
@@ -204,6 +171,7 @@ template <>
|
||||
inline void ValueWitnessTable::publishLayout(const TypeLayout &layout) {
|
||||
size = layout.size;
|
||||
stride = layout.stride;
|
||||
extraInhabitantCount = layout.extraInhabitantCount;
|
||||
|
||||
// Currently there is nothing in the runtime or ABI which tries to
|
||||
// asynchronously check completion, so we can just do a normal store here.
|
||||
@@ -220,54 +188,33 @@ template <> inline bool ValueWitnessTable::checkIsComplete() const {
|
||||
return !flags.isIncomplete();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const ExtraInhabitantsValueWitnessTable *
|
||||
ValueWitnessTable::_asXIVWT() const {
|
||||
assert(ExtraInhabitantsValueWitnessTable::classof(this));
|
||||
return static_cast<const ExtraInhabitantsValueWitnessTable *>(this);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const EnumValueWitnessTable *ValueWitnessTable::_asEVWT() const {
|
||||
assert(EnumValueWitnessTable::classof(this));
|
||||
return static_cast<const EnumValueWitnessTable *>(this);
|
||||
}
|
||||
|
||||
template <> inline unsigned ValueWitnessTable::getNumExtraInhabitants() const {
|
||||
// If the table does not have extra inhabitant witnesses, then there are zero.
|
||||
if (!flags.hasExtraInhabitants())
|
||||
return 0;
|
||||
return this->_asXIVWT()->extraInhabitantFlags.getNumExtraInhabitants();
|
||||
}
|
||||
|
||||
inline unsigned TypeLayout::getNumExtraInhabitants() const {
|
||||
// If the table does not have extra inhabitant witnesses, then there are zero.
|
||||
if (!flags.hasExtraInhabitants())
|
||||
return 0;
|
||||
return extraInhabitantFlags.getNumExtraInhabitants();
|
||||
}
|
||||
|
||||
// Standard value-witness tables.
|
||||
|
||||
#define BUILTIN_TYPE(Symbol, _) \
|
||||
SWIFT_RUNTIME_EXPORT const ValueWitnessTable VALUE_WITNESS_SYM(Symbol);
|
||||
#define BUILTIN_POINTER_TYPE(Symbol, _) \
|
||||
SWIFT_RUNTIME_EXPORT const ExtraInhabitantsValueWitnessTable VALUE_WITNESS_SYM(Symbol);
|
||||
SWIFT_RUNTIME_EXPORT const ValueWitnessTable VALUE_WITNESS_SYM(Symbol);
|
||||
#include "swift/Runtime/BuiltinTypes.def"
|
||||
|
||||
// The () -> () table can be used for arbitrary function types.
|
||||
SWIFT_RUNTIME_EXPORT
|
||||
const ExtraInhabitantsValueWitnessTable
|
||||
const ValueWitnessTable
|
||||
VALUE_WITNESS_SYM(FUNCTION_MANGLING); // () -> ()
|
||||
|
||||
// The @escaping () -> () table can be used for arbitrary escaping function types.
|
||||
SWIFT_RUNTIME_EXPORT
|
||||
const ExtraInhabitantsValueWitnessTable
|
||||
const ValueWitnessTable
|
||||
VALUE_WITNESS_SYM(NOESCAPE_FUNCTION_MANGLING); // @noescape () -> ()
|
||||
|
||||
// The @convention(thin) () -> () table can be used for arbitrary thin function types.
|
||||
SWIFT_RUNTIME_EXPORT
|
||||
const ExtraInhabitantsValueWitnessTable
|
||||
const ValueWitnessTable
|
||||
VALUE_WITNESS_SYM(THIN_FUNCTION_MANGLING); // @convention(thin) () -> ()
|
||||
|
||||
// The () table can be used for arbitrary empty types.
|
||||
@@ -276,7 +223,7 @@ const ValueWitnessTable VALUE_WITNESS_SYM(EMPTY_TUPLE_MANGLING); // ()
|
||||
|
||||
// The table for aligned-pointer-to-pointer types.
|
||||
SWIFT_RUNTIME_EXPORT
|
||||
const ExtraInhabitantsValueWitnessTable METATYPE_VALUE_WITNESS_SYM(Bo); // Builtin.NativeObject.Type
|
||||
const ValueWitnessTable METATYPE_VALUE_WITNESS_SYM(Bo); // Builtin.NativeObject.Type
|
||||
|
||||
/// Return the value witnesses for unmanaged pointers.
|
||||
static inline const ValueWitnessTable &getUnmanagedPointerValueWitnesses() {
|
||||
@@ -289,7 +236,7 @@ static inline const ValueWitnessTable &getUnmanagedPointerValueWitnesses() {
|
||||
|
||||
/// Return value witnesses for a pointer-aligned pointer type.
|
||||
static inline
|
||||
const ExtraInhabitantsValueWitnessTable &
|
||||
const ValueWitnessTable &
|
||||
getUnmanagedPointerPointerValueWitnesses() {
|
||||
return METATYPE_VALUE_WITNESS_SYM(Bo);
|
||||
}
|
||||
|
||||
@@ -863,15 +863,6 @@ FUNCTION(InitEnumMetadataMultiPayload,
|
||||
ARGS(TypeMetadataPtrTy, SizeTy, SizeTy, Int8PtrPtrTy->getPointerTo(0)),
|
||||
ATTRS(NoUnwind))
|
||||
|
||||
// int swift_getEnumCaseSinglePayload(opaque_t *obj, Metadata *payload,
|
||||
// unsigned num_empty_cases);
|
||||
FUNCTION(GetEnumCaseSinglePayload,
|
||||
swift_getEnumCaseSinglePayload,
|
||||
C_CC,
|
||||
RETURNS(Int32Ty),
|
||||
ARGS(OpaquePtrTy, TypeMetadataPtrTy, Int32Ty),
|
||||
ATTRS(NoUnwind, ReadOnly))
|
||||
|
||||
// int swift_getEnumCaseMultiPayload(opaque_t *obj, Metadata *enumTy);
|
||||
FUNCTION(GetEnumCaseMultiPayload,
|
||||
swift_getEnumCaseMultiPayload,
|
||||
@@ -880,14 +871,36 @@ FUNCTION(GetEnumCaseMultiPayload,
|
||||
ARGS(OpaquePtrTy, TypeMetadataPtrTy),
|
||||
ATTRS(NoUnwind, ReadOnly))
|
||||
|
||||
// void swift_storeEnumTagSinglePayload(opaque_t *obj, Metadata *payload,
|
||||
// unsigned case_index,
|
||||
// unsigned num_empty_cases);
|
||||
FUNCTION(StoreEnumTagSinglePayload,
|
||||
swift_storeEnumTagSinglePayload,
|
||||
// int swift_getEnumTagSinglePayloadGeneric(opaque_t *obj,
|
||||
// unsigned num_empty_cases,
|
||||
// Metadata *payloadType,
|
||||
// int (*getExtraInhabitantIndex)(opaque_t *obj,
|
||||
// Metadata *payload));
|
||||
FUNCTION(GetEnumTagSinglePayloadGeneric,
|
||||
swift_getEnumTagSinglePayloadGeneric,
|
||||
C_CC,
|
||||
RETURNS(Int32Ty),
|
||||
ARGS(OpaquePtrTy, Int32Ty, TypeMetadataPtrTy,
|
||||
llvm::FunctionType::get(Int32Ty, {OpaquePtrTy, TypeMetadataPtrTy},
|
||||
false)->getPointerTo()),
|
||||
ATTRS(NoUnwind, ReadOnly))
|
||||
|
||||
|
||||
// void swift_storeEnumTagSinglePayloadGeneric(opaque_t *obj,
|
||||
// unsigned case_index,
|
||||
// unsigned num_empty_cases,
|
||||
// Metadata *payloadType,
|
||||
// void (*storeExtraInhabitant)(opaque_t *obj,
|
||||
// unsigned case_index,
|
||||
// Metadata *payload));
|
||||
FUNCTION(StoreEnumTagSinglePayloadGeneric,
|
||||
swift_storeEnumTagSinglePayloadGeneric,
|
||||
C_CC,
|
||||
RETURNS(VoidTy),
|
||||
ARGS(OpaquePtrTy, TypeMetadataPtrTy, Int32Ty, Int32Ty),
|
||||
ARGS(OpaquePtrTy, Int32Ty, Int32Ty, TypeMetadataPtrTy,
|
||||
llvm::FunctionType::get(VoidTy, {OpaquePtrTy, Int32Ty,
|
||||
TypeMetadataPtrTy},
|
||||
false)->getPointerTo()),
|
||||
ATTRS(NoUnwind))
|
||||
|
||||
// void swift_storeEnumTagMultiPayload(opaque_t *obj, Metadata *enumTy,
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "IRGenModule.h"
|
||||
#include "IRGenFunction.h"
|
||||
#include "SwiftTargetInfo.h"
|
||||
#include "swift/ABI/MetadataValues.h"
|
||||
|
||||
using namespace swift;
|
||||
using namespace irgen;
|
||||
@@ -44,8 +45,9 @@ static unsigned getPointerExtraInhabitantCount(const IRGenModule &IGM,
|
||||
uint64_t rawCount =
|
||||
IGM.TargetInfo.LeastValidPointerValue >> numReservedLowBits;
|
||||
|
||||
// The runtime limits the count to INT_MAX.
|
||||
return std::min((uint64_t)INT_MAX, rawCount);
|
||||
// The runtime limits the count.
|
||||
return std::min(uint64_t(ValueWitnessFlags::MaxNumExtraInhabitants),
|
||||
rawCount);
|
||||
}
|
||||
|
||||
unsigned irgen::getHeapObjectExtraInhabitantCount(const IRGenModule &IGM) {
|
||||
|
||||
@@ -167,9 +167,9 @@ public:
|
||||
|
||||
/// Map an extra inhabitant representation in memory to a unique 31-bit
|
||||
/// identifier, and map a valid representation of the type to -1.
|
||||
llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
|
||||
Address src, SILType T,
|
||||
bool isOutlined) const override {
|
||||
virtual llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
|
||||
Address src, SILType T,
|
||||
bool isOutlined) const {
|
||||
return getSpareBitExtraInhabitantIndex(IGF, src);
|
||||
}
|
||||
|
||||
@@ -180,10 +180,10 @@ public:
|
||||
|
||||
/// Store the extra inhabitant representation indexed by a 31-bit identifier
|
||||
/// to memory.
|
||||
void storeExtraInhabitant(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
Address dest, SILType T,
|
||||
bool isOutlined) const override {
|
||||
virtual void storeExtraInhabitant(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
Address dest, SILType T,
|
||||
bool isOutlined) const {
|
||||
storeSpareBitExtraInhabitant(IGF, index, dest);
|
||||
}
|
||||
|
||||
@@ -236,16 +236,30 @@ public:
|
||||
llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr,
|
||||
SILType T) const override;
|
||||
SILType T,
|
||||
bool isOutlined) const override;
|
||||
|
||||
void storeEnumTagSinglePayload(IRGenFunction &IGF, llvm::Value *whichCase,
|
||||
llvm::Value *numEmptyCases, Address enumAddr,
|
||||
SILType T) const override;
|
||||
SILType T, bool isOutlined) const override;
|
||||
|
||||
static bool classof(const FixedTypeInfo *type) { return true; }
|
||||
static bool classof(const TypeInfo *type) { return type->isFixedSize(); }
|
||||
};
|
||||
|
||||
llvm::Value *getFixedTypeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
const FixedTypeInfo &fixedTI,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr,
|
||||
SILType T, bool isOutlined);
|
||||
|
||||
void storeFixedTypeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
const FixedTypeInfo &fixedTI,
|
||||
llvm::Value *index,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr,
|
||||
SILType T, bool isOutlined);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -649,7 +649,7 @@ namespace {
|
||||
return llvm::ConstantInt::getSigned(IGF.IGM.Int32Ty, -1);
|
||||
}
|
||||
|
||||
return getSingleton()->getExtraInhabitantIndex(IGF,
|
||||
return getFixedSingleton()->getExtraInhabitantIndex(IGF,
|
||||
getSingletonAddress(IGF, src),
|
||||
getSingletonType(IGF.IGM, T),
|
||||
isOutlined);
|
||||
@@ -663,10 +663,44 @@ namespace {
|
||||
// Nothing to store for empty singletons.
|
||||
return;
|
||||
}
|
||||
getSingleton()->storeExtraInhabitant(IGF, index,
|
||||
getSingletonAddress(IGF, dest),
|
||||
getSingletonType(IGF.IGM, T),
|
||||
getFixedSingleton()->storeExtraInhabitant(IGF, index,
|
||||
getSingletonAddress(IGF, dest),
|
||||
getSingletonType(IGF.IGM, T),
|
||||
isOutlined);
|
||||
}
|
||||
|
||||
llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address src, SILType T,
|
||||
bool isOutlined) const override {
|
||||
if (!getSingleton()) {
|
||||
return getFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
|
||||
numEmptyCases, src, T,
|
||||
isOutlined);
|
||||
}
|
||||
|
||||
return getSingleton()->getEnumTagSinglePayload(IGF, numEmptyCases,
|
||||
getSingletonAddress(IGF, src),
|
||||
getSingletonType(IGF.IGM, T),
|
||||
isOutlined);
|
||||
}
|
||||
|
||||
void storeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address src, SILType T,
|
||||
bool isOutlined) const override {
|
||||
if (!getSingleton()) {
|
||||
storeFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
|
||||
index, numEmptyCases, src, T,
|
||||
isOutlined);
|
||||
return;
|
||||
}
|
||||
|
||||
getSingleton()->storeEnumTagSinglePayload(IGF, index, numEmptyCases,
|
||||
getSingletonAddress(IGF, src),
|
||||
getSingletonType(IGF.IGM, T),
|
||||
isOutlined);
|
||||
}
|
||||
|
||||
unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override {
|
||||
@@ -1007,7 +1041,9 @@ namespace {
|
||||
assert(bits < 32 && "freakishly huge no-payload enum");
|
||||
|
||||
size_t shifted = static_cast<size_t>(static_cast<size_t>(1) << bits);
|
||||
return shifted - ElementsWithNoPayload.size();
|
||||
size_t rawCount = shifted - ElementsWithNoPayload.size();
|
||||
return std::min(rawCount,
|
||||
size_t(ValueWitnessFlags::MaxNumExtraInhabitants));
|
||||
}
|
||||
|
||||
APInt getFixedExtraInhabitantValue(IRGenModule &IGM,
|
||||
@@ -1061,6 +1097,25 @@ namespace {
|
||||
llvm::ConstantInt::get(payloadTy, ElementsWithNoPayload.size()));
|
||||
IGF.Builder.CreateStore(index, dest);
|
||||
}
|
||||
|
||||
llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address src, SILType T,
|
||||
bool isOutlined) const override {
|
||||
return getFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
|
||||
numEmptyCases, src, T,
|
||||
isOutlined);
|
||||
}
|
||||
|
||||
void storeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address src, SILType T,
|
||||
bool isOutlined) const override {
|
||||
storeFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
|
||||
index, numEmptyCases, src, T,
|
||||
isOutlined);
|
||||
}
|
||||
};
|
||||
|
||||
/// Implementation strategy for C-compatible enums, where none of the cases
|
||||
@@ -1137,6 +1192,25 @@ namespace {
|
||||
llvm_unreachable("no extra inhabitants");
|
||||
}
|
||||
|
||||
llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address src, SILType T,
|
||||
bool isOutlined) const override {
|
||||
return getFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
|
||||
numEmptyCases, src, T,
|
||||
isOutlined);
|
||||
}
|
||||
|
||||
void storeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address src, SILType T,
|
||||
bool isOutlined) const override {
|
||||
storeFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
|
||||
index, numEmptyCases, src, T,
|
||||
isOutlined);
|
||||
}
|
||||
|
||||
bool isReflectable() const override {
|
||||
// C enums have arbitrary values and we don't preserve the mapping
|
||||
// between the case and raw value at runtime, so don't mark it as
|
||||
@@ -2927,10 +3001,17 @@ namespace {
|
||||
bool isOutlined) const override {
|
||||
auto payload = projectPayloadData(IGF, src);
|
||||
llvm::Value *index
|
||||
= getPayloadTypeInfo().getExtraInhabitantIndex(IGF, payload,
|
||||
getPayloadType(IGM, T),
|
||||
= getFixedPayloadTypeInfo().getExtraInhabitantIndex(IGF, payload,
|
||||
getPayloadType(IGF.IGM, T),
|
||||
isOutlined);
|
||||
|
||||
return adjustPayloadExtraInhabitantIndex(IGF, index);
|
||||
}
|
||||
|
||||
/// Given an extra inhabitant index for the payload type, adjust it to
|
||||
/// be an appropriate extra inhabitant index for the enum type.
|
||||
llvm::Value *adjustPayloadExtraInhabitantIndex(IRGenFunction &IGF,
|
||||
llvm::Value *index) const {
|
||||
// Offset the payload extra inhabitant index by the number of inhabitants
|
||||
// we used. If less than zero, it's a valid value of the enum type.
|
||||
index = IGF.Builder.CreateSub(index,
|
||||
@@ -2947,16 +3028,152 @@ namespace {
|
||||
llvm::Value *index,
|
||||
Address dest, SILType T,
|
||||
bool isOutlined) const override {
|
||||
// Offset the index to skip the extra inhabitants we used.
|
||||
index = IGF.Builder.CreateAdd(index,
|
||||
llvm::ConstantInt::get(IGM.Int32Ty, ElementsWithNoPayload.size()));
|
||||
|
||||
index = adjustExtraInhabitantIndexForPayload(IGF, index);
|
||||
auto payload = projectPayloadData(IGF, dest);
|
||||
getPayloadTypeInfo().storeExtraInhabitant(IGF, index, payload,
|
||||
getPayloadType(IGM, T),
|
||||
getFixedPayloadTypeInfo().storeExtraInhabitant(IGF, index, payload,
|
||||
getPayloadType(IGF.IGM, T),
|
||||
isOutlined);
|
||||
}
|
||||
|
||||
|
||||
/// Given an extra inhabitant index, adjust it to be an appropriate
|
||||
/// extra inhabitant index for the payload type.
|
||||
llvm::Value *adjustExtraInhabitantIndexForPayload(IRGenFunction &IGF,
|
||||
llvm::Value *index) const{
|
||||
// Skip the extra inhabitants this enum uses.
|
||||
index = IGF.Builder.CreateAdd(index,
|
||||
llvm::ConstantInt::get(IGF.IGM.Int32Ty, ElementsWithNoPayload.size()));
|
||||
return index;
|
||||
}
|
||||
|
||||
llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address addr, SILType T,
|
||||
bool isOutlined) const override {
|
||||
if (TIK >= Fixed) {
|
||||
return getFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
|
||||
numEmptyCases, addr, T,
|
||||
isOutlined);
|
||||
}
|
||||
|
||||
// If we're not emitting an outlined copy, just call the value witness.
|
||||
if (!isOutlined) {
|
||||
return emitGetEnumTagSinglePayloadCall(IGF, T, numEmptyCases, addr);
|
||||
}
|
||||
|
||||
// Otherwise, fall back on a generic implementation.
|
||||
// TODO: consider inlining some of this so that we don't have to
|
||||
// bounce into the runtime when e.g. dynamically working with
|
||||
// double-optionals.
|
||||
return emitGetEnumTagSinglePayloadGenericCall(IGF, T, *TI, numEmptyCases,
|
||||
addr,
|
||||
[this, T](IRGenFunction &IGF, Address addr) -> llvm::Value* {
|
||||
auto payloadType = getPayloadType(IGF.IGM, T);
|
||||
auto payloadAddr = projectPayloadData(IGF, addr);
|
||||
|
||||
// For the case count, we just load the XI count from the metadata
|
||||
// for the payload type. We're almost certainly about to call a value
|
||||
// witness on that metadata anyway.
|
||||
auto payloadNumExtraCases =
|
||||
emitLoadOfExtraInhabitantCount(IGF, payloadType);
|
||||
|
||||
llvm::Value *tag
|
||||
= getPayloadTypeInfo().getEnumTagSinglePayload(IGF,
|
||||
payloadNumExtraCases,
|
||||
payloadAddr,
|
||||
payloadType,
|
||||
/*outlined*/ false);
|
||||
|
||||
// We need to adjust that for the number of cases we're using
|
||||
// in this enum.
|
||||
return adjustPayloadExtraInhabitantTag(IGF, tag);
|
||||
});
|
||||
}
|
||||
|
||||
/// Given an extra inhabitant tag for the payload type, adjust it to
|
||||
/// be an appropriate extra inhabitant tag for the enum type.
|
||||
llvm::Value *adjustPayloadExtraInhabitantTag(IRGenFunction &IGF,
|
||||
llvm::Value *tag) const {
|
||||
auto numExtraCases = IGF.IGM.getInt32(ElementsWithNoPayload.size());
|
||||
|
||||
// Adjust the tag.
|
||||
llvm::Value *adjustedTag = IGF.Builder.CreateSub(tag, numExtraCases);
|
||||
|
||||
// If tag <= numExtraCases, then this is a valid value of the enum type,
|
||||
// and the proper tag to return is 0.
|
||||
auto isEnumValue = IGF.Builder.CreateICmpULE(tag, numExtraCases);
|
||||
adjustedTag = IGF.Builder.CreateSelect(isEnumValue,
|
||||
IGF.IGM.getInt32(0),
|
||||
adjustedTag);
|
||||
return adjustedTag;
|
||||
}
|
||||
|
||||
void storeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *tag,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address dest, SILType T,
|
||||
bool isOutlined) const override {
|
||||
if (TIK >= Fixed) {
|
||||
storeFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
|
||||
tag, numEmptyCases, dest, T,
|
||||
isOutlined);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're not emitting an outlined copy, just call the value witness.
|
||||
if (!isOutlined) {
|
||||
emitStoreEnumTagSinglePayloadCall(IGF, T, tag, numEmptyCases, dest);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, fall back on a generic implementation.
|
||||
// TODO: consider inlining some of this so that we don't have to
|
||||
// bounce into the runtime when e.g. dynamically working with
|
||||
// double-optionals.
|
||||
emitStoreEnumTagSinglePayloadGenericCall(IGF, T, *TI, tag,
|
||||
numEmptyCases, dest,
|
||||
[this, T](IRGenFunction &IGF, Address dest, llvm::Value *tag) {
|
||||
auto payloadType = getPayloadType(IGF.IGM, T);
|
||||
auto payloadDest = projectPayloadData(IGF, dest);
|
||||
auto payloadTag = adjustExtraInhabitantTagForPayload(IGF, tag,
|
||||
/*nonzero*/false);
|
||||
|
||||
// We know that tag <= numXI, and as long as that's true, storing an
|
||||
// extra inhabitant is always a no-op.
|
||||
auto payloadNumXI = payloadTag;
|
||||
|
||||
getPayloadTypeInfo().storeEnumTagSinglePayload(IGF, payloadTag,
|
||||
payloadNumXI,
|
||||
payloadDest,
|
||||
payloadType,
|
||||
/*outlined*/ false);
|
||||
});
|
||||
}
|
||||
|
||||
/// Given an extra inhabitant tag for the payload type, which is known
|
||||
/// not to be 0, adjust it to be an appropriate extra inhabitant tag
|
||||
/// for the enum type.
|
||||
llvm::Value *adjustExtraInhabitantTagForPayload(IRGenFunction &IGF,
|
||||
llvm::Value *tag,
|
||||
bool isKnownNonZero) const {
|
||||
auto numExtraCases = IGF.IGM.getInt32(ElementsWithNoPayload.size());
|
||||
|
||||
// Adjust the tag.
|
||||
llvm::Value *adjustedTag = IGF.Builder.CreateAdd(tag, numExtraCases);
|
||||
|
||||
// Preserve the zero tag so that we don't pass down a meaningless XI
|
||||
// value that the payload will waste time installing before we
|
||||
// immediately overwrite it.
|
||||
if (!isKnownNonZero) {
|
||||
// If tag <= numExtraCases, then this is a valid value of the enum type,
|
||||
// and the proper tag to return is 0.
|
||||
auto isEnumValue = IGF.Builder.CreateIsNull(tag);
|
||||
adjustedTag = IGF.Builder.CreateSelect(isEnumValue,
|
||||
IGF.IGM.getInt32(0),
|
||||
adjustedTag);
|
||||
}
|
||||
return adjustedTag;
|
||||
}
|
||||
|
||||
APInt
|
||||
getFixedExtraInhabitantMask(IRGenModule &IGM) const override {
|
||||
auto &payloadTI = getFixedPayloadTypeInfo();
|
||||
@@ -4874,11 +5091,15 @@ namespace {
|
||||
Address src,
|
||||
SILType T,
|
||||
bool isOutlined) const override {
|
||||
// For dynamic layouts, the runtime provides a value witness to do this.
|
||||
if (TIK < Fixed) {
|
||||
return emitGetExtraInhabitantIndexCall(IGF, T, src);
|
||||
}
|
||||
|
||||
assert(TIK >= Fixed);
|
||||
return getExtraInhabitantIndexImpl(IGF, src, T, isOutlined,
|
||||
getFixedExtraInhabitantCount(IGF.IGM));
|
||||
}
|
||||
|
||||
llvm::Value *getExtraInhabitantIndexImpl(IRGenFunction &IGF,
|
||||
Address src, SILType T,
|
||||
bool isOutlined,
|
||||
unsigned xiCount) const {
|
||||
llvm::Value *tag;
|
||||
if (CommonSpareBits.count()) {
|
||||
auto payload = EnumPayload::load(IGF, projectPayload(IGF, src),
|
||||
@@ -4932,8 +5153,7 @@ namespace {
|
||||
llvm::ConstantInt::get(IGM.Int32Ty, maxTag),
|
||||
tag);
|
||||
auto isExtraInhabitant = IGF.Builder.CreateICmpULT(index,
|
||||
llvm::ConstantInt::get(IGM.Int32Ty,
|
||||
getFixedExtraInhabitantCount(IGM)));
|
||||
llvm::ConstantInt::get(IGF.IGM.Int32Ty, xiCount));
|
||||
return IGF.Builder.CreateSelect(isExtraInhabitant,
|
||||
index, llvm::ConstantInt::get(IGM.Int32Ty, -1));
|
||||
}
|
||||
@@ -4943,11 +5163,7 @@ namespace {
|
||||
Address dest,
|
||||
SILType T,
|
||||
bool isOutlined) const override {
|
||||
// For dynamic layouts, the runtime provides a value witness to do this.
|
||||
if (TIK < Fixed) {
|
||||
emitStoreExtraInhabitantCall(IGF, T, index, dest);
|
||||
return;
|
||||
}
|
||||
assert(TIK >= Fixed);
|
||||
|
||||
auto indexValue = IGF.Builder.CreateNot(index);
|
||||
|
||||
@@ -4995,6 +5211,36 @@ namespace {
|
||||
IGF.Builder.CreateStore(indexValue, tagAddr);
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address src, SILType T,
|
||||
bool isOutlined) const override {
|
||||
if (TIK < Fixed) {
|
||||
// For dynamic layouts, the runtime provides a value witness to do this.
|
||||
return emitGetEnumTagSinglePayloadCall(IGF, T, numEmptyCases, src);
|
||||
}
|
||||
|
||||
return getFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
|
||||
numEmptyCases, src, T,
|
||||
isOutlined);
|
||||
}
|
||||
|
||||
void storeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address src, SILType T,
|
||||
bool isOutlined) const override {
|
||||
if (TIK < Fixed) {
|
||||
// For dynamic layouts, the runtime provides a value witness to do this.
|
||||
emitStoreEnumTagSinglePayloadCall(IGF, T, index, numEmptyCases, src);
|
||||
return;
|
||||
}
|
||||
|
||||
storeFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
|
||||
index, numEmptyCases, src, T,
|
||||
isOutlined);
|
||||
}
|
||||
|
||||
APInt
|
||||
getFixedExtraInhabitantMask(IRGenModule &IGM) const override {
|
||||
@@ -5014,9 +5260,12 @@ namespace {
|
||||
unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override {
|
||||
unsigned totalTagBits = CommonSpareBits.count() + getExtraTagBitCountForExtraInhabitants();
|
||||
if (totalTagBits >= 32)
|
||||
return INT_MAX;
|
||||
return ValueWitnessFlags::MaxNumExtraInhabitants;
|
||||
unsigned totalTags = 1u << totalTagBits;
|
||||
return totalTags - ElementsWithPayload.size() - NumEmptyElementTags;
|
||||
unsigned rawCount =
|
||||
totalTags - ElementsWithPayload.size() - NumEmptyElementTags;
|
||||
return std::min(rawCount,
|
||||
unsigned(ValueWitnessFlags::MaxNumExtraInhabitants));
|
||||
}
|
||||
|
||||
APInt
|
||||
@@ -5433,7 +5682,7 @@ namespace {
|
||||
Address src,
|
||||
SILType T,
|
||||
bool isOutlined) const override {
|
||||
return emitGetExtraInhabitantIndexCall(IGF, T, src);
|
||||
llvm_unreachable("resilient enums are never fixed-layout types");
|
||||
}
|
||||
|
||||
void storeExtraInhabitant(IRGenFunction &IGF,
|
||||
@@ -5441,7 +5690,22 @@ namespace {
|
||||
Address dest,
|
||||
SILType T,
|
||||
bool isOutlined) const override {
|
||||
emitStoreExtraInhabitantCall(IGF, T, index, dest);
|
||||
llvm_unreachable("resilient enums are never fixed-layout types");
|
||||
}
|
||||
|
||||
llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address src, SILType T,
|
||||
bool isOutlined) const override {
|
||||
return emitGetEnumTagSinglePayloadCall(IGF, T, numEmptyCases, src);
|
||||
}
|
||||
|
||||
void storeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address src, SILType T,
|
||||
bool isOutlined) const override {
|
||||
emitStoreEnumTagSinglePayloadCall(IGF, T, index, numEmptyCases, src);
|
||||
}
|
||||
|
||||
APInt
|
||||
@@ -5663,18 +5927,22 @@ namespace {
|
||||
bool mayHaveExtraInhabitants(IRGenModule &IGM) const override {
|
||||
return Strategy.mayHaveExtraInhabitants(IGM);
|
||||
}
|
||||
llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
|
||||
Address src,
|
||||
llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr,
|
||||
SILType T,
|
||||
bool isOutlined) const override {
|
||||
return Strategy.getExtraInhabitantIndex(IGF, src, T, isOutlined);
|
||||
return Strategy.getEnumTagSinglePayload(IGF, numEmptyCases, enumAddr, T,
|
||||
isOutlined);
|
||||
}
|
||||
void storeExtraInhabitant(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
Address dest,
|
||||
SILType T,
|
||||
bool isOutlined) const override {
|
||||
return Strategy.storeExtraInhabitant(IGF, index, dest, T, isOutlined);
|
||||
void storeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *whichCase,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr,
|
||||
SILType T,
|
||||
bool isOutlined) const override {
|
||||
return Strategy.storeEnumTagSinglePayload(IGF, whichCase, numEmptyCases,
|
||||
enumAddr, T, isOutlined);
|
||||
}
|
||||
bool isSingleRetainablePointer(ResilienceExpansion expansion,
|
||||
ReferenceCounting *rc) const override {
|
||||
@@ -5682,15 +5950,13 @@ namespace {
|
||||
}
|
||||
};
|
||||
|
||||
/// TypeInfo for fixed-layout, address-only enum types.
|
||||
class FixedEnumTypeInfo : public EnumTypeInfoBase<FixedTypeInfo> {
|
||||
template <class Base>
|
||||
class FixedEnumTypeInfoBase : public EnumTypeInfoBase<Base> {
|
||||
protected:
|
||||
using EnumTypeInfoBase<Base>::EnumTypeInfoBase;
|
||||
|
||||
public:
|
||||
FixedEnumTypeInfo(EnumImplStrategy &strategy,
|
||||
llvm::StructType *T, Size S, SpareBitVector SB,
|
||||
Alignment A, IsPOD_t isPOD, IsBitwiseTakable_t isBT,
|
||||
IsFixedSize_t alwaysFixedSize)
|
||||
: EnumTypeInfoBase(strategy, T, S, std::move(SB), A, isPOD, isBT,
|
||||
alwaysFixedSize) {}
|
||||
using EnumTypeInfoBase<Base>::Strategy;
|
||||
|
||||
/// \group Methods delegated to the EnumImplStrategy
|
||||
|
||||
@@ -5708,18 +5974,43 @@ namespace {
|
||||
APInt getFixedExtraInhabitantMask(IRGenModule &IGM) const override {
|
||||
return Strategy.getFixedExtraInhabitantMask(IGM);
|
||||
}
|
||||
|
||||
llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
|
||||
Address src,
|
||||
SILType T,
|
||||
bool isOutlined) const override {
|
||||
return Strategy.getExtraInhabitantIndex(IGF, src, T, isOutlined);
|
||||
}
|
||||
void storeExtraInhabitant(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
Address dest,
|
||||
SILType T,
|
||||
bool isOutlined) const override {
|
||||
return Strategy.storeExtraInhabitant(IGF, index, dest, T, isOutlined);
|
||||
}
|
||||
};
|
||||
|
||||
/// TypeInfo for fixed-layout but address-only enum types.
|
||||
class FixedEnumTypeInfo : public FixedEnumTypeInfoBase<FixedTypeInfo> {
|
||||
public:
|
||||
FixedEnumTypeInfo(EnumImplStrategy &strategy,
|
||||
llvm::StructType *T, Size S, SpareBitVector SB,
|
||||
Alignment A, IsPOD_t isPOD, IsBitwiseTakable_t isBT,
|
||||
IsFixedSize_t alwaysFixedSize)
|
||||
: FixedEnumTypeInfoBase(strategy, T, S, std::move(SB), A, isPOD, isBT,
|
||||
alwaysFixedSize) {}
|
||||
};
|
||||
|
||||
/// TypeInfo for loadable enum types.
|
||||
class LoadableEnumTypeInfo : public EnumTypeInfoBase<LoadableTypeInfo> {
|
||||
class LoadableEnumTypeInfo : public FixedEnumTypeInfoBase<LoadableTypeInfo> {
|
||||
public:
|
||||
// FIXME: Derive spare bits from element layout.
|
||||
LoadableEnumTypeInfo(EnumImplStrategy &strategy,
|
||||
llvm::StructType *T, Size S, SpareBitVector SB,
|
||||
Alignment A, IsPOD_t isPOD,
|
||||
IsFixedSize_t alwaysFixedSize)
|
||||
: EnumTypeInfoBase(strategy, T, S, std::move(SB), A, isPOD,
|
||||
alwaysFixedSize) {}
|
||||
: FixedEnumTypeInfoBase(strategy, T, S, std::move(SB), A, isPOD,
|
||||
alwaysFixedSize) {}
|
||||
|
||||
void addToAggLowering(IRGenModule &IGM, SwiftAggLowering &lowering,
|
||||
Size offset) const override {
|
||||
@@ -5772,20 +6063,6 @@ namespace {
|
||||
unsigned offset) const override {
|
||||
return Strategy.unpackFromEnumPayload(IGF, payload, dest, offset);
|
||||
}
|
||||
unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override {
|
||||
return Strategy.getFixedExtraInhabitantCount(IGM);
|
||||
}
|
||||
|
||||
APInt getFixedExtraInhabitantValue(IRGenModule &IGM,
|
||||
unsigned bits,
|
||||
unsigned index)
|
||||
const override {
|
||||
return Strategy.getFixedExtraInhabitantValue(IGM, bits, index);
|
||||
}
|
||||
|
||||
APInt getFixedExtraInhabitantMask(IRGenModule &IGM) const override {
|
||||
return Strategy.getFixedExtraInhabitantMask(IGM);
|
||||
}
|
||||
LoadedRef loadRefcountedPtr(IRGenFunction &IGF,
|
||||
SourceLoc loc, Address addr) const override {
|
||||
return LoadedRef(Strategy.loadRefcountedPtr(IGF, loc, addr), false);
|
||||
|
||||
@@ -373,15 +373,28 @@ public:
|
||||
|
||||
virtual bool mayHaveExtraInhabitants(IRGenModule &IGM) const = 0;
|
||||
|
||||
// Only ever called for fixed types.
|
||||
virtual llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
|
||||
Address src,
|
||||
SILType T,
|
||||
bool isOutlined) const = 0;
|
||||
// Only ever called for fixed types.
|
||||
virtual void storeExtraInhabitant(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
Address dest,
|
||||
SILType T,
|
||||
bool isOutlined) const = 0;
|
||||
virtual llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr,
|
||||
SILType T,
|
||||
bool isOutlined) const = 0;
|
||||
virtual void storeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *whichCase,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr,
|
||||
SILType T,
|
||||
bool isOutlined) const = 0;
|
||||
|
||||
/// \group Delegated FixedTypeInfo operations
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "swift/IRGen/ValueWitness.h"
|
||||
|
||||
#include "Callee.h"
|
||||
#include "Explosion.h"
|
||||
#include "FixedTypeInfo.h"
|
||||
#include "IRGenFunction.h"
|
||||
#include "IRGenModule.h"
|
||||
@@ -85,28 +86,6 @@ static llvm::Type *createWitnessType(IRGenModule &IGM, ValueWitness index) {
|
||||
return llvm::FunctionType::get(ptrTy, args, /*isVarArg*/ false);
|
||||
}
|
||||
|
||||
/// void (*storeExtraInhabitant)(T *obj, unsigned index, M *self);
|
||||
case ValueWitness::StoreExtraInhabitant: {
|
||||
llvm::Type *ptrTy = IGM.OpaquePtrTy;
|
||||
llvm::Type *indexTy = IGM.Int32Ty;
|
||||
llvm::Type *metaTy = IGM.TypeMetadataPtrTy;
|
||||
llvm::Type *voidTy = IGM.VoidTy;
|
||||
llvm::Type *args[] = {ptrTy, indexTy, metaTy};
|
||||
|
||||
return llvm::FunctionType::get(voidTy, args, /*isVarArg*/ false);
|
||||
}
|
||||
|
||||
/// int (*getExtraInhabitantIndex)(T *obj, M *self);
|
||||
case ValueWitness::GetExtraInhabitantIndex: {
|
||||
llvm::Type *ptrTy = IGM.OpaquePtrTy;
|
||||
llvm::Type *metaTy = IGM.TypeMetadataPtrTy;
|
||||
llvm::Type *indexTy = IGM.Int32Ty;
|
||||
|
||||
llvm::Type *args[] = {ptrTy, metaTy};
|
||||
|
||||
return llvm::FunctionType::get(indexTy, args, /*isVarArg*/ false);
|
||||
}
|
||||
|
||||
/// unsigned (*getEnumTag)(T *obj, M *self);
|
||||
case ValueWitness::GetEnumTag: {
|
||||
llvm::Type *ptrTy = IGM.OpaquePtrTy;
|
||||
@@ -166,11 +145,11 @@ static llvm::Type *createWitnessType(IRGenModule &IGM, ValueWitness index) {
|
||||
}
|
||||
|
||||
case ValueWitness::Size:
|
||||
case ValueWitness::Flags:
|
||||
case ValueWitness::Stride:
|
||||
case ValueWitness::ExtraInhabitantFlags:
|
||||
// Non-function witnesses all have type size_t.
|
||||
return IGM.SizeTy;
|
||||
case ValueWitness::Flags:
|
||||
case ValueWitness::ExtraInhabitantCount:
|
||||
return IGM.Int32Ty;
|
||||
}
|
||||
|
||||
llvm_unreachable("bad value witness!");
|
||||
@@ -196,8 +175,6 @@ static llvm::AttributeList getValueWitnessAttrs(IRGenModule &IGM,
|
||||
case ValueWitness::DestructiveInjectEnumTag:
|
||||
case ValueWitness::DestructiveProjectEnumData:
|
||||
case ValueWitness::GetEnumTag:
|
||||
case ValueWitness::GetExtraInhabitantIndex:
|
||||
case ValueWitness::StoreExtraInhabitant:
|
||||
case ValueWitness::StoreEnumTagSinglePayload:
|
||||
return attrs.addAttribute(ctx, 1, llvm::Attribute::NoAlias);
|
||||
|
||||
@@ -217,8 +194,8 @@ static llvm::AttributeList getValueWitnessAttrs(IRGenModule &IGM,
|
||||
|
||||
case ValueWitness::Size:
|
||||
case ValueWitness::Flags:
|
||||
case ValueWitness::ExtraInhabitantCount:
|
||||
case ValueWitness::Stride:
|
||||
case ValueWitness::ExtraInhabitantFlags:
|
||||
llvm_unreachable("not a function value witness");
|
||||
}
|
||||
llvm_unreachable("bad witness");
|
||||
@@ -260,14 +237,10 @@ static StringRef getValueWitnessLabel(ValueWitness index) {
|
||||
return "size";
|
||||
case ValueWitness::Flags:
|
||||
return "flags";
|
||||
case ValueWitness::ExtraInhabitantCount:
|
||||
return "extraInhabitantCount";
|
||||
case ValueWitness::Stride:
|
||||
return "stride";
|
||||
case ValueWitness::StoreExtraInhabitant:
|
||||
return "storeExtraInhabitant";
|
||||
case ValueWitness::GetExtraInhabitantIndex:
|
||||
return "getExtraInhabitantIndex";
|
||||
case ValueWitness::ExtraInhabitantFlags:
|
||||
return "extraInhabitantFlags";
|
||||
case ValueWitness::GetEnumTag:
|
||||
return "getEnumTag";
|
||||
case ValueWitness::DestructiveProjectEnumData:
|
||||
@@ -282,6 +255,58 @@ static StringRef getValueWitnessLabel(ValueWitness index) {
|
||||
llvm_unreachable("bad value witness index");
|
||||
}
|
||||
|
||||
static llvm::PointerType *
|
||||
getOrCreateValueWitnessTablePtrTy(IRGenModule &IGM, llvm::PointerType *&cache,
|
||||
StringRef name, bool includeEnumWitnesses) {
|
||||
if (cache) return cache;
|
||||
|
||||
SmallVector<llvm::Type*, 16> types;
|
||||
|
||||
#define FUNC(lowerId, upperId, retTy, paramTys) \
|
||||
types.push_back(IGM.Int8PtrTy);
|
||||
#define DATA(lowerId, upperId, ty) \
|
||||
types.push_back(IGM.getValueWitnessTy(ValueWitness::upperId));
|
||||
|
||||
// Add the base value witnesses.
|
||||
#define WANT_ONLY_REQUIRED_VALUE_WITNESSES
|
||||
#define FUNCTION_VALUE_WITNESS FUNC
|
||||
#define DATA_VALUE_WITNESS DATA
|
||||
#include "swift/ABI/ValueWitness.def"
|
||||
|
||||
// Add the enum value witnesses.
|
||||
if (includeEnumWitnesses) {
|
||||
#define WANT_ONLY_ENUM_VALUE_WITNESSES
|
||||
#define FUNCTION_VALUE_WITNESS FUNC
|
||||
#define DATA_VALUE_WITNESS DATA
|
||||
#include "swift/ABI/ValueWitness.def"
|
||||
}
|
||||
|
||||
#undef DATA
|
||||
#undef FUNC
|
||||
|
||||
auto structTy = llvm::StructType::create(types, name);
|
||||
auto ptrTy = structTy->getPointerTo();
|
||||
cache = ptrTy;
|
||||
return ptrTy;
|
||||
}
|
||||
|
||||
llvm::StructType *IRGenModule::getValueWitnessTableTy() {
|
||||
return cast<llvm::StructType>(getValueWitnessTablePtrTy()->getElementType());
|
||||
}
|
||||
llvm::PointerType *IRGenModule::getValueWitnessTablePtrTy() {
|
||||
return getOrCreateValueWitnessTablePtrTy(*this, ValueWitnessTablePtrTy,
|
||||
"swift.vwtable", false);
|
||||
}
|
||||
|
||||
llvm::StructType *IRGenModule::getEnumValueWitnessTableTy() {
|
||||
return cast<llvm::StructType>(getEnumValueWitnessTablePtrTy()
|
||||
->getElementType());
|
||||
}
|
||||
llvm::PointerType *IRGenModule::getEnumValueWitnessTablePtrTy() {
|
||||
return getOrCreateValueWitnessTablePtrTy(*this, EnumValueWitnessTablePtrTy,
|
||||
"swift.enum_vwtable", true);
|
||||
}
|
||||
|
||||
/// Load a specific witness from a known table. The result is
|
||||
/// always an i8*.
|
||||
llvm::Value *irgen::emitInvariantLoadOfOpaqueWitness(IRGenFunction &IGF,
|
||||
@@ -321,12 +346,31 @@ llvm::Value *irgen::emitInvariantLoadOfOpaqueWitness(IRGenFunction &IGF,
|
||||
/// The result has the appropriate type for the witness.
|
||||
static llvm::Value *emitLoadOfValueWitnessValue(IRGenFunction &IGF,
|
||||
llvm::Value *table,
|
||||
ValueWitness index) {
|
||||
assert(!isValueWitnessFunction(index));
|
||||
llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, table, index);
|
||||
auto label = getValueWitnessLabel(index);
|
||||
auto type = IGF.IGM.getValueWitnessTy(index);
|
||||
return IGF.Builder.CreatePtrToInt(witness, type, label);
|
||||
ValueWitness witness) {
|
||||
assert(!isValueWitnessFunction(witness));
|
||||
assert(unsigned(witness) <= unsigned(ValueWitness::ExtraInhabitantCount) &&
|
||||
"extraInhabitantCount not the last non-function value witness");
|
||||
|
||||
auto pointerSize = IGF.IGM.getPointerSize();
|
||||
|
||||
// Most of the witnesses are at an offset that's just a multiple of the
|
||||
// pointer size, but the extra-inhabitant count is packed in after the
|
||||
// 32-bit flags.
|
||||
// This computation is correct for all pointer sizes, including 16.
|
||||
// It would be wrong if size_t is ever a different size from the pointer
|
||||
// size, though.
|
||||
Size offset =
|
||||
(witness == ValueWitness::ExtraInhabitantCount
|
||||
? unsigned(ValueWitness::Flags) * pointerSize + Size(4)
|
||||
: unsigned(witness) * pointerSize);
|
||||
|
||||
Address addr = Address(table, IGF.IGM.getPointerAlignment());
|
||||
addr = IGF.Builder.CreateBitCast(addr, IGF.IGM.getValueWitnessTablePtrTy());
|
||||
addr = IGF.Builder.CreateStructGEP(addr, unsigned(witness), offset);
|
||||
|
||||
auto load = IGF.Builder.CreateLoad(addr, getValueWitnessLabel(witness));
|
||||
IGF.setInvariantLoad(load);
|
||||
return load;
|
||||
}
|
||||
|
||||
/// Given a type metadata pointer, load one of the value witnesses from its
|
||||
@@ -345,7 +389,23 @@ static FunctionPointer emitLoadOfValueWitnessFunction(IRGenFunction &IGF,
|
||||
llvm::Value *table,
|
||||
ValueWitness index) {
|
||||
assert(isValueWitnessFunction(index));
|
||||
llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, table, index);
|
||||
|
||||
WitnessIndex windex = [&] {
|
||||
unsigned i = unsigned(index);
|
||||
if (i > unsigned(ValueWitness::Flags)) {
|
||||
if (IGF.IGM.getPointerSize() == Size(8)) {
|
||||
i--; // one pointer width skips both flags and xiCount
|
||||
} else if (IGF.IGM.getPointerSize() == Size(4)) {
|
||||
// no adjustment required
|
||||
} else {
|
||||
assert(IGF.IGM.getPointerSize() == Size(2));
|
||||
i += 2; // flags and xiCount take up two pointers apiece
|
||||
}
|
||||
}
|
||||
return WitnessIndex(i, false);
|
||||
}();
|
||||
|
||||
llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, table, windex);
|
||||
auto label = getValueWitnessLabel(index);
|
||||
auto signature = IGF.IGM.getValueWitnessSignature(index);
|
||||
|
||||
@@ -665,36 +725,6 @@ void irgen::emitDestroyArrayCall(IRGenFunction &IGF,
|
||||
IGF.Builder.CreateCall(IGF.IGM.getArrayDestroyFn(), {obj, count, metadata});
|
||||
}
|
||||
|
||||
/// Emit a call to the 'getExtraInhabitantIndex' operation.
|
||||
/// The type must be dynamically known to have extra inhabitant witnesses.
|
||||
llvm::Value *irgen::emitGetExtraInhabitantIndexCall(IRGenFunction &IGF,
|
||||
SILType T,
|
||||
Address srcObject) {
|
||||
llvm::Value *metadata;
|
||||
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
|
||||
ValueWitness::GetExtraInhabitantIndex);
|
||||
|
||||
auto src = emitCastToOpaquePtr(IGF, srcObject);
|
||||
llvm::CallInst *call =
|
||||
IGF.Builder.CreateCall(fn, {src, metadata});
|
||||
return call;
|
||||
}
|
||||
|
||||
/// Emit a call to the 'storeExtraInhabitant' operation.
|
||||
/// The type must be dynamically known to have extra inhabitant witnesses.
|
||||
llvm::Value *irgen::emitStoreExtraInhabitantCall(IRGenFunction &IGF,
|
||||
SILType T,
|
||||
llvm::Value *index,
|
||||
Address destObject) {
|
||||
llvm::Value *metadata;
|
||||
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
|
||||
ValueWitness::StoreExtraInhabitant);
|
||||
auto dest = emitCastToOpaquePtr(IGF, destObject);
|
||||
llvm::CallInst *call =
|
||||
IGF.Builder.CreateCall(fn, {dest, index, metadata});
|
||||
return call;
|
||||
}
|
||||
|
||||
/// Emit a trampoline to call the getEnumTagSinglePayload witness. API:
|
||||
/// UINT_TYPE (const T* enum, UINT_TYPE emptyCases, M *self)
|
||||
static llvm::Constant *
|
||||
@@ -774,7 +804,7 @@ llvm::Value *irgen::emitGetEnumTagSinglePayloadCall(IRGenFunction &IGF,
|
||||
return result;
|
||||
}
|
||||
|
||||
llvm::Value *irgen::emitStoreEnumTagSinglePayloadCall(
|
||||
void irgen::emitStoreEnumTagSinglePayloadCall(
|
||||
IRGenFunction &IGF, SILType T, llvm::Value *whichCase,
|
||||
llvm::Value *numEmptyCases, Address destObject) {
|
||||
if (!IGF.optimizeForSize()) {
|
||||
@@ -782,17 +812,14 @@ llvm::Value *irgen::emitStoreEnumTagSinglePayloadCall(
|
||||
auto fn = IGF.emitValueWitnessFunctionRef(
|
||||
T, metadata, ValueWitness::StoreEnumTagSinglePayload);
|
||||
auto dest = emitCastToOpaquePtr(IGF, destObject);
|
||||
llvm::CallInst *call = IGF.Builder.CreateCall(
|
||||
fn, {dest, whichCase, numEmptyCases, metadata});
|
||||
return call;
|
||||
IGF.Builder.CreateCall(fn, {dest, whichCase, numEmptyCases, metadata});
|
||||
return;
|
||||
}
|
||||
|
||||
auto *metadata = IGF.emitTypeMetadataRefForLayout(T);
|
||||
auto *func = getStoreEnumTagSinglePayloadTrampolineFn(IGF.IGM);
|
||||
auto dest = emitCastToOpaquePtr(IGF, destObject);
|
||||
auto *result = IGF.Builder.CreateCall(func,
|
||||
{dest, whichCase, numEmptyCases, metadata});
|
||||
return result;
|
||||
IGF.Builder.CreateCall(func, {dest, whichCase, numEmptyCases, metadata});
|
||||
}
|
||||
|
||||
/// Emit a call to the 'getEnumTag' operation.
|
||||
@@ -842,47 +869,36 @@ llvm::Value *irgen::emitLoadOfSize(IRGenFunction &IGF, SILType T) {
|
||||
/// Load the 'alignmentMask' value witness from the given table as a size_t.
|
||||
llvm::Value *irgen::emitLoadOfAlignmentMask(IRGenFunction &IGF, SILType T) {
|
||||
auto flags = IGF.emitValueWitnessValue(T, ValueWitness::Flags);
|
||||
auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::AlignmentMask));
|
||||
return IGF.Builder.CreateAnd(flags, mask,
|
||||
flags->getName() + ".alignmentMask");
|
||||
return emitAlignMaskFromFlags(IGF, flags);
|
||||
}
|
||||
|
||||
/// Load the 'isPOD' valueWitness from the given table as an i1.
|
||||
llvm::Value *irgen::emitLoadOfIsPOD(IRGenFunction &IGF, SILType T) {
|
||||
auto flags = IGF.emitValueWitnessValue(T, ValueWitness::Flags);
|
||||
auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::IsNonPOD));
|
||||
auto mask = IGF.IGM.getInt32(ValueWitnessFlags::IsNonPOD);
|
||||
auto masked = IGF.Builder.CreateAnd(flags, mask);
|
||||
return IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getSize(Size(0)),
|
||||
return IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getInt32(0),
|
||||
flags->getName() + ".isPOD");
|
||||
}
|
||||
|
||||
/// Load the 'isBitwiseTakable' valueWitness from the given table as an i1.
|
||||
llvm::Value *irgen::emitLoadOfIsBitwiseTakable(IRGenFunction &IGF, SILType T) {
|
||||
auto flags = IGF.emitValueWitnessValue(T, ValueWitness::Flags);
|
||||
auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::IsNonBitwiseTakable));
|
||||
auto mask = IGF.IGM.getInt32(ValueWitnessFlags::IsNonBitwiseTakable);
|
||||
auto masked = IGF.Builder.CreateAnd(flags, mask);
|
||||
return IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getSize(Size(0)),
|
||||
return IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getInt32(0),
|
||||
flags->getName() + ".isBitwiseTakable");
|
||||
}
|
||||
|
||||
/// Load the 'isInline' valueWitness from the given table as an i1.
|
||||
llvm::Value *irgen::emitLoadOfIsInline(IRGenFunction &IGF, SILType T) {
|
||||
auto flags = IGF.emitValueWitnessValue(T, ValueWitness::Flags);
|
||||
auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::IsNonInline));
|
||||
auto mask = IGF.IGM.getInt32(ValueWitnessFlags::IsNonInline);
|
||||
auto masked = IGF.Builder.CreateAnd(flags, mask);
|
||||
return IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getSize(Size(0)),
|
||||
return IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getInt32(0),
|
||||
flags->getName() + ".isInline");
|
||||
}
|
||||
|
||||
/// Load the 'hasExtraInhabitants' valueWitness from the given table as an i1.
|
||||
llvm::Value *irgen::emitLoadOfHasExtraInhabitants(IRGenFunction &IGF, SILType T) {
|
||||
auto flags = IGF.emitValueWitnessValue(T, ValueWitness::Flags);
|
||||
auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::HasExtraInhabitants));
|
||||
auto masked = IGF.Builder.CreateAnd(flags, mask);
|
||||
return IGF.Builder.CreateICmpNE(masked, IGF.IGM.getSize(Size(0)),
|
||||
flags->getName() + ".hasExtraInhabitants");
|
||||
}
|
||||
|
||||
/// Load the 'stride' value witness from the given table as a size_t.
|
||||
llvm::Value *irgen::emitLoadOfStride(IRGenFunction &IGF, SILType T) {
|
||||
return IGF.emitValueWitnessValue(T, ValueWitness::Stride);
|
||||
@@ -890,22 +906,17 @@ llvm::Value *irgen::emitLoadOfStride(IRGenFunction &IGF, SILType T) {
|
||||
|
||||
llvm::Value *irgen::emitLoadOfExtraInhabitantCount(IRGenFunction &IGF,
|
||||
SILType T) {
|
||||
auto xiFlags =
|
||||
IGF.emitValueWitnessValue(T, ValueWitness::ExtraInhabitantFlags);
|
||||
auto mask = IGF.IGM.getSize(
|
||||
Size(ExtraInhabitantFlags::NumExtraInhabitantsMask));
|
||||
return IGF.Builder.CreateAnd(xiFlags, mask,
|
||||
xiFlags->getName() + ".extraInhabitantCount");
|
||||
return IGF.emitValueWitnessValue(T, ValueWitness::ExtraInhabitantCount);
|
||||
}
|
||||
|
||||
std::pair<llvm::Value *, llvm::Value *>
|
||||
irgen::emitLoadOfIsInline(IRGenFunction &IGF, llvm::Value *metadata) {
|
||||
auto *flags = emitLoadOfValueWitnessValueFromMetadata(IGF, metadata,
|
||||
ValueWitness::Flags);
|
||||
auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::IsNonInline));
|
||||
auto mask = IGF.IGM.getInt32(ValueWitnessFlags::IsNonInline);
|
||||
auto masked = IGF.Builder.CreateAnd(flags, mask);
|
||||
return std::make_pair(
|
||||
IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getSize(Size(0)),
|
||||
IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getInt32(0),
|
||||
flags->getName() + ".isInline"),
|
||||
flags);
|
||||
}
|
||||
@@ -918,8 +929,9 @@ llvm::Value *irgen::emitLoadOfSize(IRGenFunction &IGF, llvm::Value *metadata) {
|
||||
|
||||
llvm::Value *irgen::emitAlignMaskFromFlags(IRGenFunction &IGF,
|
||||
llvm::Value *flags) {
|
||||
auto flagsAsSize = IGF.Builder.CreateZExtOrTrunc(flags, IGF.IGM.SizeTy);
|
||||
auto *alignMask = IGF.IGM.getSize(Size(ValueWitnessFlags::AlignmentMask));
|
||||
return IGF.Builder.CreateAnd(flags, alignMask,
|
||||
return IGF.Builder.CreateAnd(flagsAsSize, alignMask,
|
||||
flags->getName() + ".alignmentMask");
|
||||
}
|
||||
|
||||
@@ -1246,3 +1258,183 @@ void irgen::emitDeallocateValueInBuffer(IRGenFunction &IGF,
|
||||
call->setCallingConv(IGF.IGM.DefaultCC);
|
||||
call->setDoesNotThrow();
|
||||
}
|
||||
|
||||
llvm::Value *
|
||||
irgen::emitGetEnumTagSinglePayloadGenericCall(IRGenFunction &IGF,
|
||||
SILType payloadType,
|
||||
const TypeInfo &payloadTI,
|
||||
llvm::Value *numExtraCases,
|
||||
Address address,
|
||||
GetExtraInhabitantTagEmitter emitter) {
|
||||
auto getExtraInhabitantTagFn =
|
||||
getOrCreateGetExtraInhabitantTagFunction(IGF.IGM, payloadType,
|
||||
payloadTI, emitter);
|
||||
|
||||
// We assume this is never a reabstracted type.
|
||||
auto type = payloadType.getASTType();
|
||||
assert(type->isLegalFormalType());
|
||||
auto metadata = IGF.emitTypeMetadataRef(type);
|
||||
|
||||
auto ptr = IGF.Builder.CreateBitCast(address.getAddress(),
|
||||
IGF.IGM.OpaquePtrTy);
|
||||
|
||||
auto getEnumTagGenericFn =
|
||||
IGF.IGM.getGetEnumTagSinglePayloadGenericFn();
|
||||
auto call = IGF.Builder.CreateCall(getEnumTagGenericFn,
|
||||
{ptr,
|
||||
numExtraCases,
|
||||
metadata,
|
||||
getExtraInhabitantTagFn});
|
||||
return call;
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
irgen::getOrCreateGetExtraInhabitantTagFunction(IRGenModule &IGM,
|
||||
SILType objectType,
|
||||
const TypeInfo &objectTI,
|
||||
GetExtraInhabitantTagEmitter emitter) {
|
||||
// We assume this is never a reabstracted type.
|
||||
CanType type = objectType.getASTType();
|
||||
assert(type->isLegalFormalType());
|
||||
|
||||
auto fnTy = llvm::FunctionType::get(IGM.Int32Ty,
|
||||
{IGM.OpaquePtrTy,
|
||||
IGM.TypeMetadataPtrTy},
|
||||
false);
|
||||
|
||||
// TODO: use a meaningful mangled name and internal/shared linkage.
|
||||
auto fn = llvm::Function::Create(fnTy, llvm::Function::PrivateLinkage,
|
||||
"__swift_get_extra_inhabitant_index",
|
||||
&IGM.Module);
|
||||
IRGenFunction IGF(IGM, fn);
|
||||
auto parameters = IGF.collectParameters();
|
||||
auto ptr = parameters.claimNext();
|
||||
auto metadata = parameters.claimNext();
|
||||
|
||||
// Bind the metadata to make any archetypes available.
|
||||
IGF.bindLocalTypeDataFromTypeMetadata(type, IsExact, metadata,
|
||||
MetadataState::Complete);
|
||||
|
||||
// Form a well-typed address from the opaque pointer.
|
||||
ptr = IGF.Builder.CreateBitCast(ptr,
|
||||
objectTI.getStorageType()->getPointerTo());
|
||||
Address addr = objectTI.getAddressForPointer(ptr);
|
||||
|
||||
auto tag = emitter(IGF, addr);
|
||||
IGF.Builder.CreateRet(tag);
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
void
|
||||
irgen::emitStoreEnumTagSinglePayloadGenericCall(IRGenFunction &IGF,
|
||||
SILType payloadType,
|
||||
const TypeInfo &payloadTI,
|
||||
llvm::Value *whichCase,
|
||||
llvm::Value *numExtraCases,
|
||||
Address address,
|
||||
StoreExtraInhabitantTagEmitter emitter) {
|
||||
auto storeExtraInhabitantTagFn =
|
||||
getOrCreateStoreExtraInhabitantTagFunction(IGF.IGM, payloadType,
|
||||
payloadTI, emitter);
|
||||
|
||||
// We assume this is never a reabstracted type.
|
||||
auto type = payloadType.getASTType();
|
||||
assert(type->isLegalFormalType());
|
||||
auto metadata = IGF.emitTypeMetadataRef(type);
|
||||
|
||||
auto ptr = IGF.Builder.CreateBitCast(address.getAddress(),
|
||||
IGF.IGM.OpaquePtrTy);
|
||||
|
||||
auto storeEnumTagGenericFn =
|
||||
IGF.IGM.getStoreEnumTagSinglePayloadGenericFn();
|
||||
auto call = IGF.Builder.CreateCall(storeEnumTagGenericFn,
|
||||
{ptr,
|
||||
whichCase,
|
||||
numExtraCases,
|
||||
metadata,
|
||||
storeExtraInhabitantTagFn});
|
||||
(void) call;
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
irgen::getOrCreateStoreExtraInhabitantTagFunction(IRGenModule &IGM,
|
||||
SILType objectType,
|
||||
const TypeInfo &objectTI,
|
||||
StoreExtraInhabitantTagEmitter emitter) {
|
||||
// We assume this is never a reabstracted type.
|
||||
CanType type = objectType.getASTType();
|
||||
assert(type->isLegalFormalType());
|
||||
|
||||
auto fnTy = llvm::FunctionType::get(IGM.VoidTy,
|
||||
{IGM.OpaquePtrTy,
|
||||
IGM.Int32Ty,
|
||||
IGM.TypeMetadataPtrTy},
|
||||
false);
|
||||
|
||||
// TODO: use a meaningful mangled name and internal/shared linkage.
|
||||
auto fn = llvm::Function::Create(fnTy, llvm::Function::PrivateLinkage,
|
||||
"__swift_get_extra_inhabitant_index",
|
||||
&IGM.Module);
|
||||
IRGenFunction IGF(IGM, fn);
|
||||
auto parameters = IGF.collectParameters();
|
||||
auto ptr = parameters.claimNext();
|
||||
auto tag = parameters.claimNext();
|
||||
auto metadata = parameters.claimNext();
|
||||
|
||||
// Bind the metadata to make any archetypes available.
|
||||
IGF.bindLocalTypeDataFromTypeMetadata(type, IsExact, metadata,
|
||||
MetadataState::Complete);
|
||||
|
||||
// Form a well-typed address from the opaque pointer.
|
||||
ptr = IGF.Builder.CreateBitCast(ptr,
|
||||
objectTI.getStorageType()->getPointerTo());
|
||||
Address addr = objectTI.getAddressForPointer(ptr);
|
||||
|
||||
emitter(IGF, addr, tag);
|
||||
IGF.Builder.CreateRetVoid();
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
llvm::Value *TypeInfo::getExtraInhabitantTagDynamic(IRGenFunction &IGF,
|
||||
Address address,
|
||||
SILType T,
|
||||
llvm::Value *knownXICount,
|
||||
bool isOutlined) const {
|
||||
if (auto fixedTI = dyn_cast<FixedTypeInfo>(this)) {
|
||||
auto index = fixedTI->getExtraInhabitantIndex(IGF, address, T, isOutlined);
|
||||
// The runtime APIs expect that 0 means the payload case and 1+
|
||||
// means the extra cases, but in IRGen, getExtraInhabitantIndex
|
||||
// returns -1 for the payload case and 0+ for extra inhabitants.
|
||||
// This is an easy adjustment to make.
|
||||
auto one = llvm::ConstantInt::get(IGF.IGM.Int32Ty, 1);
|
||||
auto tag = IGF.Builder.CreateAdd(index, one);
|
||||
return tag;
|
||||
} else {
|
||||
if (!knownXICount)
|
||||
knownXICount = emitLoadOfExtraInhabitantCount(IGF, T);
|
||||
|
||||
auto tag = getEnumTagSinglePayload(IGF, /*num extra cases*/ knownXICount,
|
||||
address, T, isOutlined);
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
|
||||
void TypeInfo::storeExtraInhabitantTagDynamic(IRGenFunction &IGF,
|
||||
llvm::Value *tag,
|
||||
Address address,
|
||||
SILType T,
|
||||
bool isOutlined) const {
|
||||
if (auto fixedTI = dyn_cast<FixedTypeInfo>(this)) {
|
||||
// The runtime APIs expect that 0 means the payload case and 1+
|
||||
// means the extra cases, but in IRGen, storeExtraInhabitant
|
||||
// expects extra inhabitants to be indexed as 0+.
|
||||
// This is an easy adjustment to make.
|
||||
auto one = llvm::ConstantInt::get(IGF.IGM.Int32Ty, 1);
|
||||
auto index = IGF.Builder.CreateSub(tag, one);
|
||||
fixedTI->storeExtraInhabitant(IGF, index, address, T, isOutlined);
|
||||
} else {
|
||||
storeEnumTagSinglePayload(IGF, tag, tag, address, T, isOutlined);
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ namespace irgen {
|
||||
class Address;
|
||||
class IRGenFunction;
|
||||
class IRGenModule;
|
||||
class TypeInfo;
|
||||
enum class ValueWitness : unsigned;
|
||||
class WitnessIndex;
|
||||
|
||||
@@ -164,29 +165,16 @@ namespace irgen {
|
||||
Address object,
|
||||
llvm::Value *count);
|
||||
|
||||
/// Emit a call to the 'getExtraInhabitantIndex' operation.
|
||||
/// The type must be dynamically known to have extra inhabitant witnesses.
|
||||
llvm::Value *emitGetExtraInhabitantIndexCall(IRGenFunction &IGF,
|
||||
SILType T,
|
||||
Address srcObject);
|
||||
|
||||
/// Emit a call to the 'storeExtraInhabitant' operation.
|
||||
/// The type must be dynamically known to have extra inhabitant witnesses.
|
||||
llvm::Value *emitStoreExtraInhabitantCall(IRGenFunction &IGF,
|
||||
SILType T,
|
||||
llvm::Value *index,
|
||||
Address destObject);
|
||||
|
||||
/// Emit a call to the 'getEnumTagSinglePayload' operation.
|
||||
llvm::Value *emitGetEnumTagSinglePayloadCall(IRGenFunction &IGF, SILType T,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address destObject);
|
||||
|
||||
/// Emit a call to the 'storeEnumTagSinglePayload' operation.
|
||||
llvm::Value *emitStoreEnumTagSinglePayloadCall(IRGenFunction &IGF, SILType T,
|
||||
llvm::Value *whichCase,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address destObject);
|
||||
void emitStoreEnumTagSinglePayloadCall(IRGenFunction &IGF, SILType T,
|
||||
llvm::Value *whichCase,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address destObject);
|
||||
|
||||
/// Emit a call to the 'getEnumTag' operation.
|
||||
llvm::Value *emitGetEnumTagCall(IRGenFunction &IGF,
|
||||
@@ -224,11 +212,7 @@ namespace irgen {
|
||||
/// Emit a load of the 'isInline' value witness.
|
||||
llvm::Value *emitLoadOfIsInline(IRGenFunction &IGF, SILType T);
|
||||
|
||||
/// Emit a load of the 'hasExtraInhabitants' value witness.
|
||||
llvm::Value *emitLoadOfHasExtraInhabitants(IRGenFunction &IGF, SILType T);
|
||||
|
||||
/// Emit a load of the 'extraInhabitantCount' value witness.
|
||||
/// The type must be dynamically known to have extra inhabitant witnesses.
|
||||
llvm::Value *emitLoadOfExtraInhabitantCount(IRGenFunction &IGF, SILType T);
|
||||
|
||||
/// Returns the IsInline flag and the loaded flags value.
|
||||
@@ -251,6 +235,44 @@ namespace irgen {
|
||||
void emitDeallocateValueInBuffer(IRGenFunction &IGF,
|
||||
SILType type,
|
||||
Address buffer);
|
||||
|
||||
|
||||
using GetExtraInhabitantTagEmitter =
|
||||
llvm::function_ref<llvm::Value*(IRGenFunction &IGF,
|
||||
Address addr)>;
|
||||
|
||||
llvm::Constant *
|
||||
getOrCreateGetExtraInhabitantTagFunction(IRGenModule &IGM,
|
||||
SILType objectType,
|
||||
const TypeInfo &objectTI,
|
||||
GetExtraInhabitantTagEmitter emit);
|
||||
|
||||
llvm::Value *
|
||||
emitGetEnumTagSinglePayloadGenericCall(IRGenFunction &IGF,
|
||||
SILType payloadType,
|
||||
const TypeInfo &payloadTI,
|
||||
llvm::Value *numExtraCases,
|
||||
Address address,
|
||||
GetExtraInhabitantTagEmitter emit);
|
||||
|
||||
using StoreExtraInhabitantTagEmitter =
|
||||
llvm::function_ref<void(IRGenFunction &IGF,
|
||||
Address addr,
|
||||
llvm::Value *tag)>;
|
||||
|
||||
llvm::Constant *
|
||||
getOrCreateStoreExtraInhabitantTagFunction(IRGenModule &IGM,
|
||||
SILType objectType,
|
||||
const TypeInfo &objectTI,
|
||||
StoreExtraInhabitantTagEmitter emit);
|
||||
|
||||
void emitStoreEnumTagSinglePayloadGenericCall(IRGenFunction &IGF,
|
||||
SILType payloadType,
|
||||
const TypeInfo &payloadTI,
|
||||
llvm::Value *index,
|
||||
llvm::Value *numExtraCases,
|
||||
Address address,
|
||||
StoreExtraInhabitantTagEmitter emit);
|
||||
} // end namespace irgen
|
||||
} // end namespace swift
|
||||
|
||||
|
||||
@@ -303,21 +303,16 @@ public:
|
||||
llvm::Value *withExtraInhabitantProvidingField(IRGenFunction &IGF,
|
||||
Address structAddr,
|
||||
SILType structType,
|
||||
bool isOutlined,
|
||||
llvm::Type *resultTy,
|
||||
llvm::function_ref<llvm::Value* (const FieldImpl &field)> body,
|
||||
llvm::function_ref<llvm::Value* ()> outline) const {
|
||||
llvm::function_ref<llvm::Value* (const FieldImpl &field,
|
||||
llvm::Value *numXI)> body) const {
|
||||
// If we know one field consistently provides extra inhabitants, delegate
|
||||
// to that field.
|
||||
if (auto field = asImpl().getFixedExtraInhabitantProvidingField(IGF.IGM)){
|
||||
return body(*field);
|
||||
return body(*field, nullptr);
|
||||
}
|
||||
|
||||
// Otherwise, we have to figure out which field at runtime.
|
||||
// The decision tree could be rather large, so invoke the value witness
|
||||
// unless we're emitting the value witness.
|
||||
if (!isOutlined)
|
||||
return outline();
|
||||
|
||||
// The number of extra inhabitants the instantiated type has can be used
|
||||
// to figure out which field the runtime chose. The runtime uses the same
|
||||
@@ -376,7 +371,7 @@ public:
|
||||
if (&field != fixedCandidate)
|
||||
continue;
|
||||
|
||||
fieldCount = llvm::ConstantInt::get(IGF.IGM.SizeTy, fixedCount);
|
||||
fieldCount = IGF.IGM.getInt32(fixedCount);
|
||||
} else {
|
||||
auto fieldTy = field.getType(IGF.IGM, structType);
|
||||
// If this field has the same type as a field we already tested,
|
||||
@@ -395,7 +390,7 @@ public:
|
||||
IGF.Builder.CreateCondBr(equalsCount, yesBB, noBB);
|
||||
|
||||
IGF.Builder.emitBlock(yesBB);
|
||||
auto value = body(field);
|
||||
auto value = body(field, instantiatedCount);
|
||||
if (contPhi)
|
||||
contPhi->addIncoming(value, IGF.Builder.GetInsertBlock());
|
||||
IGF.Builder.CreateBr(contBB);
|
||||
@@ -414,46 +409,6 @@ public:
|
||||
return contPhi;
|
||||
}
|
||||
|
||||
llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
|
||||
Address structAddr,
|
||||
SILType structType,
|
||||
bool isOutlined) const override {
|
||||
return withExtraInhabitantProvidingField(IGF, structAddr, structType,
|
||||
isOutlined,
|
||||
IGF.IGM.Int32Ty,
|
||||
[&](const FieldImpl &field) -> llvm::Value* {
|
||||
Address fieldAddr = asImpl().projectFieldAddress(
|
||||
IGF, structAddr, structType, field);
|
||||
return field.getTypeInfo().getExtraInhabitantIndex(IGF, fieldAddr,
|
||||
field.getType(IGF.IGM, structType),
|
||||
false /*not outlined for field*/);
|
||||
},
|
||||
[&]() -> llvm::Value * {
|
||||
return emitGetExtraInhabitantIndexCall(IGF, structType, structAddr);
|
||||
});
|
||||
}
|
||||
|
||||
void storeExtraInhabitant(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
Address structAddr,
|
||||
SILType structType,
|
||||
bool isOutlined) const override {
|
||||
withExtraInhabitantProvidingField(IGF, structAddr, structType, isOutlined,
|
||||
IGF.IGM.VoidTy,
|
||||
[&](const FieldImpl &field) -> llvm::Value* {
|
||||
Address fieldAddr = asImpl().projectFieldAddress(
|
||||
IGF, structAddr, structType, field);
|
||||
field.getTypeInfo().storeExtraInhabitant(IGF, index, fieldAddr,
|
||||
field.getType(IGF.IGM, structType),
|
||||
false /*not outlined for field*/);
|
||||
return nullptr;
|
||||
},
|
||||
[&]() -> llvm::Value * {
|
||||
emitStoreExtraInhabitantCall(IGF, structType, index, structAddr);
|
||||
return nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
const FieldImpl *
|
||||
getFixedExtraInhabitantProvidingField(IRGenModule &IGM) const {
|
||||
if (!ExtraInhabitantProvidingField.hasValue()) {
|
||||
@@ -658,6 +613,33 @@ public:
|
||||
fieldMask = fieldMask.shl(field->getFixedByteOffset().getValueInBits());
|
||||
return fieldMask;
|
||||
}
|
||||
|
||||
llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
|
||||
Address structAddr,
|
||||
SILType structType,
|
||||
bool isOutlined) const override {
|
||||
auto field = *asImpl().getFixedExtraInhabitantProvidingField(IGF.IGM);
|
||||
Address fieldAddr =
|
||||
asImpl().projectFieldAddress(IGF, structAddr, structType, field);
|
||||
auto &fieldTI = cast<FixedTypeInfo>(field.getTypeInfo());
|
||||
return fieldTI.getExtraInhabitantIndex(IGF, fieldAddr,
|
||||
field.getType(IGF.IGM, structType),
|
||||
false /*not outlined for field*/);
|
||||
}
|
||||
|
||||
void storeExtraInhabitant(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
Address structAddr,
|
||||
SILType structType,
|
||||
bool isOutlined) const override {
|
||||
auto field = *asImpl().getFixedExtraInhabitantProvidingField(IGF.IGM);
|
||||
Address fieldAddr =
|
||||
asImpl().projectFieldAddress(IGF, structAddr, structType, field);
|
||||
auto &fieldTI = cast<FixedTypeInfo>(field.getTypeInfo());
|
||||
fieldTI.storeExtraInhabitant(IGF, index, fieldAddr,
|
||||
field.getType(IGF.IGM, structType),
|
||||
false /*not outlined for field*/);
|
||||
}
|
||||
};
|
||||
|
||||
/// An implementation of RecordTypeInfo for loadable types.
|
||||
|
||||
@@ -472,6 +472,66 @@ namespace {
|
||||
return StructNonFixedOffsets(T).getFieldAccessStrategy(IGM,
|
||||
field.getNonFixedElementIndex());
|
||||
}
|
||||
|
||||
llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address structAddr,
|
||||
SILType structType,
|
||||
bool isOutlined) const override {
|
||||
// If we're not emitting the value witness table's implementation,
|
||||
// just call that.
|
||||
if (!isOutlined) {
|
||||
return emitGetEnumTagSinglePayloadCall(IGF, structType, numEmptyCases,
|
||||
structAddr);
|
||||
}
|
||||
|
||||
return emitGetEnumTagSinglePayloadGenericCall(IGF, structType, *this,
|
||||
numEmptyCases, structAddr,
|
||||
[this,structType](IRGenFunction &IGF, Address structAddr) {
|
||||
return withExtraInhabitantProvidingField(IGF, structAddr, structType,
|
||||
IGF.IGM.Int32Ty,
|
||||
[&](const FieldImpl &field, llvm::Value *numXI) -> llvm::Value* {
|
||||
Address fieldAddr = asImpl().projectFieldAddress(
|
||||
IGF, structAddr, structType, field);
|
||||
auto fieldTy = field.getType(IGF.IGM, structType);
|
||||
return field.getTypeInfo()
|
||||
.getExtraInhabitantTagDynamic(IGF, fieldAddr, fieldTy,
|
||||
numXI, /*outlined*/ false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void storeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *whichCase,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address structAddr,
|
||||
SILType structType,
|
||||
bool isOutlined) const override {
|
||||
// If we're not emitting the value witness table's implementation,
|
||||
// just call that.
|
||||
if (!isOutlined) {
|
||||
return emitStoreEnumTagSinglePayloadCall(IGF, structType, whichCase,
|
||||
numEmptyCases, structAddr);
|
||||
}
|
||||
|
||||
emitStoreEnumTagSinglePayloadGenericCall(IGF, structType, *this,
|
||||
whichCase, numEmptyCases,
|
||||
structAddr,
|
||||
[this,structType](IRGenFunction &IGF, Address structAddr,
|
||||
llvm::Value *tag) {
|
||||
withExtraInhabitantProvidingField(IGF, structAddr, structType,
|
||||
IGF.IGM.VoidTy,
|
||||
[&](const FieldImpl &field, llvm::Value *numXI) -> llvm::Value* {
|
||||
Address fieldAddr = asImpl().projectFieldAddress(
|
||||
IGF, structAddr, structType, field);
|
||||
auto fieldTy = field.getType(IGF.IGM, structType);
|
||||
field.getTypeInfo()
|
||||
.storeExtraInhabitantTagDynamic(IGF, tag, fieldAddr, fieldTy,
|
||||
/*outlined*/ false);
|
||||
return nullptr;
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
class StructTypeBuilder :
|
||||
|
||||
@@ -295,6 +295,29 @@ namespace {
|
||||
SILType T) const {
|
||||
return TupleNonFixedOffsets(T);
|
||||
}
|
||||
|
||||
llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address structAddr,
|
||||
SILType structType,
|
||||
bool isOutlined) const override {
|
||||
// The runtime will overwrite this with a concrete implementation
|
||||
// in the value witness table.
|
||||
return emitGetEnumTagSinglePayloadCall(IGF, structType, numEmptyCases,
|
||||
structAddr);
|
||||
}
|
||||
|
||||
void storeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address structAddr,
|
||||
SILType structType,
|
||||
bool isOutlined) const override {
|
||||
// The runtime will overwrite this with a concrete implementation
|
||||
// in the value witness table.
|
||||
emitStoreEnumTagSinglePayloadCall(IGF, structType, index,
|
||||
numEmptyCases, structAddr);
|
||||
}
|
||||
};
|
||||
|
||||
class TupleTypeBuilder :
|
||||
|
||||
@@ -240,15 +240,16 @@ llvm::Value *FixedTypeInfo::isDynamicallyPackedInline(IRGenFunction &IGF,
|
||||
unsigned FixedTypeInfo::getSpareBitExtraInhabitantCount() const {
|
||||
if (SpareBits.none())
|
||||
return 0;
|
||||
// The runtime supports a max of 0x7FFFFFFF extra inhabitants, which ought
|
||||
// to be enough for anybody.
|
||||
// Make sure the arithmetic below doesn't overflow.
|
||||
if (getFixedSize().getValue() >= 4)
|
||||
return 0x7FFFFFFF;
|
||||
return ValueWitnessFlags::MaxNumExtraInhabitants;
|
||||
unsigned spareBitCount = SpareBits.count();
|
||||
assert(spareBitCount <= getFixedSize().getValueInBits()
|
||||
&& "more spare bits than storage bits?!");
|
||||
unsigned inhabitedBitCount = getFixedSize().getValueInBits() - spareBitCount;
|
||||
return ((1U << spareBitCount) - 1U) << inhabitedBitCount;
|
||||
unsigned rawCount = ((1U << spareBitCount) - 1U) << inhabitedBitCount;
|
||||
return std::min(rawCount,
|
||||
unsigned(ValueWitnessFlags::MaxNumExtraInhabitants));
|
||||
}
|
||||
|
||||
void FixedTypeInfo::applyFixedSpareBitsMask(SpareBitVector &mask,
|
||||
@@ -426,15 +427,26 @@ static llvm::Value *computeExtraTagBytes(IRGenFunction &IGF, IRBuilder &Builder,
|
||||
llvm::Value *FixedTypeInfo::getEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr,
|
||||
SILType T) const {
|
||||
SILType T,
|
||||
bool isOutlined) const {
|
||||
return getFixedTypeEnumTagSinglePayload(IGF, *this, numEmptyCases, enumAddr,
|
||||
T, isOutlined);
|
||||
}
|
||||
|
||||
llvm::Value *irgen::getFixedTypeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
const FixedTypeInfo &ti,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr,
|
||||
SILType T,
|
||||
bool isOutlined) {
|
||||
auto &IGM = IGF.IGM;
|
||||
auto &Ctx = IGF.IGM.getLLVMContext();
|
||||
auto &Builder = IGF.Builder;
|
||||
|
||||
auto *size = getSize(IGF, T);
|
||||
Size fixedSize = getFixedSize();
|
||||
auto *size = ti.getSize(IGF, T);
|
||||
Size fixedSize = ti.getFixedSize();
|
||||
auto *numExtraInhabitants =
|
||||
llvm::ConstantInt::get(IGM.Int32Ty, getFixedExtraInhabitantCount(IGM));
|
||||
llvm::ConstantInt::get(IGM.Int32Ty, ti.getFixedExtraInhabitantCount(IGM));
|
||||
|
||||
auto *zero = llvm::ConstantInt::get(IGM.Int32Ty, 0U);
|
||||
auto *one = llvm::ConstantInt::get(IGM.Int32Ty, 1U);
|
||||
@@ -513,8 +525,8 @@ llvm::Value *FixedTypeInfo::getEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
Builder.emitBlock(noExtraTagBitsBB);
|
||||
// If there are extra inhabitants, see whether the payload is valid.
|
||||
llvm::Value *result0;
|
||||
if (mayHaveExtraInhabitants(IGM)) {
|
||||
result0 = getExtraInhabitantIndex(IGF, enumAddr, T, false);
|
||||
if (ti.mayHaveExtraInhabitants(IGM)) {
|
||||
result0 = ti.getExtraInhabitantIndex(IGF, enumAddr, T, false);
|
||||
noExtraTagBitsBB = Builder.GetInsertBlock();
|
||||
} else {
|
||||
result0 = llvm::ConstantInt::getSigned(IGM.Int32Ty, -1);
|
||||
@@ -605,7 +617,19 @@ void FixedTypeInfo::storeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *whichCase,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr,
|
||||
SILType T) const {
|
||||
SILType T,
|
||||
bool isOutlined) const {
|
||||
storeFixedTypeEnumTagSinglePayload(IGF, *this, whichCase, numEmptyCases,
|
||||
enumAddr, T, isOutlined);
|
||||
}
|
||||
|
||||
void irgen::storeFixedTypeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
const FixedTypeInfo &ti,
|
||||
llvm::Value *whichCase,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr,
|
||||
SILType T,
|
||||
bool isOutlined) {
|
||||
auto &IGM = IGF.IGM;
|
||||
auto &Ctx = IGF.IGM.getLLVMContext();
|
||||
auto &Builder = IGF.Builder;
|
||||
@@ -616,15 +640,15 @@ void FixedTypeInfo::storeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
auto *four = llvm::ConstantInt::get(int32Ty, 4U);
|
||||
auto *eight = llvm::ConstantInt::get(int32Ty, 8U);
|
||||
|
||||
auto fixedSize = getFixedSize();
|
||||
auto fixedSize = ti.getFixedSize();
|
||||
|
||||
Address valueAddr = Builder.CreateElementBitCast(enumAddr, IGM.Int8Ty);
|
||||
Address extraTagBitsAddr =
|
||||
Builder.CreateConstByteArrayGEP(valueAddr, fixedSize);
|
||||
|
||||
auto *numExtraInhabitants =
|
||||
llvm::ConstantInt::get(IGM.Int32Ty, getFixedExtraInhabitantCount(IGM));
|
||||
auto *size = getSize(IGF, T);
|
||||
llvm::ConstantInt::get(IGM.Int32Ty, ti.getFixedExtraInhabitantCount(IGM));
|
||||
auto *size = ti.getSize(IGF, T);
|
||||
|
||||
// Do we need extra tag bytes.
|
||||
auto *entryBB = Builder.GetInsertBlock();
|
||||
@@ -666,11 +690,11 @@ void FixedTypeInfo::storeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
Builder.CreateCondBr(isPayload, returnBB, storeInhabitantBB);
|
||||
|
||||
Builder.emitBlock(storeInhabitantBB);
|
||||
if (mayHaveExtraInhabitants(IGM)) {
|
||||
if (ti.mayHaveExtraInhabitants(IGM)) {
|
||||
// Store an index in the range [0..ElementsWithNoPayload-1].
|
||||
auto *nonPayloadElementIndex = Builder.CreateSub(whichCase, one);
|
||||
storeExtraInhabitant(IGF, nonPayloadElementIndex, enumAddr, T,
|
||||
/*outlined*/ false);
|
||||
ti.storeExtraInhabitant(IGF, nonPayloadElementIndex, enumAddr, T,
|
||||
/*outlined*/ false);
|
||||
}
|
||||
Builder.CreateBr(returnBB);
|
||||
|
||||
@@ -728,30 +752,6 @@ void FixedTypeInfo::storeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
Builder.emitBlock(returnBB);
|
||||
}
|
||||
|
||||
llvm::Value *irgen::emitGetEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr, SILType T) {
|
||||
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
|
||||
auto opaqueAddr =
|
||||
IGF.Builder.CreateBitCast(enumAddr.getAddress(), IGF.IGM.OpaquePtrTy);
|
||||
|
||||
return IGF.Builder.CreateCall(IGF.IGM.getGetEnumCaseSinglePayloadFn(),
|
||||
{opaqueAddr, metadata, numEmptyCases});
|
||||
}
|
||||
|
||||
void irgen::emitStoreEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *whichCase,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr,
|
||||
SILType T) {
|
||||
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
|
||||
auto opaqueAddr =
|
||||
IGF.Builder.CreateBitCast(enumAddr.getAddress(), IGF.IGM.OpaquePtrTy);
|
||||
|
||||
IGF.Builder.CreateCall(IGF.IGM.getStoreEnumTagSinglePayloadFn(),
|
||||
{opaqueAddr, metadata, whichCase, numEmptyCases});
|
||||
}
|
||||
|
||||
void
|
||||
FixedTypeInfo::storeSpareBitExtraInhabitant(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
|
||||
@@ -56,15 +56,13 @@ const char *irgen::getValueWitnessName(ValueWitness witness) {
|
||||
CASE(InitializeBufferWithCopyOfBuffer)
|
||||
CASE(InitializeWithCopy)
|
||||
CASE(InitializeWithTake)
|
||||
CASE(StoreExtraInhabitant)
|
||||
CASE(GetExtraInhabitantIndex)
|
||||
CASE(GetEnumTag)
|
||||
CASE(DestructiveProjectEnumData)
|
||||
CASE(DestructiveInjectEnumTag)
|
||||
CASE(Size)
|
||||
CASE(Flags)
|
||||
CASE(ExtraInhabitantCount)
|
||||
CASE(Stride)
|
||||
CASE(ExtraInhabitantFlags)
|
||||
CASE(GetEnumTagSinglePayload)
|
||||
CASE(StoreEnumTagSinglePayload)
|
||||
#undef CASE
|
||||
@@ -510,27 +508,6 @@ static void buildValueWitnessFunction(IRGenModule &IGM,
|
||||
return;
|
||||
}
|
||||
|
||||
case ValueWitness::StoreExtraInhabitant: {
|
||||
Address dest = getArgAs(IGF, argv, type, "dest");
|
||||
llvm::Value *index = getArg(argv, "index");
|
||||
getArgAsLocalSelfTypeMetadata(IGF, argv, abstractType);
|
||||
|
||||
type.storeExtraInhabitant(IGF, index, dest, concreteType,
|
||||
/*outlined*/ true);
|
||||
IGF.Builder.CreateRetVoid();
|
||||
return;
|
||||
}
|
||||
|
||||
case ValueWitness::GetExtraInhabitantIndex: {
|
||||
Address src = getArgAs(IGF, argv, type, "src");
|
||||
getArgAsLocalSelfTypeMetadata(IGF, argv, abstractType);
|
||||
|
||||
llvm::Value *idx = type.getExtraInhabitantIndex(IGF, src, concreteType,
|
||||
/*outlined*/ true);
|
||||
IGF.Builder.CreateRet(idx);
|
||||
return;
|
||||
}
|
||||
|
||||
case ValueWitness::GetEnumTag: {
|
||||
auto &strategy = getEnumImplStrategy(IGM, concreteType);
|
||||
|
||||
@@ -593,7 +570,7 @@ static void buildValueWitnessFunction(IRGenModule &IGM,
|
||||
|
||||
llvm::Value *idx = type.getEnumTagSinglePayload(
|
||||
IGF, numEmptyCases, Address(value, type.getBestKnownAlignment()),
|
||||
concreteType);
|
||||
concreteType, true);
|
||||
IGF.Builder.CreateRet(idx);
|
||||
return;
|
||||
}
|
||||
@@ -610,15 +587,15 @@ static void buildValueWitnessFunction(IRGenModule &IGM,
|
||||
|
||||
type.storeEnumTagSinglePayload(IGF, whichCase, numEmptyCases,
|
||||
Address(value, type.getBestKnownAlignment()),
|
||||
concreteType);
|
||||
concreteType, true);
|
||||
IGF.Builder.CreateRetVoid();
|
||||
return;
|
||||
}
|
||||
|
||||
case ValueWitness::Size:
|
||||
case ValueWitness::Flags:
|
||||
case ValueWitness::ExtraInhabitantCount:
|
||||
case ValueWitness::Stride:
|
||||
case ValueWitness::ExtraInhabitantFlags:
|
||||
llvm_unreachable("these value witnesses aren't functions");
|
||||
}
|
||||
llvm_unreachable("bad value witness kind!");
|
||||
@@ -753,7 +730,7 @@ static llvm::Constant *getMemCpyFunction(IRGenModule &IGM,
|
||||
/// Find a witness to the fact that a type is a value type.
|
||||
/// Always adds an i8*.
|
||||
static void addValueWitness(IRGenModule &IGM,
|
||||
ConstantArrayBuilder &B,
|
||||
ConstantStructBuilder &B,
|
||||
ValueWitness index,
|
||||
FixedPacking packing,
|
||||
CanType abstractType,
|
||||
@@ -815,10 +792,10 @@ static void addValueWitness(IRGenModule &IGM,
|
||||
|
||||
case ValueWitness::Size: {
|
||||
if (auto value = concreteTI.getStaticSize(IGM))
|
||||
return B.add(llvm::ConstantExpr::getIntToPtr(value, IGM.Int8PtrTy));
|
||||
return B.add(value);
|
||||
|
||||
// Just fill in null here if the type can't be statically laid out.
|
||||
return B.add(llvm::ConstantPointerNull::get(IGM.Int8PtrTy));
|
||||
// Just fill in 0 here if the type can't be statically laid out.
|
||||
return B.addSize(Size(0));
|
||||
}
|
||||
|
||||
case ValueWitness::Flags: {
|
||||
@@ -836,8 +813,6 @@ static void addValueWitness(IRGenModule &IGM,
|
||||
flags = flags.withAlignment(fixedTI->getFixedAlignment().getValue())
|
||||
.withPOD(fixedTI->isPOD(ResilienceExpansion::Maximal))
|
||||
.withInlineStorage(isInline)
|
||||
.withExtraInhabitants(
|
||||
fixedTI->getFixedExtraInhabitantCount(IGM) > 0)
|
||||
.withBitwiseTakable(isBitwiseTakable);
|
||||
} else {
|
||||
flags = flags.withIncomplete(true);
|
||||
@@ -846,50 +821,23 @@ static void addValueWitness(IRGenModule &IGM,
|
||||
if (concreteType.getEnumOrBoundGenericEnum())
|
||||
flags = flags.withEnumWitnesses(true);
|
||||
|
||||
auto value = IGM.getSize(Size(flags.getOpaqueValue()));
|
||||
return B.add(llvm::ConstantExpr::getIntToPtr(value, IGM.Int8PtrTy));
|
||||
return B.addInt32(flags.getOpaqueValue());
|
||||
}
|
||||
|
||||
case ValueWitness::ExtraInhabitantCount: {
|
||||
unsigned value = 0;
|
||||
if (auto *fixedTI = dyn_cast<FixedTypeInfo>(&concreteTI)) {
|
||||
value = fixedTI->getFixedExtraInhabitantCount(IGM);
|
||||
}
|
||||
return B.addInt32(value);
|
||||
}
|
||||
|
||||
case ValueWitness::Stride: {
|
||||
if (auto value = concreteTI.getStaticStride(IGM))
|
||||
return B.add(llvm::ConstantExpr::getIntToPtr(value, IGM.Int8PtrTy));
|
||||
return B.add(value);
|
||||
|
||||
// Just fill in null here if the type can't be statically laid out.
|
||||
return B.add(llvm::ConstantPointerNull::get(IGM.Int8PtrTy));
|
||||
}
|
||||
|
||||
case ValueWitness::StoreExtraInhabitant:
|
||||
case ValueWitness::GetExtraInhabitantIndex: {
|
||||
if (!concreteTI.mayHaveExtraInhabitants(IGM)) {
|
||||
assert(concreteType.getEnumOrBoundGenericEnum());
|
||||
return B.addNullPointer(IGM.Int8PtrTy);
|
||||
}
|
||||
|
||||
goto standard;
|
||||
}
|
||||
|
||||
case ValueWitness::ExtraInhabitantFlags: {
|
||||
if (!concreteTI.mayHaveExtraInhabitants(IGM)) {
|
||||
assert(concreteType.getEnumOrBoundGenericEnum());
|
||||
return B.add(llvm::ConstantPointerNull::get(IGM.Int8PtrTy));
|
||||
}
|
||||
|
||||
// If we locally know that the type has fixed layout, we can emit
|
||||
// meaningful flags for it.
|
||||
if (auto *fixedTI = dyn_cast<FixedTypeInfo>(&concreteTI)) {
|
||||
ExtraInhabitantFlags flags;
|
||||
|
||||
uint64_t numExtraInhabitants = fixedTI->getFixedExtraInhabitantCount(IGM);
|
||||
assert(numExtraInhabitants <= ExtraInhabitantFlags::NumExtraInhabitantsMask);
|
||||
flags = flags.withNumExtraInhabitants(numExtraInhabitants);
|
||||
|
||||
auto value = IGM.getSize(Size(flags.getOpaqueValue()));
|
||||
return B.add(llvm::ConstantExpr::getIntToPtr(value, IGM.Int8PtrTy));
|
||||
}
|
||||
|
||||
// Otherwise, just fill in null here if the type can't be statically
|
||||
// queried for extra inhabitants.
|
||||
return B.add(llvm::ConstantPointerNull::get(IGM.Int8PtrTy));
|
||||
return B.addSize(Size(0));
|
||||
}
|
||||
|
||||
case ValueWitness::GetEnumTagSinglePayload:
|
||||
@@ -914,9 +862,21 @@ static void addValueWitness(IRGenModule &IGM,
|
||||
addFunction(fn);
|
||||
}
|
||||
|
||||
static bool shouldAddEnumWitnesses(CanType abstractType) {
|
||||
// Needs to handle UnboundGenericType.
|
||||
return dyn_cast_or_null<EnumDecl>(abstractType.getAnyNominal()) != nullptr;
|
||||
}
|
||||
|
||||
static llvm::StructType *getValueWitnessTableType(IRGenModule &IGM,
|
||||
CanType abstractType) {
|
||||
return shouldAddEnumWitnesses(abstractType)
|
||||
? IGM.getEnumValueWitnessTableTy()
|
||||
: IGM.getValueWitnessTableTy();
|
||||
}
|
||||
|
||||
/// Collect the value witnesses for a particular type.
|
||||
static void addValueWitnesses(IRGenModule &IGM,
|
||||
ConstantArrayBuilder &B,
|
||||
ConstantStructBuilder &B,
|
||||
FixedPacking packing,
|
||||
CanType abstractType,
|
||||
SILType concreteType,
|
||||
@@ -925,16 +885,7 @@ static void addValueWitnesses(IRGenModule &IGM,
|
||||
addValueWitness(IGM, B, ValueWitness(i), packing,
|
||||
abstractType, concreteType, concreteTI);
|
||||
}
|
||||
if (concreteType.getEnumOrBoundGenericEnum() ||
|
||||
concreteTI.mayHaveExtraInhabitants(IGM)) {
|
||||
for (auto i = unsigned(ValueWitness::First_ExtraInhabitantValueWitness);
|
||||
i <= unsigned(ValueWitness::Last_ExtraInhabitantValueWitness);
|
||||
++i) {
|
||||
addValueWitness(IGM, B, ValueWitness(i), packing,
|
||||
abstractType, concreteType, concreteTI);
|
||||
}
|
||||
}
|
||||
if (concreteType.getEnumOrBoundGenericEnum()) {
|
||||
if (shouldAddEnumWitnesses(abstractType)) {
|
||||
for (auto i = unsigned(ValueWitness::First_EnumValueWitness);
|
||||
i <= unsigned(ValueWitness::Last_EnumValueWitness);
|
||||
++i) {
|
||||
@@ -952,7 +903,7 @@ bool irgen::hasDependentValueWitnessTable(IRGenModule &IGM, CanType ty) {
|
||||
}
|
||||
|
||||
static void addValueWitnessesForAbstractType(IRGenModule &IGM,
|
||||
ConstantArrayBuilder &B,
|
||||
ConstantStructBuilder &B,
|
||||
CanType abstractType,
|
||||
bool &canBeConstant) {
|
||||
CanType concreteFormalType = getFormalTypeInContext(abstractType);
|
||||
@@ -1095,7 +1046,8 @@ llvm::Constant *irgen::emitValueWitnessTable(IRGenModule &IGM,
|
||||
"emitting VWT pattern for fixed-layout type");
|
||||
|
||||
ConstantInitBuilder builder(IGM);
|
||||
auto witnesses = builder.beginArray(IGM.Int8PtrTy);
|
||||
auto witnesses =
|
||||
builder.beginStruct(getValueWitnessTableType(IGM, abstractType));
|
||||
|
||||
bool canBeConstant = false;
|
||||
addValueWitnessesForAbstractType(IGM, witnesses, abstractType, canBeConstant);
|
||||
@@ -1159,7 +1111,7 @@ llvm::Constant *IRGenModule::emitFixedTypeLayout(CanType t,
|
||||
|
||||
// Emit the layout values.
|
||||
ConstantInitBuilder builder(*this);
|
||||
auto witnesses = builder.beginArray(Int8PtrTy);
|
||||
auto witnesses = builder.beginStruct();
|
||||
FixedPacking packing = ti.getFixedPacking(*this);
|
||||
for (auto witness = ValueWitness::First_TypeLayoutWitness;
|
||||
witness <= ValueWitness::Last_RequiredTypeLayoutWitness;
|
||||
@@ -1167,12 +1119,6 @@ llvm::Constant *IRGenModule::emitFixedTypeLayout(CanType t,
|
||||
addValueWitness(*this, witnesses, witness, packing, t, silTy, ti);
|
||||
}
|
||||
|
||||
if (ti.mayHaveExtraInhabitants(*this))
|
||||
for (auto witness = ValueWitness::First_ExtraInhabitantValueWitness;
|
||||
witness <= ValueWitness::Last_TypeLayoutWitness;
|
||||
witness = ValueWitness(unsigned(witness) + 1))
|
||||
addValueWitness(*this, witnesses, witness, packing, t, silTy, ti);
|
||||
|
||||
auto layoutVar
|
||||
= witnesses.finishAndCreateGlobal(
|
||||
"type_layout_" + llvm::Twine(size)
|
||||
@@ -1184,10 +1130,8 @@ llvm::Constant *IRGenModule::emitFixedTypeLayout(CanType t,
|
||||
/*constant*/ true,
|
||||
llvm::GlobalValue::PrivateLinkage);
|
||||
|
||||
auto zero = llvm::ConstantInt::get(Int32Ty, 0);
|
||||
llvm::Constant *indices[] = {zero, zero};
|
||||
auto layout = llvm::ConstantExpr::getGetElementPtr(layoutVar->getValueType(),
|
||||
layoutVar, indices);
|
||||
// Cast to the standard currency type for type layouts.
|
||||
auto layout = llvm::ConstantExpr::getBitCast(layoutVar, Int8PtrPtrTy);
|
||||
|
||||
PrivateFixedLayouts.insert({key, layout});
|
||||
return layout;
|
||||
|
||||
@@ -49,16 +49,14 @@ std::string IRGenMangler::mangleValueWitness(Type type, ValueWitness witness) {
|
||||
GET_MANGLING(AssignWithTake) \
|
||||
GET_MANGLING(GetEnumTagSinglePayload) \
|
||||
GET_MANGLING(StoreEnumTagSinglePayload) \
|
||||
GET_MANGLING(StoreExtraInhabitant) \
|
||||
GET_MANGLING(GetExtraInhabitantIndex) \
|
||||
GET_MANGLING(GetEnumTag) \
|
||||
GET_MANGLING(DestructiveProjectEnumData) \
|
||||
GET_MANGLING(DestructiveInjectEnumTag)
|
||||
#undef GET_MANGLING
|
||||
case ValueWitness::Size:
|
||||
case ValueWitness::Flags:
|
||||
case ValueWitness::ExtraInhabitantCount:
|
||||
case ValueWitness::Stride:
|
||||
case ValueWitness::ExtraInhabitantFlags:
|
||||
llvm_unreachable("not a function witness");
|
||||
}
|
||||
appendOperator("w", Code);
|
||||
|
||||
@@ -860,6 +860,10 @@ llvm::AttributeList IRGenModule::constructInitialAttributes() {
|
||||
llvm::AttributeList::FunctionIndex, b);
|
||||
}
|
||||
|
||||
llvm::Constant *IRGenModule::getInt32(uint32_t value) {
|
||||
return llvm::ConstantInt::get(Int32Ty, value);
|
||||
}
|
||||
|
||||
llvm::Constant *IRGenModule::getSize(Size size) {
|
||||
return llvm::ConstantInt::get(SizeTy, size.getValue());
|
||||
}
|
||||
|
||||
@@ -625,7 +625,7 @@ public:
|
||||
/// Get the bit width of an integer type for the target platform.
|
||||
unsigned getBuiltinIntegerWidth(BuiltinIntegerType *t);
|
||||
unsigned getBuiltinIntegerWidth(BuiltinIntegerWidth w);
|
||||
|
||||
|
||||
Size getPointerSize() const { return PtrSize; }
|
||||
Alignment getPointerAlignment() const {
|
||||
// We always use the pointer's width as its swift ABI alignment.
|
||||
@@ -699,6 +699,11 @@ public:
|
||||
|
||||
llvm::StructType *getIntegerLiteralTy();
|
||||
|
||||
llvm::StructType *getValueWitnessTableTy();
|
||||
llvm::StructType *getEnumValueWitnessTableTy();
|
||||
llvm::PointerType *getValueWitnessTablePtrTy();
|
||||
llvm::PointerType *getEnumValueWitnessTablePtrTy();
|
||||
|
||||
void unimplemented(SourceLoc, StringRef Message);
|
||||
LLVM_ATTRIBUTE_NORETURN
|
||||
void fatal_unimplemented(SourceLoc, StringRef Message);
|
||||
@@ -729,7 +734,9 @@ private:
|
||||
llvm::FunctionType *AssociatedTypeWitnessTableAccessFunctionTy = nullptr;
|
||||
llvm::StructType *GenericWitnessTableCacheTy = nullptr;
|
||||
llvm::StructType *IntegerLiteralTy = nullptr;
|
||||
|
||||
llvm::PointerType *ValueWitnessTablePtrTy = nullptr;
|
||||
llvm::PointerType *EnumValueWitnessTablePtrTy = nullptr;
|
||||
|
||||
llvm::DenseMap<llvm::Type *, SpareBitVector> SpareBitsForTypes;
|
||||
|
||||
//--- Types -----------------------------------------------------------------
|
||||
@@ -1185,6 +1192,7 @@ public:
|
||||
ForeignFunctionInfo *foreignInfo=nullptr);
|
||||
ForeignFunctionInfo getForeignFunctionInfo(CanSILFunctionType type);
|
||||
|
||||
llvm::Constant *getInt32(uint32_t value);
|
||||
llvm::Constant *getSize(Size size);
|
||||
llvm::Constant *getAlignment(Alignment align);
|
||||
llvm::Constant *getBool(bool condition);
|
||||
|
||||
@@ -799,7 +799,7 @@ llvm::Type *LinkEntity::getDefaultDeclarationType(IRGenModule &IGM) const {
|
||||
case Kind::ReflectionFieldDescriptor:
|
||||
case Kind::ReflectionAssociatedTypeDescriptor:
|
||||
return IGM.FieldDescriptorTy;
|
||||
case Kind::ValueWitnessTable:
|
||||
case Kind::ValueWitnessTable: // TODO: use ValueWitnessTableTy
|
||||
case Kind::ProtocolWitnessTable:
|
||||
case Kind::ProtocolWitnessTablePattern:
|
||||
return IGM.WitnessTableTy;
|
||||
|
||||
@@ -30,16 +30,6 @@
|
||||
namespace swift {
|
||||
namespace irgen {
|
||||
|
||||
/// Emits the generic implementation for getEnumTagSinglePayload.
|
||||
llvm::Value *emitGetEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr, SILType T);
|
||||
|
||||
/// Emits the generic implementation for storeEnumTagSinglePayload.
|
||||
void emitStoreEnumTagSinglePayload(IRGenFunction &IGF, llvm::Value *whichCase,
|
||||
llvm::Value *numEmptyCases, Address enumAddr,
|
||||
SILType T);
|
||||
|
||||
/// An abstract CRTP class designed for types whose storage size,
|
||||
/// alignment, and stride need to be fetched from the value witness
|
||||
/// table for the type.
|
||||
@@ -119,19 +109,7 @@ public:
|
||||
return emitLoadOfIsInline(IGF, T);
|
||||
}
|
||||
|
||||
/// FIXME: Dynamic extra inhabitant lookup.
|
||||
bool mayHaveExtraInhabitants(IRGenModule &) const override { return false; }
|
||||
llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
|
||||
Address src, SILType T,
|
||||
bool isOutlined) const override {
|
||||
llvm_unreachable("dynamic extra inhabitants not supported");
|
||||
}
|
||||
void storeExtraInhabitant(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
Address dest, SILType T,
|
||||
bool isOutlined) const override {
|
||||
llvm_unreachable("dynamic extra inhabitants not supported");
|
||||
}
|
||||
bool mayHaveExtraInhabitants(IRGenModule &) const override { return true; }
|
||||
|
||||
llvm::Constant *getStaticSize(IRGenModule &IGM) const override {
|
||||
return nullptr;
|
||||
@@ -142,19 +120,6 @@ public:
|
||||
llvm::Constant *getStaticStride(IRGenModule &IGM) const override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr,
|
||||
SILType T) const override {
|
||||
return emitGetEnumTagSinglePayload(IGF, numEmptyCases, enumAddr, T);
|
||||
}
|
||||
|
||||
void storeEnumTagSinglePayload(IRGenFunction &IGF, llvm::Value *whichCase,
|
||||
llvm::Value *numEmptyCases, Address enumAddr,
|
||||
SILType T) const override {
|
||||
emitStoreEnumTagSinglePayload(IGF, whichCase, numEmptyCases, enumAddr, T);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,30 +137,18 @@ public:
|
||||
bool mayHaveExtraInhabitants(IRGenModule &IGM) const override {
|
||||
return true;
|
||||
}
|
||||
llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
|
||||
Address src,
|
||||
SILType T,
|
||||
bool isOutlined) const override {
|
||||
return emitGetExtraInhabitantIndexCall(IGF, T, src);
|
||||
}
|
||||
void storeExtraInhabitant(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
Address dest,
|
||||
SILType T,
|
||||
bool isOutlined) const override {
|
||||
emitStoreExtraInhabitantCall(IGF, T, index, dest);
|
||||
}
|
||||
|
||||
llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr,
|
||||
SILType T) const override {
|
||||
SILType T,
|
||||
bool isOutlined) const override {
|
||||
return emitGetEnumTagSinglePayloadCall(IGF, T, numEmptyCases, enumAddr);
|
||||
}
|
||||
|
||||
void storeEnumTagSinglePayload(IRGenFunction &IGF, llvm::Value *whichCase,
|
||||
llvm::Value *numEmptyCases, Address enumAddr,
|
||||
SILType T) const override {
|
||||
SILType T, bool isOutlined) const override {
|
||||
emitStoreEnumTagSinglePayloadCall(IGF, T, whichCase, numEmptyCases, enumAddr);
|
||||
}
|
||||
|
||||
|
||||
@@ -402,42 +402,48 @@ public:
|
||||
/// Does this type statically have extra inhabitants, or may it dynamically
|
||||
/// have extra inhabitants based on type arguments?
|
||||
virtual bool mayHaveExtraInhabitants(IRGenModule &IGM) const = 0;
|
||||
|
||||
/// Map an extra inhabitant representation in memory to a unique 31-bit
|
||||
/// identifier, and map a valid representation of the type to -1.
|
||||
///
|
||||
/// Calls to this witness must be dominated by a runtime check that the type
|
||||
/// has extra inhabitants.
|
||||
virtual llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
|
||||
Address src,
|
||||
SILType T,
|
||||
bool isOutlined) const = 0;
|
||||
|
||||
/// Store the extra inhabitant representation indexed by a 31-bit identifier
|
||||
/// to memory.
|
||||
///
|
||||
/// Calls to this witness must be dominated by a runtime check that the type
|
||||
/// has extra inhabitants.
|
||||
virtual void storeExtraInhabitant(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
Address dest,
|
||||
SILType T,
|
||||
bool isOutlined) const = 0;
|
||||
|
||||
|
||||
/// Get the tag of a single payload enum with a payload of this type (\p T) e.g
|
||||
/// Optional<T>.
|
||||
virtual llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr,
|
||||
SILType T) const = 0;
|
||||
SILType T,
|
||||
bool isOutlined) const = 0;
|
||||
|
||||
/// Store the tag of a single payload enum with a payload of this type.
|
||||
virtual void storeEnumTagSinglePayload(IRGenFunction &IGF,
|
||||
llvm::Value *whichCase,
|
||||
llvm::Value *numEmptyCases,
|
||||
Address enumAddr,
|
||||
SILType T) const = 0;
|
||||
|
||||
SILType T,
|
||||
bool isOutlined) const = 0;
|
||||
|
||||
/// Return an extra-inhabitant tag for the given type, which will be
|
||||
/// 0 for a value that's not an extra inhabitant or else a value in
|
||||
/// 1...extraInhabitantCount. Note that the range is off by one relative
|
||||
/// to the expectations of FixedTypeInfo::getExtraInhabitantIndex!
|
||||
///
|
||||
/// Most places in IRGen shouldn't be using this.
|
||||
///
|
||||
/// knownXICount can be null.
|
||||
llvm::Value *getExtraInhabitantTagDynamic(IRGenFunction &IGF,
|
||||
Address address,
|
||||
SILType T,
|
||||
llvm::Value *knownXICount,
|
||||
bool isOutlined) const;
|
||||
|
||||
/// Store an extra-inhabitant tag for the given type, which is known to be
|
||||
/// in 1...extraInhabitantCount. Note that the range is off by one
|
||||
/// relative to the expectations of FixedTypeInfo::storeExtraInhabitant!
|
||||
///
|
||||
/// Most places in IRGen shouldn't be using this.
|
||||
void storeExtraInhabitantTagDynamic(IRGenFunction &IGF,
|
||||
llvm::Value *index,
|
||||
Address address,
|
||||
SILType T,
|
||||
bool isOutlined) const;
|
||||
|
||||
/// Compute the packing of values of this type into a fixed-size buffer.
|
||||
/// A value might not be stored in the fixed-size buffer because it does not
|
||||
/// fit or because it is not bit-wise takable. Non bit-wise takable values are
|
||||
|
||||
@@ -96,17 +96,12 @@ IRGenTypeVerifierFunction::emit(ArrayRef<CanType> formalTypes) {
|
||||
"is-bitwise-takable bit");
|
||||
unsigned xiCount = fixedTI->getFixedExtraInhabitantCount(IGM);
|
||||
verifyValues(metadata,
|
||||
emitLoadOfHasExtraInhabitants(*this, layoutType),
|
||||
getBoolConstant(xiCount != 0),
|
||||
"has-extra-inhabitants bit");
|
||||
emitLoadOfExtraInhabitantCount(*this, layoutType),
|
||||
IGM.getInt32(xiCount),
|
||||
"extra inhabitant count");
|
||||
|
||||
// Check extra inhabitants.
|
||||
if (xiCount > 0) {
|
||||
verifyValues(metadata,
|
||||
emitLoadOfExtraInhabitantCount(*this, layoutType),
|
||||
getSizeConstant(Size(xiCount)),
|
||||
"extra inhabitant count");
|
||||
|
||||
// Verify that the extra inhabitant representations are consistent.
|
||||
|
||||
// TODO: Update for EnumPayload implementation changes.
|
||||
@@ -122,10 +117,12 @@ IRGenTypeVerifierFunction::emit(ArrayRef<CanType> formalTypes) {
|
||||
auto xiMask = fixedTI->getFixedExtraInhabitantMask(IGM);
|
||||
auto xiSchema = EnumPayloadSchema::withBitSize(xiMask.getBitWidth());
|
||||
|
||||
auto maxXiCount = std::min(xiCount, 256u);
|
||||
auto numCases = llvm::ConstantInt::get(IGM.Int32Ty, maxXiCount);
|
||||
|
||||
// TODO: Randomize the set of extra inhabitants we check.
|
||||
unsigned bits = fixedTI->getFixedSize().getValueInBits();
|
||||
for (unsigned i = 0, e = std::min(xiCount, 256u);
|
||||
i < e; ++i) {
|
||||
for (unsigned i = 0, e = maxXiCount; i < e; ++i) {
|
||||
// Initialize the buffer with junk, to help ensure we're insensitive to
|
||||
// insignificant bits.
|
||||
// TODO: Randomize the filler.
|
||||
@@ -135,8 +132,9 @@ IRGenTypeVerifierFunction::emit(ArrayRef<CanType> formalTypes) {
|
||||
fixedTI->getFixedAlignment().getValue());
|
||||
|
||||
// Ask the runtime to store an extra inhabitant.
|
||||
auto index = llvm::ConstantInt::get(IGM.Int32Ty, i);
|
||||
emitStoreExtraInhabitantCall(*this, layoutType, index, xiOpaque);
|
||||
auto tag = llvm::ConstantInt::get(IGM.Int32Ty, i+1);
|
||||
emitStoreEnumTagSinglePayloadCall(*this, layoutType, tag,
|
||||
numCases, xiOpaque);
|
||||
|
||||
// Compare the stored extra inhabitant against the fixed extra
|
||||
// inhabitant pattern.
|
||||
@@ -171,11 +169,12 @@ IRGenTypeVerifierFunction::emit(ArrayRef<CanType> formalTypes) {
|
||||
fixedXIValue, xiSchema);
|
||||
maskedXIPayload.store(*this, fixedXIBuf);
|
||||
|
||||
auto runtimeIndex = emitGetExtraInhabitantIndexCall(*this, layoutType,
|
||||
fixedXIOpaque);
|
||||
auto runtimeTag =
|
||||
emitGetEnumTagSinglePayloadCall(*this, layoutType, numCases,
|
||||
fixedXIOpaque);
|
||||
verifyValues(metadata,
|
||||
runtimeIndex, index,
|
||||
llvm::Twine("extra inhabitant index calculation ")
|
||||
runtimeTag, tag,
|
||||
llvm::Twine("extra inhabitant tag calculation ")
|
||||
+ numberBuf.str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ class WitnessIndex {
|
||||
unsigned IsPrefix : 1;
|
||||
public:
|
||||
WitnessIndex() = default;
|
||||
WitnessIndex(ValueWitness index) : Value(int(index)) {}
|
||||
explicit WitnessIndex(int index, bool isPrefix)
|
||||
: Value(index), IsPrefix(isPrefix) {}
|
||||
|
||||
|
||||
@@ -1076,10 +1076,12 @@ public:
|
||||
// Dynamic multi-payload enums use the tag representations not assigned
|
||||
// to cases for extra inhabitants.
|
||||
if (tagCounts.numTagBytes >= 32) {
|
||||
NumExtraInhabitants = INT_MAX;
|
||||
NumExtraInhabitants = ValueWitnessFlags::MaxNumExtraInhabitants;
|
||||
} else {
|
||||
NumExtraInhabitants =
|
||||
(1 << (tagCounts.numTagBytes * 8)) - tagCounts.numTags;
|
||||
NumExtraInhabitants = std::min(NumExtraInhabitants,
|
||||
unsigned(ValueWitnessFlags::MaxNumExtraInhabitants));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1876,7 +1876,7 @@ checkDynamicCastFromOptional(OpaqueValue *dest,
|
||||
const Metadata *payloadType =
|
||||
cast<EnumMetadata>(srcType)->getGenericArgs()[0];
|
||||
unsigned enumCase =
|
||||
swift_getEnumCaseSinglePayload(src, payloadType, 1 /*emptyCases=*/);
|
||||
payloadType->vw_getEnumTagSinglePayload(src, /*emptyCases=*/1);
|
||||
if (enumCase != 0) {
|
||||
// Allow Optional<T>.none -> Optional<U>.none
|
||||
if (targetType->getKind() != MetadataKind::Optional) {
|
||||
@@ -1889,8 +1889,8 @@ checkDynamicCastFromOptional(OpaqueValue *dest,
|
||||
cast<EnumMetadata>(targetType)->getGenericArgs()[0];
|
||||
|
||||
// Inject the .none tag
|
||||
swift_storeEnumTagSinglePayload(dest, targetPayloadType, enumCase,
|
||||
1 /*emptyCases=*/);
|
||||
targetPayloadType->vw_storeEnumTagSinglePayload(dest, enumCase,
|
||||
/*emptyCases=*/1);
|
||||
|
||||
// We don't have to destroy the source, because it was nil.
|
||||
return {true, nullptr};
|
||||
@@ -2314,8 +2314,8 @@ static bool swift_dynamicCastImpl(OpaqueValue *dest, OpaqueValue *src,
|
||||
const Metadata *payloadType =
|
||||
cast<EnumMetadata>(targetType)->getGenericArgs()[0];
|
||||
if (swift_dynamicCast(dest, src, srcType, payloadType, flags)) {
|
||||
swift_storeEnumTagSinglePayload(dest, payloadType, 0 /*case*/,
|
||||
1 /*emptyCases*/);
|
||||
payloadType->vw_storeEnumTagSinglePayload(dest, /*case*/ 0,
|
||||
/*emptyCases*/ 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -2720,8 +2720,8 @@ static bool _dynamicCastClassToValueViaObjCBridgeable(
|
||||
}
|
||||
|
||||
// Initialize the buffer as an empty optional.
|
||||
swift_storeEnumTagSinglePayload((OpaqueValue *)optDestBuffer, targetType,
|
||||
1, 1);
|
||||
targetType->vw_storeEnumTagSinglePayload((OpaqueValue *)optDestBuffer,
|
||||
1, 1);
|
||||
|
||||
// Perform the bridging operation.
|
||||
bool success;
|
||||
|
||||
@@ -55,11 +55,6 @@ swift::swift_initEnumMetadataSingleCase(EnumMetadata *self,
|
||||
layout.stride = payloadLayout->stride;
|
||||
layout.flags = payloadLayout->flags.withEnumWitnesses(true);
|
||||
|
||||
if (payloadLayout->flags.hasExtraInhabitants()) {
|
||||
auto ew = static_cast<ExtraInhabitantsValueWitnessTable*>(vwtable);
|
||||
ew->extraInhabitantFlags = payloadLayout->getExtraInhabitantFlags();
|
||||
}
|
||||
|
||||
vwtable->publishLayout(layout);
|
||||
}
|
||||
|
||||
@@ -93,10 +88,11 @@ swift::swift_initEnumMetadataSinglePayload(EnumMetadata *self,
|
||||
TypeLayout layout;
|
||||
layout.size = size;
|
||||
layout.flags =
|
||||
payloadLayout->flags.withExtraInhabitants(unusedExtraInhabitants > 0)
|
||||
payloadLayout->flags
|
||||
.withEnumWitnesses(true)
|
||||
.withInlineStorage(
|
||||
ValueWitnessTable::isValueInline(isBT, size, align));
|
||||
layout.extraInhabitantCount = unusedExtraInhabitants;
|
||||
auto rawStride = llvm::alignTo(size, align);
|
||||
layout.stride = rawStride == 0 ? 1 : rawStride;
|
||||
|
||||
@@ -127,53 +123,42 @@ swift::swift_initEnumMetadataSinglePayload(EnumMetadata *self,
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// If the payload has extra inhabitants left over after the ones we used,
|
||||
// forward them as our own.
|
||||
if (unusedExtraInhabitants > 0) {
|
||||
auto xiVWTable = static_cast<ExtraInhabitantsValueWitnessTable*>(vwtable);
|
||||
xiVWTable->extraInhabitantFlags = ExtraInhabitantFlags()
|
||||
.withNumExtraInhabitants(unusedExtraInhabitants);
|
||||
}
|
||||
|
||||
vwtable->publishLayout(layout);
|
||||
}
|
||||
|
||||
unsigned swift::swift_getEnumCaseSinglePayload(const OpaqueValue *value,
|
||||
const Metadata *payload,
|
||||
unsigned emptyCases) {
|
||||
|
||||
auto *payloadWitnesses = payload->getValueWitnesses();
|
||||
auto size = payloadWitnesses->getSize();
|
||||
auto numExtraInhabitants = payloadWitnesses->getNumExtraInhabitants();
|
||||
auto EIVWT = dyn_cast<ExtraInhabitantsValueWitnessTable>(payloadWitnesses);
|
||||
auto getExtraInhabitantIndex = EIVWT ? EIVWT->getExtraInhabitantIndex : nullptr;
|
||||
|
||||
return getEnumTagSinglePayloadImpl(value, emptyCases, payload, size,
|
||||
unsigned
|
||||
swift::swift_getEnumTagSinglePayloadGeneric(const OpaqueValue *value,
|
||||
unsigned emptyCases,
|
||||
const Metadata *payloadType,
|
||||
unsigned (*getExtraInhabitantTag)(const OpaqueValue *value,
|
||||
const Metadata *payloadType)) {
|
||||
auto size = payloadType->vw_size();
|
||||
auto numExtraInhabitants = payloadType->vw_getNumExtraInhabitants();
|
||||
return getEnumTagSinglePayloadImpl(value, emptyCases, payloadType, size,
|
||||
numExtraInhabitants,
|
||||
getExtraInhabitantIndex);
|
||||
getExtraInhabitantTag);
|
||||
}
|
||||
|
||||
void swift::swift_storeEnumTagSinglePayload(OpaqueValue *value,
|
||||
const Metadata *payload,
|
||||
unsigned whichCase,
|
||||
unsigned emptyCases) {
|
||||
|
||||
auto *payloadWitnesses = payload->getValueWitnesses();
|
||||
auto size = payloadWitnesses->getSize();
|
||||
auto numExtraInhabitants = payloadWitnesses->getNumExtraInhabitants();
|
||||
auto EIVWT = dyn_cast<ExtraInhabitantsValueWitnessTable>(payloadWitnesses);
|
||||
auto storeExtraInhabitant = EIVWT ? EIVWT->storeExtraInhabitant : nullptr;
|
||||
|
||||
storeEnumTagSinglePayloadImpl(value, whichCase, emptyCases, payload, size,
|
||||
numExtraInhabitants, storeExtraInhabitant);
|
||||
void swift::swift_storeEnumTagSinglePayloadGeneric(OpaqueValue *value,
|
||||
unsigned whichCase,
|
||||
unsigned emptyCases,
|
||||
const Metadata *payloadType,
|
||||
void (*storeExtraInhabitantTag)(OpaqueValue *value,
|
||||
unsigned whichCase,
|
||||
const Metadata *payloadType)) {
|
||||
auto size = payloadType->vw_size();
|
||||
auto numExtraInhabitants = payloadType->vw_getNumExtraInhabitants();
|
||||
storeEnumTagSinglePayloadImpl(value, whichCase, emptyCases, payloadType, size,
|
||||
numExtraInhabitants, storeExtraInhabitantTag);
|
||||
}
|
||||
|
||||
static int32_t getMultiPayloadExtraInhabitantIndex(const OpaqueValue *value,
|
||||
const Metadata *enumType);
|
||||
static void storeMultiPayloadExtraInhabitant(OpaqueValue *value,
|
||||
int32_t index,
|
||||
const Metadata *enumType);
|
||||
static uint32_t getMultiPayloadEnumTagSinglePayload(const OpaqueValue *value,
|
||||
uint32_t numExtraCases,
|
||||
const Metadata *enumType);
|
||||
static void storeMultiPayloadEnumTagSinglePayload(OpaqueValue *value,
|
||||
uint32_t index,
|
||||
uint32_t numExtraCases,
|
||||
const Metadata *enumType);
|
||||
|
||||
void
|
||||
swift::swift_initEnumMetadataMultiPayload(EnumMetadata *enumType,
|
||||
@@ -205,32 +190,32 @@ swift::swift_initEnumMetadataMultiPayload(EnumMetadata *enumType,
|
||||
unsigned numExtraInhabitants = tagCounts.numTagBytes == 4
|
||||
? INT_MAX
|
||||
: (1 << (tagCounts.numTagBytes * 8)) - tagCounts.numTags;
|
||||
numExtraInhabitants = std::min(numExtraInhabitants,
|
||||
unsigned(ValueWitnessFlags::MaxNumExtraInhabitants));
|
||||
|
||||
auto vwtable = getMutableVWTableForInit(enumType, layoutFlags);
|
||||
|
||||
// Set up the layout info in the vwtable.
|
||||
auto rawStride = (totalSize + alignMask) & ~alignMask;
|
||||
TypeLayout layout{totalSize,
|
||||
rawStride == 0 ? 1 : rawStride,
|
||||
ValueWitnessFlags()
|
||||
.withAlignmentMask(alignMask)
|
||||
.withPOD(isPOD)
|
||||
.withBitwiseTakable(isBT)
|
||||
.withExtraInhabitants(numExtraInhabitants > 0)
|
||||
.withEnumWitnesses(true)
|
||||
.withInlineStorage(ValueWitnessTable::isValueInline(
|
||||
isBT, totalSize, alignMask + 1)),
|
||||
rawStride == 0 ? 1 : rawStride,
|
||||
numExtraInhabitants > 0
|
||||
? ExtraInhabitantFlags()
|
||||
.withNumExtraInhabitants(numExtraInhabitants)
|
||||
: ExtraInhabitantFlags()};
|
||||
numExtraInhabitants};
|
||||
|
||||
installCommonValueWitnesses(layout, vwtable);
|
||||
if (numExtraInhabitants > 0) {
|
||||
vwtable->extraInhabitantFlags = layout.getExtraInhabitantFlags();
|
||||
vwtable->storeExtraInhabitant = storeMultiPayloadExtraInhabitant;
|
||||
vwtable->getExtraInhabitantIndex = getMultiPayloadExtraInhabitantIndex;
|
||||
}
|
||||
|
||||
// Unconditionally overwrite the enum-tag witnesses.
|
||||
// The compiler does not generate meaningful enum-tag witnesses for
|
||||
// enums in this state.
|
||||
vwtable->getEnumTagSinglePayload = getMultiPayloadEnumTagSinglePayload;
|
||||
vwtable->storeEnumTagSinglePayload = storeMultiPayloadEnumTagSinglePayload;
|
||||
|
||||
vwtable->publishLayout(layout);
|
||||
}
|
||||
|
||||
@@ -320,22 +305,40 @@ static unsigned loadMultiPayloadValue(const OpaqueValue *value,
|
||||
return payloadValue;
|
||||
}
|
||||
|
||||
static int32_t getMultiPayloadExtraInhabitantIndex(const OpaqueValue *value,
|
||||
const Metadata *enumType) {
|
||||
static unsigned getMultiPayloadExtraInhabitantTag(const OpaqueValue *value,
|
||||
const Metadata *enumType) {
|
||||
auto layout = getMultiPayloadLayout(cast<EnumMetadata>(enumType));
|
||||
unsigned index = ~loadMultiPayloadTag(value, layout, ~0u);
|
||||
|
||||
if (index >= enumType->getValueWitnesses()->getNumExtraInhabitants())
|
||||
return -1;
|
||||
return index;
|
||||
return 0;
|
||||
return index + 1;
|
||||
}
|
||||
static void storeMultiPayloadExtraInhabitant(OpaqueValue *value,
|
||||
int32_t index,
|
||||
const Metadata *enumType) {
|
||||
static void storeMultiPayloadExtraInhabitantTag(OpaqueValue *value,
|
||||
unsigned tag,
|
||||
const Metadata *enumType) {
|
||||
auto layout = getMultiPayloadLayout(cast<EnumMetadata>(enumType));
|
||||
storeMultiPayloadTag(value, layout, ~index);
|
||||
storeMultiPayloadTag(value, layout, ~(tag - 1));
|
||||
}
|
||||
|
||||
static uint32_t getMultiPayloadEnumTagSinglePayload(const OpaqueValue *value,
|
||||
uint32_t numExtraCases,
|
||||
const Metadata *enumType) {
|
||||
return getEnumTagSinglePayloadImpl(value, numExtraCases, enumType,
|
||||
enumType->vw_size(),
|
||||
enumType->vw_getNumExtraInhabitants(),
|
||||
getMultiPayloadExtraInhabitantTag);
|
||||
}
|
||||
|
||||
static void storeMultiPayloadEnumTagSinglePayload(OpaqueValue *value,
|
||||
uint32_t index,
|
||||
uint32_t numExtraCases,
|
||||
const Metadata *enumType) {
|
||||
storeEnumTagSinglePayloadImpl(value, index, numExtraCases, enumType,
|
||||
enumType->vw_size(),
|
||||
enumType->vw_getNumExtraInhabitants(),
|
||||
storeMultiPayloadExtraInhabitantTag);
|
||||
}
|
||||
|
||||
void
|
||||
swift::swift_storeEnumTagMultiPayload(OpaqueValue *value,
|
||||
|
||||
@@ -64,7 +64,7 @@ static inline void small_memset(void *dest, uint8_t value, unsigned count) {
|
||||
inline unsigned getEnumTagSinglePayloadImpl(
|
||||
const OpaqueValue *enumAddr, unsigned emptyCases, const Metadata *payload,
|
||||
size_t payloadSize, size_t payloadNumExtraInhabitants,
|
||||
int (*getExtraInhabitantIndex)(const OpaqueValue *, const Metadata *)) {
|
||||
unsigned (*getExtraInhabitantTag)(const OpaqueValue *, const Metadata *)) {
|
||||
|
||||
// If there are extra tag bits, check them.
|
||||
if (emptyCases > payloadNumExtraInhabitants) {
|
||||
@@ -116,7 +116,7 @@ inline unsigned getEnumTagSinglePayloadImpl(
|
||||
|
||||
// If there are extra inhabitants, see whether the payload is valid.
|
||||
if (payloadNumExtraInhabitants > 0) {
|
||||
return getExtraInhabitantIndex(enumAddr, payload) + 1;
|
||||
return getExtraInhabitantTag(enumAddr, payload);
|
||||
}
|
||||
|
||||
// Otherwise, we have always have a valid payload.
|
||||
@@ -127,8 +127,8 @@ inline void storeEnumTagSinglePayloadImpl(
|
||||
OpaqueValue *value, unsigned whichCase, unsigned emptyCases,
|
||||
const Metadata *payload, size_t payloadSize,
|
||||
size_t payloadNumExtraInhabitants,
|
||||
void (*storeExtraInhabitant)(OpaqueValue *, int whichCase,
|
||||
const Metadata *)) {
|
||||
void (*storeExtraInhabitantTag)(OpaqueValue *, unsigned whichCase,
|
||||
const Metadata *)) {
|
||||
|
||||
auto *valueAddr = reinterpret_cast<uint8_t *>(value);
|
||||
auto *extraTagBitAddr = valueAddr + payloadSize;
|
||||
@@ -150,8 +150,7 @@ inline void storeEnumTagSinglePayloadImpl(
|
||||
return;
|
||||
|
||||
// Store the extra inhabitant.
|
||||
unsigned noPayloadIndex = whichCase - 1;
|
||||
storeExtraInhabitant(value, noPayloadIndex, payload);
|
||||
storeExtraInhabitantTag(value, whichCase, payload);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -331,16 +331,16 @@ struct LLVM_LIBRARY_VISIBILITY OpaqueExistentialBox
|
||||
static constexpr unsigned numExtraInhabitants =
|
||||
swift_getHeapObjectExtraInhabitantCount();
|
||||
|
||||
static void storeExtraInhabitant(Container *dest, int index) {
|
||||
static void storeExtraInhabitantTag(Container *dest, unsigned tag) {
|
||||
swift_storeHeapObjectExtraInhabitant(
|
||||
const_cast<HeapObject **>(
|
||||
reinterpret_cast<const HeapObject **>(&dest->Header.Type)),
|
||||
index);
|
||||
tag - 1);
|
||||
}
|
||||
|
||||
static int getExtraInhabitantIndex(const Container *src) {
|
||||
static unsigned getExtraInhabitantTag(const Container *src) {
|
||||
return swift_getHeapObjectExtraInhabitantIndex(const_cast<HeapObject **>(
|
||||
reinterpret_cast<const HeapObject *const *>(&src->Header.Type)));
|
||||
reinterpret_cast<const HeapObject *const *>(&src->Header.Type))) + 1;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -387,14 +387,14 @@ struct LLVM_LIBRARY_VISIBILITY NonFixedOpaqueExistentialBox
|
||||
static constexpr unsigned numExtraInhabitants =
|
||||
swift_getHeapObjectExtraInhabitantCount();
|
||||
|
||||
static void storeExtraInhabitant(Container *dest, int index) {
|
||||
static void storeExtraInhabitantTag(Container *dest, unsigned tag) {
|
||||
swift_storeHeapObjectExtraInhabitant(
|
||||
(HeapObject**)(uintptr_t)&dest->Header.Type, index);
|
||||
(HeapObject**)(uintptr_t)&dest->Header.Type, tag - 1);
|
||||
}
|
||||
|
||||
static int getExtraInhabitantIndex(const Container *src) {
|
||||
static unsigned getExtraInhabitantTag(const Container *src) {
|
||||
return swift_getHeapObjectExtraInhabitantIndex(
|
||||
(HeapObject* const *)(uintptr_t)&src->Header.Type);
|
||||
(HeapObject* const *)(uintptr_t)&src->Header.Type) + 1;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -452,15 +452,15 @@ struct LLVM_LIBRARY_VISIBILITY ClassExistentialBoxBase
|
||||
}
|
||||
|
||||
template <class Container, class... A>
|
||||
static void storeExtraInhabitant(Container *dest, int index, A... args) {
|
||||
static void storeExtraInhabitantTag(Container *dest, unsigned tag, A... args) {
|
||||
swift_storeHeapObjectExtraInhabitant((HeapObject**) dest->getValueSlot(),
|
||||
index);
|
||||
tag - 1);
|
||||
}
|
||||
|
||||
template <class Container, class... A>
|
||||
static int getExtraInhabitantIndex(const Container *src, A... args) {
|
||||
static int getExtraInhabitantTag(const Container *src, A... args) {
|
||||
return swift_getHeapObjectExtraInhabitantIndex(
|
||||
(HeapObject* const *) src->getValueSlot());
|
||||
(HeapObject* const *) src->getValueSlot()) + 1;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -574,17 +574,17 @@ struct LLVM_LIBRARY_VISIBILITY ExistentialMetatypeBoxBase
|
||||
}
|
||||
|
||||
template <class Container, class... A>
|
||||
static void storeExtraInhabitant(Container *dest, int index, A... args) {
|
||||
static void storeExtraInhabitantTag(Container *dest, unsigned tag, A... args) {
|
||||
Metadata **MD = const_cast<Metadata **>(dest->getValueSlot());
|
||||
swift_storeHeapObjectExtraInhabitant(reinterpret_cast<HeapObject **>(MD),
|
||||
index);
|
||||
tag - 1);
|
||||
}
|
||||
|
||||
template <class Container, class... A>
|
||||
static int getExtraInhabitantIndex(const Container *src, A... args) {
|
||||
static int getExtraInhabitantTag(const Container *src, A... args) {
|
||||
Metadata **MD = const_cast<Metadata **>(src->getValueSlot());
|
||||
return swift_getHeapObjectExtraInhabitantIndex(
|
||||
reinterpret_cast<HeapObject *const *>(MD));
|
||||
reinterpret_cast<HeapObject *const *>(MD)) + 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ const ValueWitnessTable swift::VALUE_WITNESS_SYM(Symbol) = \
|
||||
BuiltinType<ctypes::Symbol>::Alignment>>::table;
|
||||
|
||||
#define BUILTIN_POINTER_TYPE(Symbol, Name) \
|
||||
const ExtraInhabitantsValueWitnessTable swift::VALUE_WITNESS_SYM(Symbol) = \
|
||||
const ValueWitnessTable swift::VALUE_WITNESS_SYM(Symbol) = \
|
||||
ValueWitnessTableForBox<pointer_types::Symbol>::table;
|
||||
|
||||
#define BUILTIN_VECTOR_TYPE(ElementSymbol, _, Width) \
|
||||
@@ -169,7 +169,7 @@ const ExtraInhabitantsValueWitnessTable swift::VALUE_WITNESS_SYM(Symbol) = \
|
||||
#include "swift/Runtime/BuiltinTypes.def"
|
||||
|
||||
/// The value-witness table for pointer-aligned unmanaged pointer types.
|
||||
const ExtraInhabitantsValueWitnessTable swift::METATYPE_VALUE_WITNESS_SYM(Bo) =
|
||||
const ValueWitnessTable swift::METATYPE_VALUE_WITNESS_SYM(Bo) =
|
||||
ValueWitnessTableForBox<PointerPointerBox>::table;
|
||||
|
||||
/*** Functions ***************************************************************/
|
||||
@@ -182,12 +182,12 @@ namespace {
|
||||
static constexpr unsigned numExtraInhabitants =
|
||||
FunctionPointerBox::numExtraInhabitants;
|
||||
|
||||
static void storeExtraInhabitant(char *dest, int index) {
|
||||
FunctionPointerBox::storeExtraInhabitant((void**) dest, index);
|
||||
static void storeExtraInhabitantTag(char *dest, unsigned tag) {
|
||||
FunctionPointerBox::storeExtraInhabitantTag((void**) dest, tag);
|
||||
}
|
||||
|
||||
static int getExtraInhabitantIndex(const char *src) {
|
||||
return FunctionPointerBox::getExtraInhabitantIndex((void * const *) src);
|
||||
static unsigned getExtraInhabitantTag(const char *src) {
|
||||
return FunctionPointerBox::getExtraInhabitantTag((void * const *) src);
|
||||
}
|
||||
};
|
||||
/// @noescape function types.
|
||||
@@ -197,28 +197,28 @@ namespace {
|
||||
static constexpr unsigned numExtraInhabitants =
|
||||
FunctionPointerBox::numExtraInhabitants;
|
||||
|
||||
static void storeExtraInhabitant(char *dest, int index) {
|
||||
FunctionPointerBox::storeExtraInhabitant((void **)dest, index);
|
||||
static void storeExtraInhabitantTag(char *dest, unsigned tag) {
|
||||
FunctionPointerBox::storeExtraInhabitantTag((void **)dest, tag);
|
||||
}
|
||||
|
||||
static int getExtraInhabitantIndex(const char *src) {
|
||||
return FunctionPointerBox::getExtraInhabitantIndex((void *const *)src);
|
||||
static unsigned getExtraInhabitantTag(const char *src) {
|
||||
return FunctionPointerBox::getExtraInhabitantTag((void *const *)src);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
/// The basic value-witness table for escaping function types.
|
||||
const ExtraInhabitantsValueWitnessTable
|
||||
const ValueWitnessTable
|
||||
swift::VALUE_WITNESS_SYM(FUNCTION_MANGLING) =
|
||||
ValueWitnessTableForBox<ThickFunctionBox>::table;
|
||||
|
||||
/// The basic value-witness table for @noescape function types.
|
||||
const ExtraInhabitantsValueWitnessTable
|
||||
const ValueWitnessTable
|
||||
swift::VALUE_WITNESS_SYM(NOESCAPE_FUNCTION_MANGLING) =
|
||||
ValueWitnessTableForBox<TrivialThickFunctionBox>::table;
|
||||
|
||||
/// The basic value-witness table for thin function types.
|
||||
const ExtraInhabitantsValueWitnessTable
|
||||
const ValueWitnessTable
|
||||
swift::VALUE_WITNESS_SYM(THIN_FUNCTION_MANGLING) =
|
||||
ValueWitnessTableForBox<FunctionPointerBox>::table;
|
||||
|
||||
|
||||
@@ -1039,7 +1039,7 @@ public:
|
||||
// NOTE: if you change the layout of this type, you'll also need
|
||||
// to update tuple_getValueWitnesses().
|
||||
unsigned ExtraInhabitantProvidingElement;
|
||||
ExtraInhabitantsValueWitnessTable Witnesses;
|
||||
ValueWitnessTable Witnesses;
|
||||
FullMetadata<TupleTypeMetadata> Data;
|
||||
|
||||
struct Key {
|
||||
@@ -1151,7 +1151,7 @@ static Lazy<TupleCache> TupleTypes;
|
||||
/// Given a metatype pointer, produce the value-witness table for it.
|
||||
/// This is equivalent to metatype->ValueWitnesses but more efficient.
|
||||
static const ValueWitnessTable *tuple_getValueWitnesses(const Metadata *metatype) {
|
||||
return ((const ExtraInhabitantsValueWitnessTable*) asFullMetadata(metatype)) - 1;
|
||||
return ((const ValueWitnessTable*) asFullMetadata(metatype)) - 1;
|
||||
}
|
||||
|
||||
/// Generic tuple value witness for 'projectBuffer'.
|
||||
@@ -1309,9 +1309,9 @@ static OpaqueValue *tuple_initializeBufferWithCopyOfBuffer(ValueBuffer *dest,
|
||||
return tuple_projectBuffer<IsPOD, IsInline>(dest, metatype);
|
||||
}
|
||||
|
||||
static void tuple_storeExtraInhabitant(OpaqueValue *tuple,
|
||||
int index,
|
||||
const Metadata *_metatype) {
|
||||
static void tuple_storeExtraInhabitantTag(OpaqueValue *tuple,
|
||||
unsigned tag,
|
||||
const Metadata *_metatype) {
|
||||
auto &metatype = *(const TupleTypeMetadata*) _metatype;
|
||||
auto cacheEntry = TupleCacheStorage::resolveExistingEntry(&metatype);
|
||||
auto &eltInfo =
|
||||
@@ -1319,11 +1319,13 @@ static void tuple_storeExtraInhabitant(OpaqueValue *tuple,
|
||||
|
||||
auto *elt = (OpaqueValue*)((uintptr_t)tuple + eltInfo.Offset);
|
||||
|
||||
eltInfo.Type->vw_storeExtraInhabitant(elt, index);
|
||||
assert(tag >= 1);
|
||||
assert(tag <= eltInfo.Type->vw_getNumExtraInhabitants());
|
||||
eltInfo.Type->vw_storeEnumTagSinglePayload(elt, tag, tag);
|
||||
}
|
||||
|
||||
static int tuple_getExtraInhabitantIndex(const OpaqueValue *tuple,
|
||||
const Metadata *_metatype) {
|
||||
static unsigned tuple_getExtraInhabitantTag(const OpaqueValue *tuple,
|
||||
const Metadata *_metatype) {
|
||||
auto &metatype = *(const TupleTypeMetadata*) _metatype;
|
||||
|
||||
auto cacheEntry = TupleCacheStorage::resolveExistingEntry(&metatype);
|
||||
@@ -1331,7 +1333,8 @@ static int tuple_getExtraInhabitantIndex(const OpaqueValue *tuple,
|
||||
metatype.getElement(cacheEntry->ExtraInhabitantProvidingElement);
|
||||
|
||||
auto *elt = (const OpaqueValue*)((uintptr_t)tuple + eltInfo.Offset);
|
||||
return eltInfo.Type->vw_getExtraInhabitantIndex(elt);
|
||||
auto xiCount = eltInfo.Type->vw_getNumExtraInhabitants();
|
||||
return eltInfo.Type->vw_getEnumTagSinglePayload(elt, xiCount);
|
||||
}
|
||||
|
||||
template <bool IsPOD, bool IsInline>
|
||||
@@ -1342,12 +1345,11 @@ static unsigned tuple_getEnumTagSinglePayload(const OpaqueValue *enumAddr,
|
||||
auto *witnesses = tuple_getValueWitnesses(self);
|
||||
auto size = witnesses->getSize();
|
||||
auto numExtraInhabitants = witnesses->getNumExtraInhabitants();
|
||||
auto getExtraInhabitantIndex = numExtraInhabitants > 0
|
||||
? tuple_getExtraInhabitantIndex : nullptr;
|
||||
auto getExtraInhabitantTag = tuple_getExtraInhabitantTag;
|
||||
|
||||
return getEnumTagSinglePayloadImpl(enumAddr, numEmptyCases, self, size,
|
||||
numExtraInhabitants,
|
||||
getExtraInhabitantIndex);
|
||||
getExtraInhabitantTag);
|
||||
}
|
||||
|
||||
template <bool IsPOD, bool IsInline>
|
||||
@@ -1357,11 +1359,10 @@ tuple_storeEnumTagSinglePayload(OpaqueValue *enumAddr, unsigned whichCase,
|
||||
auto *witnesses = tuple_getValueWitnesses(self);
|
||||
auto size = witnesses->getSize();
|
||||
auto numExtraInhabitants = witnesses->getNumExtraInhabitants();
|
||||
auto storeExtraInhabitant = numExtraInhabitants > 0
|
||||
? tuple_storeExtraInhabitant : nullptr;
|
||||
auto storeExtraInhabitantTag = tuple_storeExtraInhabitantTag;
|
||||
|
||||
storeEnumTagSinglePayloadImpl(enumAddr, whichCase, numEmptyCases, self, size,
|
||||
numExtraInhabitants, storeExtraInhabitant);
|
||||
numExtraInhabitants, storeExtraInhabitantTag);
|
||||
}
|
||||
|
||||
/// Various standard witness table for tuples.
|
||||
@@ -1370,6 +1371,7 @@ static const ValueWitnessTable tuple_witnesses_pod_inline = {
|
||||
#define VALUE_WITNESS(LOWER_ID, UPPER_ID) &tuple_##LOWER_ID<true, true>,
|
||||
#define DATA_VALUE_WITNESS(LOWER_ID, UPPER_ID, TYPE)
|
||||
#include "swift/ABI/ValueWitness.def"
|
||||
0,
|
||||
0,
|
||||
ValueWitnessFlags(),
|
||||
0
|
||||
@@ -1379,6 +1381,7 @@ static const ValueWitnessTable tuple_witnesses_nonpod_inline = {
|
||||
#define VALUE_WITNESS(LOWER_ID, UPPER_ID) &tuple_##LOWER_ID<false, true>,
|
||||
#define DATA_VALUE_WITNESS(LOWER_ID, UPPER_ID, TYPE)
|
||||
#include "swift/ABI/ValueWitness.def"
|
||||
0,
|
||||
0,
|
||||
ValueWitnessFlags(),
|
||||
0
|
||||
@@ -1388,6 +1391,7 @@ static const ValueWitnessTable tuple_witnesses_pod_noninline = {
|
||||
#define VALUE_WITNESS(LOWER_ID, UPPER_ID) &tuple_##LOWER_ID<true, false>,
|
||||
#define DATA_VALUE_WITNESS(LOWER_ID, UPPER_ID, TYPE)
|
||||
#include "swift/ABI/ValueWitness.def"
|
||||
0,
|
||||
0,
|
||||
ValueWitnessFlags(),
|
||||
0
|
||||
@@ -1397,19 +1401,21 @@ static const ValueWitnessTable tuple_witnesses_nonpod_noninline = {
|
||||
#define VALUE_WITNESS(LOWER_ID, UPPER_ID) &tuple_##LOWER_ID<false, false>,
|
||||
#define DATA_VALUE_WITNESS(LOWER_ID, UPPER_ID, TYPE)
|
||||
#include "swift/ABI/ValueWitness.def"
|
||||
0,
|
||||
0,
|
||||
ValueWitnessFlags(),
|
||||
0
|
||||
};
|
||||
|
||||
static constexpr TypeLayout getInitialLayoutForValueType() {
|
||||
return {0, ValueWitnessFlags().withAlignment(1).withPOD(true), 0};
|
||||
return {0, 0, ValueWitnessFlags().withAlignment(1).withPOD(true), 0};
|
||||
}
|
||||
|
||||
static constexpr TypeLayout getInitialLayoutForHeapObject() {
|
||||
return {sizeof(HeapObject),
|
||||
sizeof(HeapObject),
|
||||
ValueWitnessFlags().withAlignment(alignof(HeapObject)),
|
||||
sizeof(HeapObject)};
|
||||
0};
|
||||
}
|
||||
|
||||
static size_t roundUpToAlignMask(size_t size, size_t alignMask) {
|
||||
@@ -1460,6 +1466,7 @@ static void performBasicLayout(TypeLayout &layout,
|
||||
.withPOD(isPOD)
|
||||
.withBitwiseTakable(isBitwiseTakable)
|
||||
.withInlineStorage(isInline);
|
||||
layout.extraInhabitantCount = 0;
|
||||
layout.stride = std::max(size_t(1), roundUpToAlignMask(size, alignMask));
|
||||
}
|
||||
|
||||
@@ -1505,10 +1512,9 @@ void swift::swift_getTupleTypeLayout(TypeLayout *result,
|
||||
|
||||
if (numExtraInhabitants > 0) {
|
||||
*result = TypeLayout(result->size,
|
||||
result->flags.withExtraInhabitants(true),
|
||||
result->stride,
|
||||
ExtraInhabitantFlags()
|
||||
.withNumExtraInhabitants(numExtraInhabitants));
|
||||
result->flags,
|
||||
numExtraInhabitants);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1649,22 +1655,16 @@ TupleCacheEntry::tryInitialize(Metadata *metadata,
|
||||
unsigned extraInhabitantProvidingElement = ~0u;
|
||||
unsigned numExtraInhabitants = 0;
|
||||
for (unsigned i = 0, e = Data.NumElements; i < e; ++i) {
|
||||
if (auto eltEIVWI = dyn_cast<ExtraInhabitantsValueWitnessTable>(
|
||||
Data.getElement(i).Type->getValueWitnesses())) {
|
||||
unsigned eltEI = eltEIVWI->extraInhabitantFlags.getNumExtraInhabitants();
|
||||
if (eltEI > numExtraInhabitants) {
|
||||
extraInhabitantProvidingElement = i;
|
||||
numExtraInhabitants = eltEI;
|
||||
}
|
||||
unsigned eltEI = Data.getElement(i).Type->getValueWitnesses()
|
||||
->getNumExtraInhabitants();
|
||||
if (eltEI > numExtraInhabitants) {
|
||||
extraInhabitantProvidingElement = i;
|
||||
numExtraInhabitants = eltEI;
|
||||
}
|
||||
}
|
||||
Witnesses.extraInhabitantCount = numExtraInhabitants;
|
||||
if (numExtraInhabitants > 0) {
|
||||
ExtraInhabitantProvidingElement = extraInhabitantProvidingElement;
|
||||
Witnesses.flags = Witnesses.flags.withExtraInhabitants(true);
|
||||
Witnesses.extraInhabitantFlags = ExtraInhabitantFlags()
|
||||
.withNumExtraInhabitants(numExtraInhabitants);
|
||||
Witnesses.storeExtraInhabitant = tuple_storeExtraInhabitant;
|
||||
Witnesses.getExtraInhabitantIndex = tuple_getExtraInhabitantIndex;
|
||||
}
|
||||
|
||||
// Copy the function witnesses in, either from the proposed
|
||||
@@ -1882,61 +1882,21 @@ static OpaqueValue *pod_indirect_initializeBufferWithCopyOfBuffer(
|
||||
return reinterpret_cast<OpaqueValue *>(bytePtr + byteOffset);
|
||||
}
|
||||
|
||||
static void pod_noop(void *object, const Metadata *self) {
|
||||
}
|
||||
#define pod_direct_destroy \
|
||||
pointer_function_cast<ValueWitnessTypes::destroy>(pod_noop)
|
||||
#define pod_indirect_destroy pod_direct_destroy
|
||||
static void pod_destroy(OpaqueValue *object, const Metadata *self) {}
|
||||
|
||||
static OpaqueValue *pod_direct_initializeWithCopy(OpaqueValue *dest,
|
||||
OpaqueValue *src,
|
||||
const Metadata *self) {
|
||||
static OpaqueValue *pod_copy(OpaqueValue *dest, OpaqueValue *src,
|
||||
const Metadata *self) {
|
||||
memcpy(dest, src, self->getValueWitnesses()->size);
|
||||
return dest;
|
||||
}
|
||||
#define pod_indirect_initializeWithCopy pod_direct_initializeWithCopy
|
||||
#define pod_direct_initializeBufferWithCopyOfBuffer \
|
||||
pointer_function_cast<ValueWitnessTypes::initializeBufferWithCopyOfBuffer> \
|
||||
(pod_direct_initializeWithCopy)
|
||||
#define pod_direct_assignWithCopy pod_direct_initializeWithCopy
|
||||
#define pod_indirect_assignWithCopy pod_direct_initializeWithCopy
|
||||
#define pod_direct_initializeWithTake pod_direct_initializeWithCopy
|
||||
#define pod_indirect_initializeWithTake pod_direct_initializeWithCopy
|
||||
#define pod_direct_assignWithTake pod_direct_initializeWithCopy
|
||||
#define pod_indirect_assignWithTake pod_direct_initializeWithCopy
|
||||
|
||||
static unsigned pod_direct_getEnumTagSinglePayload(const OpaqueValue *enumAddr,
|
||||
unsigned numEmptyCases,
|
||||
const Metadata *self) {
|
||||
auto *witnesses = self->getValueWitnesses();
|
||||
auto size = witnesses->getSize();
|
||||
auto numExtraInhabitants = witnesses->getNumExtraInhabitants();
|
||||
auto EIVWT = dyn_cast<ExtraInhabitantsValueWitnessTable>(witnesses);
|
||||
auto getExtraInhabitantIndex = EIVWT ? EIVWT->getExtraInhabitantIndex : nullptr;
|
||||
|
||||
return getEnumTagSinglePayloadImpl(enumAddr, numEmptyCases, self, size,
|
||||
numExtraInhabitants,
|
||||
getExtraInhabitantIndex);
|
||||
static OpaqueValue *pod_direct_initializeBufferWithCopyOfBuffer(
|
||||
ValueBuffer *dest, ValueBuffer *src, const Metadata *self) {
|
||||
return pod_copy(reinterpret_cast<OpaqueValue*>(dest),
|
||||
reinterpret_cast<OpaqueValue*>(src),
|
||||
self);
|
||||
}
|
||||
|
||||
static void pod_direct_storeEnumTagSinglePayload(OpaqueValue *enumAddr,
|
||||
unsigned whichCase,
|
||||
unsigned numEmptyCases,
|
||||
const Metadata *self) {
|
||||
auto *witnesses = self->getValueWitnesses();
|
||||
auto size = witnesses->getSize();
|
||||
auto numExtraInhabitants = witnesses->getNumExtraInhabitants();
|
||||
auto EIVWT = dyn_cast<ExtraInhabitantsValueWitnessTable>(witnesses);
|
||||
auto storeExtraInhabitant = EIVWT ? EIVWT->storeExtraInhabitant : nullptr;
|
||||
|
||||
storeEnumTagSinglePayloadImpl(enumAddr, whichCase, numEmptyCases, self, size,
|
||||
numExtraInhabitants, storeExtraInhabitant);
|
||||
}
|
||||
|
||||
#define pod_indirect_getEnumTagSinglePayload pod_direct_getEnumTagSinglePayload
|
||||
#define pod_indirect_storeEnumTagSinglePayload \
|
||||
pod_direct_storeEnumTagSinglePayload
|
||||
|
||||
static constexpr uint64_t sizeWithAlignmentMask(uint64_t size,
|
||||
uint64_t alignmentMask,
|
||||
uint64_t hasExtraInhabitants) {
|
||||
@@ -1951,25 +1911,26 @@ void swift::installCommonValueWitnesses(const TypeLayout &layout,
|
||||
// If the value has a common size and alignment, use specialized value
|
||||
// witnesses we already have lying around for the builtin types.
|
||||
const ValueWitnessTable *commonVWT;
|
||||
bool hasExtraInhabitants = flags.hasExtraInhabitants();
|
||||
bool hasExtraInhabitants = layout.hasExtraInhabitants();
|
||||
switch (sizeWithAlignmentMask(layout.size, flags.getAlignmentMask(),
|
||||
hasExtraInhabitants)) {
|
||||
default:
|
||||
// For uncommon layouts, use value witnesses that work with an arbitrary
|
||||
// size and alignment.
|
||||
if (flags.isInlineStorage()) {
|
||||
#define WANT_ONLY_REQUIRED_VALUE_WITNESSES
|
||||
#define VALUE_WITNESS(LOWER_ID, UPPER_ID) \
|
||||
vwtable->LOWER_ID = pod_direct_##LOWER_ID;
|
||||
#define DATA_VALUE_WITNESS(LOWER_ID, UPPER_ID, TYPE)
|
||||
#include "swift/ABI/ValueWitness.def"
|
||||
vwtable->initializeBufferWithCopyOfBuffer =
|
||||
pod_direct_initializeBufferWithCopyOfBuffer;
|
||||
} else {
|
||||
#define WANT_ONLY_REQUIRED_VALUE_WITNESSES
|
||||
#define VALUE_WITNESS(LOWER_ID, UPPER_ID) \
|
||||
vwtable->LOWER_ID = pod_indirect_##LOWER_ID;
|
||||
#define DATA_VALUE_WITNESS(LOWER_ID, UPPER_ID, TYPE)
|
||||
#include "swift/ABI/ValueWitness.def"
|
||||
vwtable->initializeBufferWithCopyOfBuffer =
|
||||
pod_indirect_initializeBufferWithCopyOfBuffer;
|
||||
}
|
||||
vwtable->destroy = pod_destroy;
|
||||
vwtable->initializeWithCopy = pod_copy;
|
||||
vwtable->initializeWithTake = pod_copy;
|
||||
vwtable->assignWithCopy = pod_copy;
|
||||
vwtable->assignWithTake = pod_copy;
|
||||
// getEnumTagSinglePayload and storeEnumTagSinglePayload are not
|
||||
// interestingly optimizable based on POD-ness.
|
||||
return;
|
||||
|
||||
case sizeWithAlignmentMask(1, 0, 0):
|
||||
@@ -2006,11 +1967,7 @@ void swift::installCommonValueWitnesses(const TypeLayout &layout,
|
||||
|
||||
if (flags.isBitwiseTakable()) {
|
||||
// Use POD value witnesses for operations that do an initializeWithTake.
|
||||
if (flags.isInlineStorage()) {
|
||||
vwtable->initializeWithTake = pod_direct_initializeWithTake;
|
||||
} else {
|
||||
vwtable->initializeWithTake = pod_indirect_initializeWithTake;
|
||||
}
|
||||
vwtable->initializeWithTake = pod_copy;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2021,8 +1978,7 @@ void swift::installCommonValueWitnesses(const TypeLayout &layout,
|
||||
/***************************************************************************/
|
||||
|
||||
static ValueWitnessTable *getMutableVWTableForInit(StructMetadata *self,
|
||||
StructLayoutFlags flags,
|
||||
bool hasExtraInhabitants) {
|
||||
StructLayoutFlags flags) {
|
||||
auto oldTable = self->getValueWitnesses();
|
||||
|
||||
// If we can alter the existing table in-place, do so.
|
||||
@@ -2030,17 +1986,9 @@ static ValueWitnessTable *getMutableVWTableForInit(StructMetadata *self,
|
||||
return const_cast<ValueWitnessTable*>(oldTable);
|
||||
|
||||
// Otherwise, allocate permanent memory for it and copy the existing table.
|
||||
ValueWitnessTable *newTable;
|
||||
if (hasExtraInhabitants) {
|
||||
void *memory = allocateMetadata(sizeof(ExtraInhabitantsValueWitnessTable),
|
||||
alignof(ExtraInhabitantsValueWitnessTable));
|
||||
newTable = new (memory) ExtraInhabitantsValueWitnessTable(
|
||||
*static_cast<const ExtraInhabitantsValueWitnessTable*>(oldTable));
|
||||
} else {
|
||||
void *memory = allocateMetadata(sizeof(ValueWitnessTable),
|
||||
alignof(ValueWitnessTable));
|
||||
newTable = new (memory) ValueWitnessTable(*oldTable);
|
||||
}
|
||||
void *memory = allocateMetadata(sizeof(ValueWitnessTable),
|
||||
alignof(ValueWitnessTable));
|
||||
auto newTable = new (memory) ValueWitnessTable(*oldTable);
|
||||
|
||||
// If we ever need to check layout-completeness asynchronously from
|
||||
// initialization, we'll need this to be a store-release (and rely on
|
||||
@@ -2066,33 +2014,18 @@ void swift::swift_initStructMetadata(StructMetadata *structType,
|
||||
});
|
||||
|
||||
// We have extra inhabitants if any element does. Use the field with the most.
|
||||
unsigned extraInhabitantField = ~0u;
|
||||
unsigned extraInhabitantCount = 0;
|
||||
for (unsigned i = 0; i < numFields; ++i) {
|
||||
if (!fieldTypes[i]->flags.hasExtraInhabitants())
|
||||
continue;
|
||||
unsigned fieldExtraInhabitantCount =
|
||||
fieldTypes[i]->getExtraInhabitantFlags().getNumExtraInhabitants();
|
||||
fieldTypes[i]->getNumExtraInhabitants();
|
||||
if (fieldExtraInhabitantCount > extraInhabitantCount) {
|
||||
extraInhabitantField = i;
|
||||
extraInhabitantCount = fieldExtraInhabitantCount;
|
||||
}
|
||||
}
|
||||
|
||||
auto vwtable =
|
||||
getMutableVWTableForInit(structType, layoutFlags,
|
||||
extraInhabitantCount > 0);
|
||||
|
||||
if (extraInhabitantCount > 0) {
|
||||
layout.flags = layout.flags.withExtraInhabitants(true);
|
||||
auto xiVWT = static_cast<ExtraInhabitantsValueWitnessTable*>(vwtable);
|
||||
xiVWT->extraInhabitantFlags =
|
||||
fieldTypes[extraInhabitantField]->getExtraInhabitantFlags();
|
||||
auto vwtable = getMutableVWTableForInit(structType, layoutFlags);
|
||||
|
||||
// The compiler should already have initialized these.
|
||||
assert(xiVWT->storeExtraInhabitant);
|
||||
assert(xiVWT->getExtraInhabitantIndex);
|
||||
}
|
||||
layout.extraInhabitantCount = extraInhabitantCount;
|
||||
|
||||
// Substitute in better value witnesses if we have them.
|
||||
installCommonValueWitnesses(layout, vwtable);
|
||||
@@ -2878,7 +2811,7 @@ namespace {
|
||||
/// A cache entry for existential metatype witness tables.
|
||||
class ExistentialMetatypeValueWitnessTableCacheEntry {
|
||||
public:
|
||||
ExtraInhabitantsValueWitnessTable Data;
|
||||
ValueWitnessTable Data;
|
||||
|
||||
unsigned getNumWitnessTables() const {
|
||||
return (Data.size - sizeof(ExistentialMetatypeContainer))
|
||||
@@ -2934,16 +2867,16 @@ ExistentialMetatypeValueWitnessTables;
|
||||
/// The uniquing structure for existential metatype type metadata.
|
||||
static SimpleGlobalCache<ExistentialMetatypeCacheEntry> ExistentialMetatypes;
|
||||
|
||||
static const ExtraInhabitantsValueWitnessTable
|
||||
static const ValueWitnessTable
|
||||
ExistentialMetatypeValueWitnesses_1 =
|
||||
ValueWitnessTableForBox<ExistentialMetatypeBox<1>>::table;
|
||||
static const ExtraInhabitantsValueWitnessTable
|
||||
static const ValueWitnessTable
|
||||
ExistentialMetatypeValueWitnesses_2 =
|
||||
ValueWitnessTableForBox<ExistentialMetatypeBox<2>>::table;
|
||||
|
||||
/// Instantiate a value witness table for an existential metatype
|
||||
/// container with the given number of witness table pointers.
|
||||
static const ExtraInhabitantsValueWitnessTable *
|
||||
static const ValueWitnessTable *
|
||||
getExistentialMetatypeValueWitnesses(unsigned numWitnessTables) {
|
||||
if (numWitnessTables == 0)
|
||||
return &getUnmanagedPointerPointerValueWitnesses();
|
||||
@@ -2977,11 +2910,9 @@ ExistentialMetatypeValueWitnessTableCacheEntry(unsigned numWitnessTables) {
|
||||
.withAlignment(Box::Container::getAlignment(numWitnessTables))
|
||||
.withPOD(true)
|
||||
.withBitwiseTakable(true)
|
||||
.withInlineStorage(false)
|
||||
.withExtraInhabitants(true);
|
||||
.withInlineStorage(false);
|
||||
Data.stride = Box::Container::getStride(numWitnessTables);
|
||||
Data.extraInhabitantFlags = ExtraInhabitantFlags()
|
||||
.withNumExtraInhabitants(Witnesses::numExtraInhabitants);
|
||||
Data.extraInhabitantCount = Witnesses::numExtraInhabitants;
|
||||
|
||||
assert(getNumWitnessTables() == numWitnessTables);
|
||||
}
|
||||
@@ -3073,7 +3004,7 @@ public:
|
||||
|
||||
class OpaqueExistentialValueWitnessTableCacheEntry {
|
||||
public:
|
||||
ExtraInhabitantsValueWitnessTable Data;
|
||||
ValueWitnessTable Data;
|
||||
|
||||
OpaqueExistentialValueWitnessTableCacheEntry(unsigned numTables);
|
||||
|
||||
@@ -3100,7 +3031,7 @@ public:
|
||||
|
||||
class ClassExistentialValueWitnessTableCacheEntry {
|
||||
public:
|
||||
ExtraInhabitantsValueWitnessTable Data;
|
||||
ValueWitnessTable Data;
|
||||
|
||||
ClassExistentialValueWitnessTableCacheEntry(unsigned numTables);
|
||||
|
||||
@@ -3130,10 +3061,10 @@ public:
|
||||
/// The uniquing structure for existential type metadata.
|
||||
static SimpleGlobalCache<ExistentialCacheEntry> ExistentialTypes;
|
||||
|
||||
static const ExtraInhabitantsValueWitnessTable
|
||||
static const ValueWitnessTable
|
||||
OpaqueExistentialValueWitnesses_0 =
|
||||
ValueWitnessTableForBox<OpaqueExistentialBox<0>>::table;
|
||||
static const ExtraInhabitantsValueWitnessTable
|
||||
static const ValueWitnessTable
|
||||
OpaqueExistentialValueWitnesses_1 =
|
||||
ValueWitnessTableForBox<OpaqueExistentialBox<1>>::table;
|
||||
|
||||
@@ -3201,22 +3132,16 @@ OpaqueExistentialValueWitnessTableCacheEntry(unsigned numWitnessTables) {
|
||||
.withAlignment(Box::Container::getAlignment(numWitnessTables))
|
||||
.withPOD(false)
|
||||
.withBitwiseTakable(true)
|
||||
.withInlineStorage(false)
|
||||
.withExtraInhabitants(true);
|
||||
.withInlineStorage(false);
|
||||
Data.extraInhabitantCount = Witnesses::numExtraInhabitants;
|
||||
Data.stride = Box::Container::getStride(numWitnessTables);
|
||||
|
||||
// Extra inhabitant behavior does not change with the number of witnesses.
|
||||
constexpr auto extraInhabitantFlags = Witnesses::extraInhabitantFlags;
|
||||
Data.extraInhabitantFlags = extraInhabitantFlags;
|
||||
Data.getExtraInhabitantIndex = Witnesses::getExtraInhabitantIndex;
|
||||
Data.storeExtraInhabitant = Witnesses::storeExtraInhabitant;
|
||||
|
||||
assert(getNumWitnessTables() == numWitnessTables);
|
||||
}
|
||||
|
||||
static const ExtraInhabitantsValueWitnessTable ClassExistentialValueWitnesses_1 =
|
||||
static const ValueWitnessTable ClassExistentialValueWitnesses_1 =
|
||||
ValueWitnessTableForBox<ClassExistentialBox<1>>::table;
|
||||
static const ExtraInhabitantsValueWitnessTable ClassExistentialValueWitnesses_2 =
|
||||
static const ValueWitnessTable ClassExistentialValueWitnesses_2 =
|
||||
ValueWitnessTableForBox<ClassExistentialBox<2>>::table;
|
||||
|
||||
/// The uniquing structure for class existential value witness tables.
|
||||
@@ -3225,7 +3150,7 @@ ClassExistentialValueWitnessTables;
|
||||
|
||||
/// Instantiate a value witness table for a class-constrained existential
|
||||
/// container with the given number of witness table pointers.
|
||||
static const ExtraInhabitantsValueWitnessTable *
|
||||
static const ValueWitnessTable *
|
||||
getClassExistentialValueWitnesses(const Metadata *superclass,
|
||||
unsigned numWitnessTables) {
|
||||
// FIXME: If the superclass is not @objc, use native reference counting.
|
||||
@@ -3266,11 +3191,9 @@ ClassExistentialValueWitnessTableCacheEntry(unsigned numWitnessTables) {
|
||||
.withAlignment(Box::Container::getAlignment(numWitnessTables))
|
||||
.withPOD(false)
|
||||
.withBitwiseTakable(true)
|
||||
.withInlineStorage(false)
|
||||
.withExtraInhabitants(true);
|
||||
.withInlineStorage(false);
|
||||
Data.extraInhabitantCount = Witnesses::numExtraInhabitants;
|
||||
Data.stride = Box::Container::getStride(numWitnessTables);
|
||||
Data.extraInhabitantFlags = ExtraInhabitantFlags()
|
||||
.withNumExtraInhabitants(Witnesses::numExtraInhabitants);
|
||||
|
||||
assert(getNumWitnessTables() == numWitnessTables);
|
||||
}
|
||||
|
||||
@@ -71,8 +71,8 @@ namespace metadataimpl {
|
||||
// static T *assignWithCopy(T *dest, T *src);
|
||||
// static T *assignWithTake(T *dest, T *src);
|
||||
// // Only if numExtraInhabitants is non-zero:
|
||||
// static void storeExtraInhabitant(T *dest, int index);
|
||||
// static int getExtraInhabitantIndex(const T *src);
|
||||
// static void storeExtraInhabitantTag(T *dest, unsigned index);
|
||||
// static unsigned getExtraInhabitantTag(const T *src);
|
||||
// };
|
||||
|
||||
/// A box class implemented in terms of C/C++ primitive operations.
|
||||
@@ -178,12 +178,12 @@ template <class Impl, class T> struct RetainableBoxBase {
|
||||
static constexpr unsigned numExtraInhabitants =
|
||||
swift_getHeapObjectExtraInhabitantCount();
|
||||
|
||||
static void storeExtraInhabitant(T *dest, int index) {
|
||||
swift_storeHeapObjectExtraInhabitant((HeapObject**) dest, index);
|
||||
static void storeExtraInhabitantTag(T *dest, unsigned tag) {
|
||||
swift_storeHeapObjectExtraInhabitant((HeapObject**) dest, tag - 1);
|
||||
}
|
||||
|
||||
static int getExtraInhabitantIndex(const T *src) {
|
||||
return swift_getHeapObjectExtraInhabitantIndex((HeapObject* const *) src);
|
||||
static unsigned getExtraInhabitantTag(const T *src) {
|
||||
return swift_getHeapObjectExtraInhabitantIndex((HeapObject* const *) src) +1;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -233,13 +233,13 @@ struct SwiftUnownedRetainableBox :
|
||||
// disabled.
|
||||
static constexpr unsigned numExtraInhabitants = 1;
|
||||
|
||||
static void storeExtraInhabitant(HeapObject **dest, int index) {
|
||||
assert(index == 0);
|
||||
static void storeExtraInhabitant(HeapObject **dest, unsigned index) {
|
||||
assert(index == 1);
|
||||
*dest = nullptr;
|
||||
}
|
||||
|
||||
static int getExtraInhabitantIndex(const HeapObject * const *src) {
|
||||
return (*src == nullptr ? 0 : -1);
|
||||
static unsigned getExtraInhabitantTag(const HeapObject * const *src) {
|
||||
return (*src == nullptr ? 1 : 0);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
@@ -311,12 +311,12 @@ struct ObjCUnownedRetainableBox
|
||||
: WeakRetainableBoxBase<ObjCUnownedRetainableBox, UnownedReference> {
|
||||
|
||||
static constexpr unsigned numExtraInhabitants = 1;
|
||||
static void storeExtraInhabitant(UnownedReference *dest, int index) {
|
||||
assert(index == 0);
|
||||
static void storeExtraInhabitantTag(UnownedReference *dest, unsigned index) {
|
||||
assert(index == 1);
|
||||
dest->Value = nullptr;
|
||||
}
|
||||
static int getExtraInhabitantIndex(const UnownedReference *src) {
|
||||
return (src->Value == nullptr ? 0 : -1);
|
||||
static unsigned getExtraInhabitantTag(const UnownedReference *src) {
|
||||
return (src->Value == nullptr ? 1 : 0);
|
||||
}
|
||||
|
||||
static void destroy(UnownedReference *ref) {
|
||||
@@ -424,12 +424,12 @@ struct PointerPointerBox : NativeBox<void**> {
|
||||
static constexpr unsigned numExtraInhabitants =
|
||||
swift_getHeapObjectExtraInhabitantCount();
|
||||
|
||||
static void storeExtraInhabitant(void ***dest, int index) {
|
||||
swift_storeHeapObjectExtraInhabitant((HeapObject**) dest, index);
|
||||
static void storeExtraInhabitantTag(void ***dest, unsigned tag) {
|
||||
swift_storeHeapObjectExtraInhabitant((HeapObject**) dest, tag - 1);
|
||||
}
|
||||
|
||||
static int getExtraInhabitantIndex(void ** const *src) {
|
||||
return swift_getHeapObjectExtraInhabitantIndex((HeapObject* const *) src);
|
||||
static unsigned getExtraInhabitantTag(void ** const *src) {
|
||||
return swift_getHeapObjectExtraInhabitantIndex((HeapObject* const *) src)+1;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -440,12 +440,13 @@ struct PointerPointerBox : NativeBox<void**> {
|
||||
struct RawPointerBox : NativeBox<void*> {
|
||||
static constexpr unsigned numExtraInhabitants = 1;
|
||||
|
||||
static void storeExtraInhabitant(void **dest, int index) {
|
||||
static void storeExtraInhabitantTag(void **dest, unsigned tag) {
|
||||
assert(tag == 1);
|
||||
*dest = nullptr;
|
||||
}
|
||||
|
||||
static int getExtraInhabitantIndex(void* const *src) {
|
||||
return *src == nullptr ? 0 : -1;
|
||||
static unsigned getExtraInhabitantTag(void* const *src) {
|
||||
return *src == nullptr ? 1 : 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -456,12 +457,12 @@ struct FunctionPointerBox : NativeBox<void*> {
|
||||
static constexpr unsigned numExtraInhabitants =
|
||||
swift_getFunctionPointerExtraInhabitantCount();
|
||||
|
||||
static void storeExtraInhabitant(void **dest, int index) {
|
||||
swift_storeFunctionPointerExtraInhabitant(dest, index);
|
||||
static void storeExtraInhabitantTag(void **dest, unsigned tag) {
|
||||
swift_storeFunctionPointerExtraInhabitant(dest, tag - 1);
|
||||
}
|
||||
|
||||
static int getExtraInhabitantIndex(void * const *src) {
|
||||
return swift_getFunctionPointerExtraInhabitantIndex(src);
|
||||
static unsigned getExtraInhabitantTag(void * const *src) {
|
||||
return swift_getFunctionPointerExtraInhabitantIndex(src) + 1;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -709,8 +710,8 @@ struct FixedSizeBufferValueWitnesses<Impl, isBitwiseTakable, Size, Alignment,
|
||||
unsigned numEmptyCases,
|
||||
const Metadata *self) {
|
||||
return getEnumTagSinglePayloadImpl(enumAddr, numEmptyCases, self, Size,
|
||||
Impl::numExtraInhabitants,
|
||||
Impl::getExtraInhabitantIndex);
|
||||
Impl::extraInhabitantCount,
|
||||
Impl::getExtraInhabitantTag);
|
||||
}
|
||||
|
||||
static void storeEnumTagSinglePayload(OpaqueValue *enumAddr,
|
||||
@@ -718,8 +719,8 @@ struct FixedSizeBufferValueWitnesses<Impl, isBitwiseTakable, Size, Alignment,
|
||||
unsigned numEmptyCases,
|
||||
const Metadata *self) {
|
||||
return storeEnumTagSinglePayloadImpl(enumAddr, whichCase, numEmptyCases,
|
||||
self, Size, Impl::numExtraInhabitants,
|
||||
Impl::storeExtraInhabitant);
|
||||
self, Size, Impl::extraInhabitantCount,
|
||||
Impl::storeExtraInhabitantTag);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -768,16 +769,13 @@ struct ValueWitnesses
|
||||
static constexpr size_t alignment = Box::alignment;
|
||||
static constexpr bool isPOD = Box::isPOD;
|
||||
static constexpr bool isBitwiseTakable = Box::isBitwiseTakable;
|
||||
static constexpr unsigned numExtraInhabitants = Box::numExtraInhabitants;
|
||||
static constexpr bool hasExtraInhabitants = (numExtraInhabitants != 0);
|
||||
static constexpr unsigned extraInhabitantCount = Box::numExtraInhabitants;
|
||||
static constexpr bool hasExtraInhabitants = (extraInhabitantCount != 0);
|
||||
static constexpr ValueWitnessFlags flags =
|
||||
ValueWitnessFlags().withAlignmentMask(alignment - 1)
|
||||
.withInlineStorage(Base::isInline && isBitwiseTakable)
|
||||
.withPOD(isPOD)
|
||||
.withBitwiseTakable(isBitwiseTakable)
|
||||
.withExtraInhabitants(hasExtraInhabitants);
|
||||
static constexpr ExtraInhabitantFlags extraInhabitantFlags =
|
||||
ExtraInhabitantFlags().withNumExtraInhabitants(numExtraInhabitants);
|
||||
.withBitwiseTakable(isBitwiseTakable);
|
||||
|
||||
static void destroy(OpaqueValue *value, const Metadata *self) {
|
||||
return Box::destroy((typename Box::type*) value);
|
||||
@@ -810,14 +808,14 @@ struct ValueWitnesses
|
||||
// These should not get instantiated if the type doesn't have extra
|
||||
// inhabitants.
|
||||
|
||||
static void storeExtraInhabitant(OpaqueValue *dest, int index,
|
||||
const Metadata *self) {
|
||||
Box::storeExtraInhabitant((typename Box::type*) dest, index);
|
||||
static void storeExtraInhabitantTag(OpaqueValue *dest, unsigned tag,
|
||||
const Metadata *self) {
|
||||
Box::storeExtraInhabitantTag((typename Box::type*) dest, tag);
|
||||
}
|
||||
|
||||
static int getExtraInhabitantIndex(const OpaqueValue *src,
|
||||
const Metadata *self) {
|
||||
return Box::getExtraInhabitantIndex((typename Box::type const *) src);
|
||||
static unsigned getExtraInhabitantTag(const OpaqueValue *src,
|
||||
const Metadata *self) {
|
||||
return Box::getExtraInhabitantTag((typename Box::type const *) src);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -839,8 +837,6 @@ struct NonFixedValueWitnesses :
|
||||
|
||||
static constexpr unsigned numExtraInhabitants = Box::numExtraInhabitants;
|
||||
static constexpr bool hasExtraInhabitants = (numExtraInhabitants != 0);
|
||||
static constexpr ExtraInhabitantFlags extraInhabitantFlags =
|
||||
ExtraInhabitantFlags().withNumExtraInhabitants(numExtraInhabitants);
|
||||
|
||||
static void destroy(OpaqueValue *value, const Metadata *self) {
|
||||
return Box::destroy((typename Box::type*) value, self);
|
||||
@@ -879,12 +875,11 @@ struct NonFixedValueWitnesses :
|
||||
const Metadata *self) {
|
||||
auto *payloadWitnesses = self->getValueWitnesses();
|
||||
auto size = payloadWitnesses->getSize();
|
||||
auto EIVWT = dyn_cast<ExtraInhabitantsValueWitnessTable>(payloadWitnesses);
|
||||
auto getExtraInhabitantIndex = EIVWT ? EIVWT->getExtraInhabitantIndex : nullptr;
|
||||
auto numExtraInhabitants = payloadWitnesses->getNumExtraInhabitants();
|
||||
|
||||
return getEnumTagSinglePayloadImpl(enumAddr, numEmptyCases, self, size,
|
||||
numExtraInhabitants,
|
||||
getExtraInhabitantIndex);
|
||||
getExtraInhabitantTag);
|
||||
}
|
||||
|
||||
static void storeEnumTagSinglePayload(OpaqueValue *enumAddr,
|
||||
@@ -894,34 +889,29 @@ struct NonFixedValueWitnesses :
|
||||
auto *payloadWitnesses = self->getValueWitnesses();
|
||||
auto size = payloadWitnesses->getSize();
|
||||
auto numExtraInhabitants = payloadWitnesses->getNumExtraInhabitants();
|
||||
auto EIVWT = dyn_cast<ExtraInhabitantsValueWitnessTable>(payloadWitnesses);
|
||||
auto storeExtraInhabitant = EIVWT ? EIVWT->storeExtraInhabitant : nullptr;
|
||||
|
||||
storeEnumTagSinglePayloadImpl(enumAddr, whichCase, numEmptyCases, self,
|
||||
size, numExtraInhabitants,
|
||||
storeExtraInhabitant);
|
||||
storeExtraInhabitantTag);
|
||||
}
|
||||
|
||||
// These should not get instantiated if the type doesn't have extra
|
||||
// inhabitants.
|
||||
|
||||
static void storeExtraInhabitant(OpaqueValue *dest, int index,
|
||||
const Metadata *self) {
|
||||
Box::storeExtraInhabitant((typename Box::type*) dest, index);
|
||||
static void storeExtraInhabitantTag(OpaqueValue *dest, unsigned tag,
|
||||
const Metadata *self) {
|
||||
Box::storeExtraInhabitantTag((typename Box::type*) dest, tag);
|
||||
}
|
||||
|
||||
static int getExtraInhabitantIndex(const OpaqueValue *src,
|
||||
const Metadata *self) {
|
||||
return Box::getExtraInhabitantIndex((typename Box::type const *) src);
|
||||
static unsigned getExtraInhabitantTag(const OpaqueValue *src,
|
||||
const Metadata *self) {
|
||||
return Box::getExtraInhabitantTag((typename Box::type const *) src);
|
||||
}
|
||||
};
|
||||
|
||||
/// A class which defines a ValueWitnessTable.
|
||||
template <class Witnesses,
|
||||
bool HasExtraInhabitants = Witnesses::hasExtraInhabitants>
|
||||
struct ValueWitnessTableGenerator;
|
||||
|
||||
template <class Witnesses> struct ValueWitnessTableGenerator<Witnesses, false> {
|
||||
template <class Witnesses>
|
||||
struct ValueWitnessTableGenerator {
|
||||
static constexpr const ValueWitnessTable table = {
|
||||
#define WANT_ONLY_REQUIRED_VALUE_WITNESSES
|
||||
#define VALUE_WITNESS(LOWER_ID, UPPER_ID) Witnesses::LOWER_ID,
|
||||
@@ -929,20 +919,6 @@ template <class Witnesses> struct ValueWitnessTableGenerator<Witnesses, false> {
|
||||
};
|
||||
};
|
||||
|
||||
/// A class which defines an ExtraInhabitantsValueWitnessTable.
|
||||
template <class Witnesses> struct ValueWitnessTableGenerator<Witnesses, true> {
|
||||
static constexpr const ExtraInhabitantsValueWitnessTable table = {
|
||||
{
|
||||
#define WANT_ONLY_REQUIRED_VALUE_WITNESSES
|
||||
#define VALUE_WITNESS(LOWER_ID, UPPER_ID) Witnesses::LOWER_ID,
|
||||
#include "swift/ABI/ValueWitness.def"
|
||||
},
|
||||
#define WANT_ONLY_EXTRA_INHABITANT_VALUE_WITNESSES
|
||||
#define VALUE_WITNESS(LOWER_ID, UPPER_ID) Witnesses::LOWER_ID,
|
||||
#include "swift/ABI/ValueWitness.def"
|
||||
};
|
||||
};
|
||||
|
||||
/// A convenient way to get the value witness table for a box class.
|
||||
template <class Box>
|
||||
using ValueWitnessTableForBox = ValueWitnessTableGenerator<ValueWitnesses<Box>>;
|
||||
|
||||
@@ -183,14 +183,13 @@ func sizeof_alignof_test() {
|
||||
|
||||
// CHECK: define hidden {{.*}}void @"$s8builtins27generic_sizeof_alignof_testyyxlF"
|
||||
func generic_sizeof_alignof_test<T>(_: T) {
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[T:%.*]], i32 8
|
||||
// CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]]
|
||||
// CHECK-NEXT: [[SIZE:%.*]] = ptrtoint i8* [[T1]] to i64
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[T:%.*]], i32 0, i32 8
|
||||
// CHECK-NEXT: [[SIZE:%.*]] = load i64, i64* [[T0]]
|
||||
// CHECK-NEXT: store i64 [[SIZE]], i64* [[S:%.*]]
|
||||
var s = Builtin.sizeof(T.self)
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[T:%.*]], i32 9
|
||||
// CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]]
|
||||
// CHECK-NEXT: [[T2:%.*]] = ptrtoint i8* [[T1]] to i64
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[T:%.*]], i32 0, i32 10
|
||||
// CHECK-NEXT: [[FLAGS:%.*]] = load i32, i32* [[T0]]
|
||||
// CHECK-NEXT: [[T2:%.*]] = zext i32 [[FLAGS]] to i64
|
||||
// CHECK-NEXT: [[T3:%.*]] = and i64 [[T2]], 255
|
||||
// CHECK-NEXT: [[ALIGN:%.*]] = add i64 [[T3]], 1
|
||||
// CHECK-NEXT: store i64 [[ALIGN]], i64* [[A:%.*]]
|
||||
@@ -199,9 +198,8 @@ func generic_sizeof_alignof_test<T>(_: T) {
|
||||
|
||||
// CHECK: define hidden {{.*}}void @"$s8builtins21generic_strideof_testyyxlF"
|
||||
func generic_strideof_test<T>(_: T) {
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[T:%.*]], i32 10
|
||||
// CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]]
|
||||
// CHECK-NEXT: [[STRIDE:%.*]] = ptrtoint i8* [[T1]] to i64
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[T:%.*]], i32 9
|
||||
// CHECK-NEXT: [[STRIDE:%.*]] = load i64, i64* [[T0]]
|
||||
// CHECK-NEXT: store i64 [[STRIDE]], i64* [[S:%.*]]
|
||||
var s = Builtin.strideof(T.self)
|
||||
}
|
||||
@@ -681,11 +679,10 @@ func isUniqueIUO(_ ref: inout Builtin.NativeObject?) -> Bool {
|
||||
|
||||
// CHECK-LABEL: define {{.*}} @{{.*}}generic_ispod_test
|
||||
func generic_ispod_test<T>(_: T) {
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[T:%.*]], i32 9
|
||||
// CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]]
|
||||
// CHECK-NEXT: [[FLAGS:%.*]] = ptrtoint i8* [[T1]] to i64
|
||||
// CHECK-NEXT: [[ISNOTPOD:%.*]] = and i64 [[FLAGS]], 65536
|
||||
// CHECK-NEXT: [[ISPOD:%.*]] = icmp eq i64 [[ISNOTPOD]], 0
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[T:%.*]], i32 10
|
||||
// CHECK-NEXT: [[FLAGS:%.*]] = load i32, i32* [[T0]]
|
||||
// CHECK-NEXT: [[ISNOTPOD:%.*]] = and i32 [[FLAGS]], 65536
|
||||
// CHECK-NEXT: [[ISPOD:%.*]] = icmp eq i32 [[ISNOTPOD]], 0
|
||||
// CHECK-NEXT: store i1 [[ISPOD]], i1* [[S:%.*]]
|
||||
var s = Builtin.ispod(T.self)
|
||||
}
|
||||
@@ -700,11 +697,10 @@ func ispod_test() {
|
||||
|
||||
// CHECK-LABEL: define {{.*}} @{{.*}}generic_isbitwisetakable_test
|
||||
func generic_isbitwisetakable_test<T>(_: T) {
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[T:%.*]], i32 9
|
||||
// CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]]
|
||||
// CHECK-NEXT: [[FLAGS:%.*]] = ptrtoint i8* [[T1]] to i64
|
||||
// CHECK-NEXT: [[ISNOTBITWISETAKABLE:%.*]] = and i64 [[FLAGS]], 1048576
|
||||
// CHECK-NEXT: [[ISBITWISETAKABLE:%.*]] = icmp eq i64 [[ISNOTBITWISETAKABLE]], 0
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[T:%.*]], i32 10
|
||||
// CHECK-NEXT: [[FLAGS:%.*]] = load i32, i32* [[T0]]
|
||||
// CHECK-NEXT: [[ISNOTBITWISETAKABLE:%.*]] = and i32 [[FLAGS]], 1048576
|
||||
// CHECK-NEXT: [[ISBITWISETAKABLE:%.*]] = icmp eq i32 [[ISNOTBITWISETAKABLE]], 0
|
||||
// CHECK-NEXT: store i1 [[ISBITWISETAKABLE]], i1* [[S:%.*]]
|
||||
var s = Builtin.isbitwisetakable(T.self)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// #if directives don't work with SIL keywords, therefore please put ObjC tests
|
||||
// in `enum_objc.sil`.
|
||||
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -gnone -emit-ir -enable-objc-interop | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-objc --check-prefix=CHECK-objc-%target-ptrsize --check-prefix=CHECK-objc-%target-ptrsize-simulator-%target-is-simulator
|
||||
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -gnone -emit-ir -disable-objc-interop | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-native --check-prefix=CHECK-native-%target-ptrsize
|
||||
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -gnone -emit-ir -enable-objc-interop | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-objc --check-prefix=CHECK-objc-%target-ptrsize --check-prefix=CHECK-objc-%target-ptrsize-simulator-%target-is-simulator -DWORD=i%target-ptrsize
|
||||
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -gnone -emit-ir -disable-objc-interop | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-native --check-prefix=CHECK-native-%target-ptrsize -DWORD=i%target-ptrsize
|
||||
|
||||
// REQUIRES: CPU=i386 || CPU=x86_64
|
||||
|
||||
@@ -104,13 +104,17 @@ import Swift
|
||||
|
||||
// -- Dynamic metadata template carries a value witness table pattern
|
||||
// we fill in on instantiation.
|
||||
// The witness table pattern includes extra inhabitant witness
|
||||
// implementations which are used if the instance has extra inhabitants.
|
||||
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
|
||||
// CHECK: @"$s4enum16DynamicSingletonOWV" =
|
||||
// CHECK-SAME: i8* null
|
||||
// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s4enum16DynamicSingletonOwxs" to i8*)
|
||||
// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s4enum16DynamicSingletonOwxg" to i8*)
|
||||
// CHECK-SAME: [[WORD]] 0,
|
||||
// CHECK-SAME: [[WORD]] 0,
|
||||
// 6291456 == 0x600000 (enum, incomplete)
|
||||
// CHECK-SAME: i32 6291456,
|
||||
// CHECK-SAME: i32 0,
|
||||
// Enum witnesses.
|
||||
// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s4enum16DynamicSingletonOwug" to i8*)
|
||||
// CHECK-SAME: i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s4enum16DynamicSingletonOwup" to i8*)
|
||||
// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s4enum16DynamicSingletonOwui" to i8*)
|
||||
|
||||
// CHECK: [[DYNAMICSINGLETON_NAME:@.*]] = private constant [17 x i8] c"DynamicSingleton\00"
|
||||
// CHECK: @"$s4enum16DynamicSingletonOMn" = hidden constant <{
|
||||
@@ -129,62 +133,55 @@ import Swift
|
||||
|
||||
// CHECK: @"$s4enum16DynamicSingletonOMP" = internal constant <{ {{.*}} }> <{
|
||||
// CHECK-SAME: @"$s4enum16DynamicSingletonOMi"
|
||||
// CHECK-SAME: [17 x i8*]* @"$s4enum16DynamicSingletonOWV"
|
||||
// CHECK-SAME: %swift.enum_vwtable* @"$s4enum16DynamicSingletonOWV"
|
||||
|
||||
// -- No-payload enums have extra inhabitants in
|
||||
// their value witness table.
|
||||
// CHECK: @"$s4enum10NoPayloadsOWV" = internal constant [17 x i8*] [
|
||||
// CHECK: @"$s4enum10NoPayloadsOWV" = internal constant %swift.enum_vwtable {
|
||||
// -- ...
|
||||
// -- size
|
||||
// CHECK-SAME: i8* inttoptr ([[WORD:i32|i64]] 1 to i8*),
|
||||
// -- flags 0x24_0000 - alignment 1, has extra inhabitants and enum witnesses
|
||||
// CHECK-SAME: i8* inttoptr ([[WORD]] 2359296 to i8*),
|
||||
// CHECK-SAME: [[WORD]] 1,
|
||||
// -- stride
|
||||
// CHECK-SAME: i8* inttoptr ([[WORD]] 1 to i8*),
|
||||
// CHECK-SAME: [[WORD]] 1,
|
||||
// -- flags (0x20_0000: alignment 1 and enum witnesses)
|
||||
// CHECK-SAME: i32 2097152,
|
||||
// -- num extra inhabitants (256 - 3 valid states)
|
||||
// CHECK-SAME: i8* inttoptr ([[WORD]] 253 to i8*)
|
||||
// -- storeExtraInhabitant
|
||||
// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s4enum10NoPayloadsOwxs" to i8*)
|
||||
// -- getExtraInhabitantIndex
|
||||
// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s4enum10NoPayloadsOwxg" to i8*)
|
||||
// CHECK-SAME: ]
|
||||
// CHECK-SAME: i32 253,
|
||||
// CHECK-SAME: }, align
|
||||
|
||||
// -- Single-payload enums take unused extra inhabitants from their payload
|
||||
// as their own.
|
||||
// CHECK: @"$s4enum19SinglePayloadNestedOWV" = internal constant [17 x i8*] [
|
||||
// CHECK: @"$s4enum19SinglePayloadNestedOWV" = internal constant %swift.enum_vwtable {
|
||||
// -- ...
|
||||
// -- size
|
||||
// CHECK-SAME: i8* inttoptr ([[WORD]] 1 to i8*),
|
||||
// -- flags 0x4_0000 - alignment 1, has extra inhabitants
|
||||
// CHECK-SAME: i8* inttoptr ([[WORD]] 2359296 to i8*),
|
||||
// CHECK-SAME: [[WORD]] 1,
|
||||
// -- stride
|
||||
// CHECK-SAME: i8* inttoptr ([[WORD]] 1 to i8*),
|
||||
// CHECK-SAME: [[WORD]] 1,
|
||||
// -- flags (0x20_0000: alignment 1 and enum witnesses)
|
||||
// CHECK-SAME: i32 2097152,
|
||||
// -- num extra inhabitants (253 from payload - 3 empty cases)
|
||||
// CHECK-SAME: i8* inttoptr ([[WORD]] 250 to i8*)
|
||||
// -- storeExtraInhabitant
|
||||
// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s4enum19SinglePayloadNestedOwxs" to i8*)
|
||||
// -- getExtraInhabitantIndex
|
||||
// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s4enum19SinglePayloadNestedOwxg" to i8*)
|
||||
// CHECK-SAME: ]
|
||||
// CHECK-SAME: i32 250,
|
||||
// CHECK-SAME: }
|
||||
|
||||
// CHECK: @"$s4enum20DynamicSinglePayloadOWV" = internal constant [17 x i8*] [
|
||||
// CHECK-SAME: i8* null
|
||||
// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s4enum20DynamicSinglePayloadOwxs" to i8*)
|
||||
// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s4enum20DynamicSinglePayloadOwxg" to i8*)
|
||||
// CHECK: @"$s4enum20DynamicSinglePayloadOWV" = internal constant %swift.enum_vwtable {
|
||||
// -- flags (0x60_0000: alignment 1, incomplete, enum witnesses)
|
||||
// CHECK-SAME: i32 6291456,
|
||||
// -- num extra inhabitants (253 from payload - 3 empty cases)
|
||||
// CHECK-SAME: i32 0,
|
||||
|
||||
// CHECK: @"$s4enum20DynamicSinglePayloadOMP" = internal constant <{ {{.*}} }> <{
|
||||
// CHECK-SAME: @"$s4enum20DynamicSinglePayloadOMi"
|
||||
// CHECK-SAME: [17 x i8*]* @"$s4enum20DynamicSinglePayloadOWV"
|
||||
// CHECK-SAME: %swift.enum_vwtable* @"$s4enum20DynamicSinglePayloadOWV"
|
||||
|
||||
// CHECK: @"$s4enum18MultiPayloadNestedOWV" = internal constant [17 x i8*] [
|
||||
// CHECK: @"$s4enum18MultiPayloadNestedOWV" = internal constant %swift.enum_vwtable {
|
||||
// -- size
|
||||
// CHECK-32-SAME: i8* inttoptr ([[WORD]] 5 to i8*),
|
||||
// CHECK-64-SAME: i8* inttoptr ([[WORD]] 9 to i8*),
|
||||
// -- flags 0x250003 - alignment 4
|
||||
// CHECK-32-SAME: i8* inttoptr ([[WORD]] {{2686979|2359299}} to i8*)
|
||||
// -- flags 0x240007 - alignment 8, extra inhabitants
|
||||
// CHECK-64-SAME: i8* inttoptr ([[WORD]] 2359303 to i8*)
|
||||
// CHECK-SAME: ]
|
||||
// CHECK-32-SAME: [[WORD]] 5,
|
||||
// CHECK-64-SAME: [[WORD]] 9,
|
||||
// -- flags (0x250003: alignment 4, enum)
|
||||
// -- flags (0x200007: alignment 8, enum)
|
||||
// CHECK-32-SAME: i32 2097155,
|
||||
// CHECK-64-SAME: i32 2097159,
|
||||
// CHECK-SAME: }
|
||||
|
||||
enum Empty {}
|
||||
|
||||
@@ -2688,18 +2685,19 @@ entry(%x : $*MyOptional):
|
||||
// CHECK: [[T_LAYOUT:%.*]] = getelementptr inbounds i8*, i8** [[T_VWT]], i32 8
|
||||
// CHECK: call void @swift_initEnumMetadataSinglePayload(%swift.type* [[METADATA]], [[WORD]] 0, i8** [[T_LAYOUT]], i32 3)
|
||||
|
||||
// CHECK-64-LABEL: define internal void @"$s4enum17StructWithWeakVarVwxs"(%swift.opaque* noalias %dest, i32 %index, %swift.type* %StructWithWeakVar)
|
||||
// CHECK-64-LABEL: define internal void @"$s4enum17StructWithWeakVarVwst"(%swift.opaque* noalias %value, i32 %whichCase, i32 %numEmptyCases, %swift.type* %StructWithWeakVar)
|
||||
// -- TODO: some pointless masking here.
|
||||
// -- TODO: should use EnumPayload word-chunking.
|
||||
// CHECK-64: %1 = zext i32 %index to i128
|
||||
// CHECK-64: [[INDEX:%.*]] = sub i32 %whichCase, 1
|
||||
// CHECK-64: [[T0:%.*]] = zext i32 [[INDEX]] to i128
|
||||
// -- 0xFFFF_FFFF_FFFF_FFFF
|
||||
// CHECK-64: %2 = and i128 %1, 18446744073709551615
|
||||
// CHECK-64: %3 = shl i128 %1, 3
|
||||
// CHECK-64: [[T1:%.*]] = and i128 [[T0]], 18446744073709551615
|
||||
// CHECK-64: [[T2:%.*]] = shl i128 [[T0]], 3
|
||||
// -- 0xFFFF_FFFF_FFFF_FFF8__0000_0000_0000_0000
|
||||
// CHECK-64: %4 = and i128 %3, 1329227995784915725329854470603931648
|
||||
// CHECK-64: %5 = or i128 %2, %4
|
||||
// CHECK-64: [[T3:%.*]] = and i128 [[T2]], 1329227995784915725329854470603931648
|
||||
// CHECK-64: [[T4:%.*]] = or i128 [[T1]], [[T3]]
|
||||
// -- 0x1__0000_0000_0000_0000
|
||||
// CHECK-64: %6 = or i128 %5, 18446744073709551616
|
||||
// CHECK-64: [[T5:%.*]] = or i128 [[T4]], 18446744073709551616
|
||||
|
||||
// CHECK-LABEL: define internal i32 @"$s4enum40MultiPayloadLessThan32BitsWithEmptyCasesOwug"(%swift.opaque* noalias %value
|
||||
// CHECK: [[VAL00:%.*]] = bitcast %swift.opaque* %value to %T4enum40MultiPayloadLessThan32BitsWithEmptyCasesO*
|
||||
|
||||
@@ -127,6 +127,3 @@ b:
|
||||
x:
|
||||
return undef : $()
|
||||
}
|
||||
|
||||
// Weak existentials allow extra inhabitants if not @objc, therefore StructWithWeakVar must emit:
|
||||
// CHECK: define internal void @"$s9enum_objc17StructWithWeakVarVwxs"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// RUN: %target-swift-frontend -emit-ir -enable-resilience -module-name=resilient_enum -I %t %S/../Inputs/resilient_enum.swift | %FileCheck %t/enum_resilience.swift --check-prefix=ENUM_RES
|
||||
// RUN: %target-swift-frontend -emit-ir -module-name=resilient_enum -I %t %S/../Inputs/resilient_enum.swift | %FileCheck %t/enum_resilience.swift --check-prefix=ENUM_NOT_RES
|
||||
// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_enum.swiftmodule -module-name=resilient_enum -I %t %S/../Inputs/resilient_enum.swift
|
||||
// RUN: %target-swift-frontend -module-name enum_resilience -I %t -emit-ir -enable-resilience %s | %FileCheck %t/enum_resilience.swift -DINT=i%target-ptrsize
|
||||
// RUN: %target-swift-frontend -module-name enum_resilience -I %t -emit-ir -enable-resilience %s | %FileCheck %t/enum_resilience.swift --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize -DINT=i%target-ptrsize
|
||||
// RUN: %target-swift-frontend -module-name enum_resilience -I %t -emit-ir -enable-resilience -O %s
|
||||
|
||||
import resilient_enum
|
||||
@@ -133,7 +133,9 @@ public func constructResilientEnumNoPayload() -> Medium {
|
||||
// CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR]], [[INT]] -1
|
||||
// CHECK-NEXT: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
|
||||
|
||||
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 16
|
||||
// CHECK-16-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 16
|
||||
// CHECK-32-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 14
|
||||
// CHECK-64-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 13
|
||||
// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
|
||||
// CHECK-NEXT: [[WITNESS_FN:%.*]] = bitcast i8* [[WITNESS]]
|
||||
// CHECK-NEXT: call void [[WITNESS_FN]](%swift.opaque* noalias %0, i32 [[TAG]], %swift.type* [[METADATA]])
|
||||
@@ -162,7 +164,9 @@ public func constructResilientEnumPayload(_ s: Size) -> Medium {
|
||||
// CHECK-NEXT: [[VWT_ADDR2:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR2]], [[INT]] -1
|
||||
// CHECK-NEXT: [[VWT2:%.*]] = load i8**, i8*** [[VWT_ADDR2]]
|
||||
|
||||
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT2]], i32 16
|
||||
// CHECK-16-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT2]], i32 16
|
||||
// CHECK-32-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT2]], i32 14
|
||||
// CHECK-64-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT2]], i32 13
|
||||
// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
|
||||
// CHECK-NEXT: [[WITNESS_FN:%destructiveInjectEnumTag]] = bitcast i8* [[WITNESS]]
|
||||
// CHECK-NEXT: call void [[WITNESS_FN]](%swift.opaque* noalias %0, i32 [[TAG]], %swift.type* [[METADATA2]])
|
||||
@@ -179,9 +183,9 @@ public func constructResilientEnumPayload(_ s: Size) -> Medium {
|
||||
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR]], [[INT]] -1
|
||||
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
|
||||
|
||||
// CHECK: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
|
||||
// CHECK: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
|
||||
// CHECK: [[WITNESS_FOR_SIZE:%size]] = ptrtoint i8* [[WITNESS]]
|
||||
// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK: [[WITNESS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
|
||||
// CHECK: [[WITNESS_FOR_SIZE:%size]] = load [[INT]], [[INT]]* [[WITNESS_ADDR]]
|
||||
// CHECK: [[ALLOCA:%.*]] = alloca i8, {{.*}} [[WITNESS_FOR_SIZE]], align 16
|
||||
// CHECK: [[ALLOCA:%.*]] = alloca i8, {{.*}} [[WITNESS_FOR_SIZE]], align 16
|
||||
// CHECK: [[ENUM_STORAGE:%.*]] = bitcast i8* [[ALLOCA]] to %swift.opaque*
|
||||
@@ -191,7 +195,9 @@ public func constructResilientEnumPayload(_ s: Size) -> Medium {
|
||||
// CHECK: [[WITNESS_FN:%initializeWithCopy]] = bitcast i8* [[WITNESS]]
|
||||
// CHECK: [[ENUM_COPY:%.*]] = call %swift.opaque* [[WITNESS_FN]](%swift.opaque* noalias [[ENUM_STORAGE]], %swift.opaque* noalias %0, %swift.type* [[METADATA]])
|
||||
|
||||
// CHECK: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 14
|
||||
// CHECK-16-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 14
|
||||
// CHECK-32-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 12
|
||||
// CHECK-64-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 11
|
||||
// CHECK: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
|
||||
// CHECK: [[WITNESS_FN:%getEnumTag]] = bitcast i8* [[WITNESS]]
|
||||
// CHECK: [[TAG:%.*]] = call i32 [[WITNESS_FN]](%swift.opaque* noalias [[ENUM_STORAGE]], %swift.type* [[METADATA]])
|
||||
|
||||
@@ -95,7 +95,7 @@ enum GenericFixedLayout<T> {
|
||||
}
|
||||
|
||||
|
||||
// CHECK-LABEL: @"$s20enum_value_semantics20SinglePayloadTrivialOWV" = internal constant [17 x i8*] [
|
||||
// CHECK-LABEL: @"$s20enum_value_semantics20SinglePayloadTrivialOWV" = internal constant %swift.enum_vwtable {
|
||||
// CHECK: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy9_8 to i8*),
|
||||
// CHECK: i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*),
|
||||
// CHECK: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy9_8 to i8*),
|
||||
@@ -104,49 +104,45 @@ enum GenericFixedLayout<T> {
|
||||
// CHECK: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy9_8 to i8*),
|
||||
// CHECK: i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s20enum_value_semantics20SinglePayloadTrivialOwet" to i8*),
|
||||
// CHECK: i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s20enum_value_semantics20SinglePayloadTrivialOwst" to i8*),
|
||||
// CHECK: i8* inttoptr (i64 9 to i8*),
|
||||
// CHECK: i8* inttoptr (i64 2097159 to i8*),
|
||||
// CHECK: i8* inttoptr (i64 16 to i8*),
|
||||
// CHECK: i8* null,
|
||||
// CHECK: i8* null,
|
||||
// CHECK: i8* null,
|
||||
// CHECK: i64 9,
|
||||
// CHECK: i64 16,
|
||||
// CHECK: i32 2097159,
|
||||
// CHECK: i32 0,
|
||||
// CHECK: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s20enum_value_semantics20SinglePayloadTrivialOwug" to i8*),
|
||||
// CHECK: i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s20enum_value_semantics20SinglePayloadTrivialOwup" to i8*),
|
||||
// CHECK: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s20enum_value_semantics20SinglePayloadTrivialOwui" to i8*)
|
||||
// CHECK: ]
|
||||
// CHECK: }
|
||||
|
||||
|
||||
// CHECK-LABEL: @"$s20enum_value_semantics20SinglePayloadTrivialOMf" =
|
||||
// CHECK-SAME: internal constant <{ {{.*}} }> <{
|
||||
// CHECK-SAME: i8** getelementptr inbounds ([17 x i8*], [17 x i8*]* @"$s20enum_value_semantics20SinglePayloadTrivialOWV", i32 0, i32 0),
|
||||
// CHECK-SAME: i8** getelementptr inbounds (%swift.enum_vwtable, %swift.enum_vwtable* @"$s20enum_value_semantics20SinglePayloadTrivialOWV", i32 0, i32 0),
|
||||
// CHECK-SAME: i64 513,
|
||||
// CHECK-SAME: {{.*}}* @"$s20enum_value_semantics20SinglePayloadTrivialOMn"
|
||||
// CHECK-SAME: }>
|
||||
|
||||
|
||||
// CHECK-LABEL: @"$s20enum_value_semantics23SinglePayloadNontrivialOWV" = internal constant [17 x i8*] [
|
||||
// CHECK-LABEL: @"$s20enum_value_semantics23SinglePayloadNontrivialOWV" = internal constant %swift.enum_vwtable {
|
||||
// CHECK: i8* bitcast (%swift.opaque* ([24 x i8]*, [24 x i8]*, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwCP" to i8*),
|
||||
// CHECK: i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwxx" to i8*),
|
||||
// CHECK: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwcp" to i8*),
|
||||
// CHECK: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwca" to i8*),
|
||||
// CHECK: i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy8_8 to i8*),
|
||||
// CHECK: i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwta" to i8*),
|
||||
// CHECK: i8* inttoptr (i64 8 to i8*),
|
||||
// -- 0x250007
|
||||
// CHECK: i8* inttoptr (i64 2424839 to i8*),
|
||||
// CHECK: i8* inttoptr (i64 8 to i8*),
|
||||
// CHECK: i64 8,
|
||||
// CHECK: i64 8,
|
||||
// -- 0x210007
|
||||
// CHECK: i32 2162695,
|
||||
// -- On Darwin, the first 4 GiB are unmapped: 0x7ffffffc
|
||||
// -- Otherwise, one can only assume the first page (4 KiB) is unmapped: 0xffd
|
||||
// CHECK-ios: i8* inttoptr (i64 2147483644 to i8*)
|
||||
// CHECK-macosx: i8* inttoptr (i64 2147483644 to i8*)
|
||||
// CHECK-watchos: i8* inttoptr (i64 2147483644 to i8*)
|
||||
// CHECK-darwin: i8* inttoptr (i64 2147483644 to i8*)
|
||||
// CHECK-objc-linux-gnu: i8* inttoptr (i64 2045 to i8*)
|
||||
// CHECK-native-linux-gnu: i8* inttoptr (i64 4093 to i8*)
|
||||
// CHECK-objc-windows: i8* inttoptr (i64 2045 to i8*)
|
||||
// CHECK-native-windows: i8* inttoptr (i64 4093 to i8*)
|
||||
// CHECK: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwxs" to i8*)
|
||||
// CHECK: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwxg" to i8*)
|
||||
// CHECK-ios: i32 2147483644
|
||||
// CHECK-macosx: i32 2147483644
|
||||
// CHECK-watchos: i32 2147483644
|
||||
// CHECK-darwin: i32 2147483644
|
||||
// CHECK-objc-linux-gnu: i32 2045
|
||||
// CHECK-native-linux-gnu: i32 4093
|
||||
// CHECK-objc-windows: i32 2045
|
||||
// CHECK-native-windows: i32 4093
|
||||
// CHECK: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwug" to i8*),
|
||||
// CHECK: i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwup" to i8*)
|
||||
// CHECK: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwui" to i8*)
|
||||
@@ -155,7 +151,7 @@ enum GenericFixedLayout<T> {
|
||||
|
||||
// CHECK-LABEL: @"$s20enum_value_semantics23SinglePayloadNontrivialOMf" =
|
||||
// CHECK-SAME: internal constant <{ {{.*}} }> <{
|
||||
// CHECK-SAME: i8** getelementptr inbounds ([17 x i8*], [17 x i8*]* @"$s20enum_value_semantics23SinglePayloadNontrivialOWV", i32 0, i32 0),
|
||||
// CHECK-SAME: i8** getelementptr inbounds (%swift.enum_vwtable, %swift.enum_vwtable* @"$s20enum_value_semantics23SinglePayloadNontrivialOWV", i32 0, i32 0),
|
||||
// CHECK-SAME: i64 513,
|
||||
// CHECK-SAME: {{.*}}* @"$s20enum_value_semantics23SinglePayloadNontrivialOMn"
|
||||
// CHECK-SAME: }>
|
||||
@@ -173,7 +169,7 @@ enum GenericFixedLayout<T> {
|
||||
// Pattern flags. 0x4020_0000 == (MetadataKind::Enum << 21).
|
||||
// CHECK-SAME: i32 1075838976,
|
||||
// Value witness table.
|
||||
// CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([17 x i8*]* @"$s20enum_value_semantics18GenericFixedLayoutOWV" to i64), i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32, i32, i32 }>, <{ i32, i32, i32, i32 }>* @"$s20enum_value_semantics18GenericFixedLayoutOMP", i32 0, i32 3) to i64)) to i32)
|
||||
// CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (%swift.enum_vwtable* @"$s20enum_value_semantics18GenericFixedLayoutOWV" to i64), i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32, i32, i32 }>, <{ i32, i32, i32, i32 }>* @"$s20enum_value_semantics18GenericFixedLayoutOMP", i32 0, i32 3) to i64)) to i32)
|
||||
// CHECK-SAME: }>
|
||||
|
||||
sil @single_payload_nontrivial_copy_destroy : $(@owned SinglePayloadNontrivial) -> () {
|
||||
@@ -197,16 +193,6 @@ bb0(%0 : $SinglePayloadNontrivial):
|
||||
//
|
||||
|
||||
|
||||
// -- NoPayload getExtraInhabitants
|
||||
// CHECK-LABEL: define internal i32 @"$s20enum_value_semantics9NoPayloadOwxg"
|
||||
// CHECK: [[VALUE:%.*]] = load i8, i8* {{%.*}}, align 1
|
||||
// CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[VALUE]] to i32
|
||||
// CHECK-NEXT: [[SUB:%.*]] = sub i32 [[ZEXT]], 3
|
||||
// CHECK-NEXT: [[EXTRA:%.*]] = icmp slt i32 [[SUB]], 0
|
||||
// CHECK-NEXT: [[RES:%.*]] = select i1 [[EXTRA]], i32 -1, i32 [[SUB]]
|
||||
// CHECK-NEXT: ret i32 [[RES]]
|
||||
|
||||
|
||||
// -- NoPayload getEnumTag
|
||||
// CHECK-LABEL: define internal i32 @"$s20enum_value_semantics9NoPayloadOwug"
|
||||
// CHECK: [[SELF:%.*]] = bitcast %swift.opaque* %value to %T20enum_value_semantics9NoPayloadO*
|
||||
|
||||
@@ -8,8 +8,8 @@ import Swift
|
||||
protocol P {}
|
||||
|
||||
// NonBitwiseTakableBit = 0x00100000. This struct is bitwise takable because
|
||||
// 0x70007 = 458759
|
||||
// CHECK: @"$s12existentials14BitwiseTakableVWV" = internal constant [14 x i8*] {{.*}} i8* inttoptr (i64 458759 to i8*)
|
||||
// 0x30007 = 196615
|
||||
// CHECK: @"$s12existentials14BitwiseTakableVWV" = internal constant %swift.vwtable {{.*}} i32 196615
|
||||
struct BitwiseTakable {
|
||||
var p: P
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -emit-ir | %FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-%target-ptrsize
|
||||
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -emit-ir | %FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-%target-ptrsize -DINT=i%target-ptrsize
|
||||
|
||||
sil_stage canonical
|
||||
|
||||
@@ -41,11 +41,11 @@ entry(%0 : $*T):
|
||||
// CHECK: [[CAST:%.*]] = bitcast %swift.type* [[METATYPE]]
|
||||
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{(i64|i32)}} -1
|
||||
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
|
||||
// CHECK: [[FLAG_WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
|
||||
// CHECK: [[FLAG_WITNESS:%.*]] = load i8*, i8** [[FLAG_WITNESS_ADDR]]
|
||||
// CHECK: [[FLAGS:%.*]] = ptrtoint i8* [[FLAG_WITNESS]]
|
||||
// CHECK: [[ISNOTINLINE:%.*]] = and {{(i64|i32)}} [[FLAGS]], 131072
|
||||
// CHECK: [[ISINLINE:%.*]] = icmp eq {{(i64|i32)}} [[ISNOTINLINE]], 0
|
||||
// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 10
|
||||
// CHECK: [[FLAGS:%.*]] = load i32, i32* [[FLAGS_ADDR]]
|
||||
// CHECK: [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
|
||||
// CHECK: [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
|
||||
// CHECK: [[EXISTENTIAL_BUFFER:%.*]] = getelementptr inbounds %T25existentials_opaque_boxed11ExistentialP, %T25existentials_opaque_boxed11ExistentialP* %0, i32 0, i32 0
|
||||
// CHECK: [[EXISTENTIAL_BUFFER_OPAQUE:%.*]] = bitcast [{{(24|12)}} x i8]* [[EXISTENTIAL_BUFFER]] to %swift.opaque*
|
||||
// CHECK: br i1 [[ISINLINE]], label %done, label %allocateBox
|
||||
@@ -115,11 +115,11 @@ entry:
|
||||
// CHECK: [[CAST:%.*]] = bitcast %swift.type* [[META]] to i8***
|
||||
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** %3, {{(i64|i32)}} -1
|
||||
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
|
||||
// CHECK: [[VW_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
|
||||
// CHECK: [[VW:%.*]] = load i8*, i8** [[VW_ADDR]]
|
||||
// CHECK: [[FLAGS:%.*]] = ptrtoint i8* [[VW]] to {{(i64|i32)}}
|
||||
// CHECK: [[MASKED:%.*]] = and {{(i64|i32)}} [[FLAGS]], 131072
|
||||
// CHECK: [[ISINLINE:%.*]] = icmp eq {{(i64|i32)}} [[MASKED]], 0
|
||||
// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 10
|
||||
// CHECK: [[FLAGS:%.*]] = load i32, i32* [[FLAGS_ADDR]]
|
||||
// CHECK: [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
|
||||
// CHECK: [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
|
||||
// CHECK: br i1 [[ISINLINE]], label %done, label %deallocateBox
|
||||
|
||||
// CHECK: done:
|
||||
@@ -132,10 +132,14 @@ entry:
|
||||
// CHECK: [[CAST:%.*]] = bitcast %swift.type* [[META]] to i8***
|
||||
// CHECK: [[VWT_ADDR2:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{(i64|i32)}} -1
|
||||
// CHECK: [[VWT2:%.*]] = load i8**, i8*** [[VWT_ADDR2]]
|
||||
// CHECK: [[VW_ADDR2:%.*]] = getelementptr inbounds i8*, i8** [[VWT2]], i32 8
|
||||
// CHECK: [[VW2:%.*]] = load i8*, i8** [[VW_ADDR2]]
|
||||
// CHECK: [[SIZE:%.*]] = ptrtoint i8* [[VW2]] to {{(i64|i32)}}
|
||||
// CHECK: [[ALIGNMASK:%.*]] = and {{(i64|i32)}} [[FLAGS]], 255
|
||||
// CHECK: [[VWT2_CAST:%.*]] = bitcast i8** [[VWT2]] to %swift.vwtable*
|
||||
// CHECK: [[SIZE2_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT2_CAST]], i32 0, i32 8
|
||||
// CHECK: [[SIZE:%.*]] = load [[INT]], [[INT]]* [[SIZE2_ADDR]]
|
||||
// CHECK-64:[[T0:%.*]] = zext i32 [[FLAGS]] to i64
|
||||
// CHECK-64:[[ALIGNMASK:%.*]] = and i64 [[T0]], 255
|
||||
// CHECK-32:[[ALIGNMASK:%.*]] = and i32 [[FLAGS]], 255
|
||||
// CHECK-16:[[T0:%.*]] = trunc i32 [[FLAGS]] to i16
|
||||
// CHECK-16:[[ALIGNMASK:%.*]] = and i16 [[T0]], 255
|
||||
// CHECK: [[HEADERSIZEPLUSALIGN:%.*]] = add {{(i64 16|i32 8)}}, [[ALIGNMASK]]
|
||||
// CHECK: [[NOTALIGNMASK:%.*]] = xor {{(i64|i32)}} [[ALIGNMASK]], -1
|
||||
// CHECK: [[ALIGNEDSTART:%.*]] = and {{(i64|i32)}} [[HEADERSIZEPLUSALIGN]], [[NOTALIGNMASK]]
|
||||
@@ -164,11 +168,11 @@ bb0(%0 : $*Existential):
|
||||
// CHECK: [[CAST:%.*]] = bitcast %swift.type* %1 to i8***
|
||||
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{(i64|i32)}} -1
|
||||
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
|
||||
// CHECK: [[VW_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
|
||||
// CHECK: [[VW:%.*]] = load i8*, i8** [[VW_ADDR]]
|
||||
// CHECK: [[FLAGS:%.*]] = ptrtoint i8* [[VW]] to {{(i64|i32)}}
|
||||
// CHECK: [[ISNOTINLINE:%.*]] = and {{(i64|i32)}} [[FLAGS]], 131072
|
||||
// CHECK: [[ISINLINE:%.*]] = icmp eq {{(i64|i32)}} [[ISNOTINLINE]], 0
|
||||
// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 10
|
||||
// CHECK: [[FLAGS:%.*]] = load i32, i32* [[FLAGS_ADDR]]
|
||||
// CHECK: [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
|
||||
// CHECK: [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
|
||||
// CHECK: [[VALUEADDRINLINE:%.*]] = bitcast [{{(24|12)}} x i8]* %0 to %swift.opaque*
|
||||
// CHECK: br i1 [[ISINLINE]], label %done, label %boxed
|
||||
//
|
||||
@@ -178,7 +182,11 @@ bb0(%0 : $*Existential):
|
||||
// CHECK: boxed:
|
||||
// CHECK: [[REFADDR:%.*]] = bitcast [{{(24|12)}} x i8]* %0 to %swift.refcounted**
|
||||
// CHECK: [[REF:%.*]] = load %swift.refcounted*, %swift.refcounted** [[REFADDR]]
|
||||
// CHECK: [[ALIGNMASK:%.*]] = and {{(i64|i32)}} [[FLAGS]], 255
|
||||
// CHECK-64:[[T0:%.*]] = zext i32 [[FLAGS]] to i64
|
||||
// CHECK-64:[[ALIGNMASK:%.*]] = and i64 [[T0]], 255
|
||||
// CHECK-32:[[ALIGNMASK:%.*]] = and i32 [[FLAGS]], 255
|
||||
// CHECK-16:[[T0:%.*]] = trunc i32 [[FLAGS]] to i16
|
||||
// CHECK-16:[[ALIGNMASK:%.*]] = and i16 [[T0]], 255
|
||||
// CHECK: [[HEADERSIZEPLUSALIGN:%.*]] = add {{(i64 16|i32 8)}}, [[ALIGNMASK]]
|
||||
// CHECK: [[NOTALIGNMASK:%.*]] = xor {{(i64|i32)}} [[ALIGNMASK]], -1
|
||||
// CHECK: [[ALIGNEDSTART:%.*]] = and {{(i64|i32)}} [[HEADERSIZEPLUSALIGN]], [[NOTALIGNMASK]]
|
||||
@@ -207,11 +215,11 @@ bb0(%0 : $*Existential):
|
||||
// CHECK: [[CAST:%.*]] = bitcast %swift.type* %1 to i8***
|
||||
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{(i64|i32)}} -1
|
||||
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
|
||||
// CHECK: [[VW_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
|
||||
// CHECK: [[VW:%.*]] = load i8*, i8** [[VW_ADDR]]
|
||||
// CHECK: [[FLAGS:%.*]] = ptrtoint i8* [[VW]] to {{(i64|i32)}}
|
||||
// CHECK: [[ISNOTINLINE:%.*]] = and {{(i64|i32)}} [[FLAGS]], 131072
|
||||
// CHECK: [[ISINLINE:%.*]] = icmp eq {{(i64|i32)}} [[ISNOTINLINE]], 0
|
||||
// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 10
|
||||
// CHECK: [[FLAGS:%.*]] = load i32, i32* [[FLAGS_ADDR]]
|
||||
// CHECK: [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
|
||||
// CHECK: [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
|
||||
// CHECK: [[VALUEADDRINLINE:%.*]] = bitcast [{{(24|12)}} x i8]* %0 to %swift.opaque*
|
||||
// CHECK: br i1 [[ISINLINE]], label %done, label %boxed
|
||||
//
|
||||
@@ -219,7 +227,11 @@ bb0(%0 : $*Existential):
|
||||
// CHECK: ret %swift.opaque* [[VALUEADDRINLINE]]
|
||||
|
||||
// CHECK: boxed:
|
||||
// CHECK: [[ALIGNMASK:%.*]] = and {{(i64|i32)}} [[FLAGS]], 255
|
||||
// CHECK-64:[[T0:%.*]] = zext i32 [[FLAGS]] to i64
|
||||
// CHECK-64:[[ALIGNMASK:%.*]] = and i64 [[T0]], 255
|
||||
// CHECK-32:[[ALIGNMASK:%.*]] = and i32 [[FLAGS]], 255
|
||||
// CHECK-16:[[T0:%.*]] = trunc i32 [[FLAGS]] to i16
|
||||
// CHECK-16:[[ALIGNMASK:%.*]] = and i16 [[T0]], 255
|
||||
// CHECK: [[OPAQUE_ADDR:%.*]] = bitcast [{{(24|12)}} x i8]* %0 to %swift.opaque*
|
||||
// CHECK: [[REFANDADDR:%.*]] = call swiftcc { %swift.refcounted*, %swift.opaque* } @swift_makeBoxUnique(%swift.opaque* [[OPAQUE_ADDR]], %swift.type* %1, {{(i64|i32)}} [[ALIGNMASK]])
|
||||
// CHECK: [[REF:%.*]] = extractvalue { %swift.refcounted*, %swift.opaque* } [[REFANDADDR]], 0
|
||||
@@ -244,11 +256,11 @@ bb0(%0 : $*Existential):
|
||||
// CHECK: [[CAST:%.*]] = bitcast %swift.type* [[METADATA]] to i8***
|
||||
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{(i64|i32)}} -1
|
||||
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
|
||||
// CHECK: [[VW_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
|
||||
// CHECK: [[VW:%.*]] = load i8*, i8** [[VW_ADDR]]
|
||||
// CHECK: [[FLAGS:%.*]] = ptrtoint i8* [[VW]] to {{(i64|i32)}}
|
||||
// CHECK: [[ISNOTINLINE:%.*]] = and {{(i64|i32)}} [[FLAGS]], 131072
|
||||
// CHECK: [[ISINLINE:%.*]] = icmp eq {{(i64|i32)}} [[ISNOTINLINE]], 0
|
||||
// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 10
|
||||
// CHECK: [[FLAGS:%.*]] = load i32, i32* [[FLAGS_ADDR]]
|
||||
// CHECK: [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
|
||||
// CHECK: [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
|
||||
// CHECK: br i1 [[ISINLINE]], label %inline, label %outline
|
||||
//
|
||||
// CHECK: inline:
|
||||
@@ -301,11 +313,11 @@ bb0(%0 : $*Existential):
|
||||
// CHECK: [[CAST:%.*]] = bitcast %swift.type* [[DEST_TYPE]] to i8***
|
||||
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{(i64|i32)}} -1
|
||||
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
|
||||
// CHECK: [[VW_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
|
||||
// CHECK: [[VW:%.*]] = load i8*, i8** [[VW_ADDR]]
|
||||
// CHECK: [[FLAGS:%.*]] = ptrtoint i8* [[VW]] to {{(i64|i32)}}
|
||||
// CHECK: [[MASKED:%.*]] = and {{(i64|i32)}} [[FLAGS]], 131072
|
||||
// CHECK: [[ISINLINE:%.*]] = icmp eq {{(i64|i32)}} [[MASKED]], 0
|
||||
// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 10
|
||||
// CHECK: [[FLAGS:%.*]] = load i32, i32* [[FLAGS_ADDR]]
|
||||
// CHECK: [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
|
||||
// CHECK: [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
|
||||
// CHECK: br i1 [[ISINLINE]], label %match-inline, label %match-outline
|
||||
//
|
||||
// CHECK: match-inline:
|
||||
@@ -339,19 +351,19 @@ bb0(%0 : $*Existential):
|
||||
// CHECK: [[CAST:%.*]] = bitcast %swift.type* [[DEST_TYPE]] to i8***
|
||||
// CHECK: [[DEST_VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{(i64|i32)}} -1
|
||||
// CHECK: [[DEST_VWT:%.*]] = load i8**, i8*** [[DEST_VWT_ADDR]]
|
||||
// CHECK: [[DEST_VW_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[DEST_VWT]], i32 9
|
||||
// CHECK: [[DEST_VW:%.*]] = load i8*, i8** [[DEST_VW_ADDR]]
|
||||
// CHECK: [[DEST_FLAGS:%.*]] = ptrtoint i8* [[DEST_VW]] to {{(i64|i32)}}
|
||||
// CHECK: [[DEST_ISNOTINLINE:%.*]] = and {{(i64|i32)}} [[DEST_FLAGS]], 131072
|
||||
// CHECK: [[DEST_ISINLINE:%.*]] = icmp eq {{(i64|i32)}} [[DEST_ISNOTINLINE]], 0
|
||||
// CHECK: [[DEST_VWT_CAST:%.*]] = bitcast i8** [[DEST_VWT]] to %swift.vwtable*
|
||||
// CHECK: [[DEST_FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[DEST_VWT_CAST]], i32 0, i32 10
|
||||
// CHECK: [[DEST_FLAGS:%.*]] = load i32, i32* [[DEST_FLAGS_ADDR]]
|
||||
// CHECK: [[DEST_ISNOTINLINE:%.*]] = and i32 [[DEST_FLAGS]], 131072
|
||||
// CHECK: [[DEST_ISINLINE:%.*]] = icmp eq i32 [[DEST_ISNOTINLINE]], 0
|
||||
// CHECK: [[CAST:%.*]] = bitcast %swift.type* [[SRC_TYPE]] to i8***
|
||||
// CHECK: [[SRC_VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{(i64|i32)}} -1
|
||||
// CHECK: [[SRC_VWT:%.*]] = load i8**, i8*** [[SRC_VWT_ADDR]]
|
||||
// CHECK: [[SRC_VW_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[SRC_VWT]], i32 9
|
||||
// CHECK: [[SRC_VW:%.*]] = load i8*, i8** [[SRC_VW_ADDR]]
|
||||
// CHECK: [[SRC_FLAGS:%.*]] = ptrtoint i8* [[SRC_VW]] to {{(i64|i32)}}
|
||||
// CHECK: [[SRC_ISNOTINLINE:%.*]] = and {{(i64|i32)}} [[SRC_FLAGS]], 131072
|
||||
// CHECK: [[SRC_ISINLINE:%.*]] = icmp eq {{(i64|i32)}} [[SRC_ISNOTINLINE]], 0
|
||||
// CHECK: [[SRC_VWT_CAST:%.*]] = bitcast i8** [[SRC_VWT]] to %swift.vwtable*
|
||||
// CHECK: [[SRC_FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[SRC_VWT_CAST]], i32 0, i32 10
|
||||
// CHECK: [[SRC_FLAGS:%.*]] = load i32, i32* [[SRC_FLAGS_ADDR]]
|
||||
// CHECK: [[SRC_ISNOTINLINE:%.*]] = and i32 [[SRC_FLAGS]], 131072
|
||||
// CHECK: [[SRC_ISINLINE:%.*]] = icmp eq i32 [[SRC_ISNOTINLINE]], 0
|
||||
// CHECK: br i1 [[DEST_ISINLINE]], label %dest-inline, label %dest-outline
|
||||
//
|
||||
// CHECK: dest-inline:
|
||||
|
||||
@@ -38,9 +38,9 @@ func allToInt<T>(_ x: T) -> Int {
|
||||
// CHECK: [[TYPE_ADDR:%.*]] = bitcast %swift.type* %T to i8***
|
||||
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[TYPE_ADDR]], i64 -1
|
||||
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
|
||||
// CHECK: [[SIZE_WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
|
||||
// CHECK: [[SIZE_WITNESS:%.*]] = load i8*, i8** [[SIZE_WITNESS_ADDR]]
|
||||
// CHECK: [[SIZE:%.*]] = ptrtoint i8* [[SIZE_WITNESS]]
|
||||
// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK: [[SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
|
||||
// CHECK: [[SIZE:%.*]] = load i64, i64* [[SIZE_ADDR]]
|
||||
// CHECK: [[T_ALLOCA:%.*]] = alloca i8, {{.*}} [[SIZE]], align 16
|
||||
// CHECK: [[T_TMP:%.*]] = bitcast i8* [[T_ALLOCA]] to %swift.opaque*
|
||||
// CHECK: [[TEMP:%.*]] = call %swift.opaque* {{.*}}(%swift.opaque* noalias [[T_TMP]], %swift.opaque* noalias %0, %swift.type* %T)
|
||||
|
||||
@@ -28,12 +28,11 @@ import Builtin
|
||||
// CHECK: @"$s15generic_structs13SingleDynamicVWV" = internal constant
|
||||
// CHECK-SAME: i8* bitcast (%swift.opaque* ([24 x i8]*, [24 x i8]*, %swift.type*)* @"$s15generic_structs13SingleDynamicVwCP" to i8*),
|
||||
// -- ...
|
||||
// -- placeholder for size, flags, stride
|
||||
// CHECK-SAME: i8* null, i8* inttoptr (i64 4194304 to i8*), i8* null
|
||||
// -- extra inhabitants
|
||||
// CHECK-SAME: i8* null,
|
||||
// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s15generic_structs13SingleDynamicVwxs" to i8*),
|
||||
// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s15generic_structs13SingleDynamicVwxg" to i8*)]
|
||||
// -- placeholder for size, stride, flags
|
||||
// CHECK-SAME: i64 0,
|
||||
// CHECK-SAME: i64 0,
|
||||
// CHECK-SAME: i32 4194304,
|
||||
// CHECK-SAME: i32 0 }
|
||||
|
||||
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
|
||||
// CHECK: [[SINGLEDYNAMIC_NAME:@.*]] = private constant [14 x i8] c"SingleDynamic\00"
|
||||
|
||||
@@ -18,9 +18,9 @@ func dup<T>(_ x: T) -> (T, T) { var x = x; return (x,x) }
|
||||
// CHECK: [[TYPE_ADDR:%.*]] = bitcast %swift.type* %T to i8***
|
||||
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[TYPE_ADDR]], i64 -1
|
||||
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
|
||||
// CHECK: [[SIZE_WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
|
||||
// CHECK: [[SIZE_WITNESS:%.*]] = load i8*, i8** [[SIZE_WITNESS_ADDR]]
|
||||
// CHECK: [[SIZE:%.*]] = ptrtoint i8* [[SIZE_WITNESS]]
|
||||
// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK: [[SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
|
||||
// CHECK: [[SIZE:%.*]] = load i64, i64* [[SIZE_ADDR]]
|
||||
// CHECK: [[X_ALLOCA:%.*]] = alloca i8, {{.*}} [[SIZE]], align 16
|
||||
// CHECK: [[X_TMP:%.*]] = bitcast i8* [[X_ALLOCA]] to %swift.opaque*
|
||||
// Debug info shadow copy.
|
||||
|
||||
@@ -128,21 +128,21 @@ bb0:
|
||||
// CHECK: [[CAST:%.*]] = bitcast %swift.type* %0 to i8***
|
||||
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{.*}} -1
|
||||
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
|
||||
// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 9
|
||||
// CHECK: [[FLAGSWITNESS:%.*]] = load i8*, i8** [[FLAGS_ADDR]]
|
||||
// CHECK: [[FLAGS:%.*]] = ptrtoint i8* [[FLAGSWITNESS]] to i{{.*}}
|
||||
// CHECK: [[ISNOTINLINE:%.*]] = and {{.*}} [[FLAGS]], 131072
|
||||
// CHECK: [[ISINLINE:%.*]] = icmp eq {{.*}} [[ISNOTINLINE]], 0
|
||||
// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 10
|
||||
// CHECK: [[FLAGS:%.*]] = load i32, i32* [[FLAGS_ADDR]]
|
||||
// CHECK: [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
|
||||
// CHECK: [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
|
||||
// CHECK: br i1 [[ISINLINE]], label %done, label %outline.allocateValueInBuffer
|
||||
//
|
||||
// CHECK: outline.allocateValueInBuffer:
|
||||
// CHECK: [[CAST:%.*]] = bitcast %swift.type* %0 to i8***
|
||||
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{.*}} -1
|
||||
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
|
||||
// CHECK: [[SIZE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
|
||||
// CHECK: [[SIZEWITNESS:%.*]] = load i8*, i8** [[SIZE_ADDR]]
|
||||
// CHECK: [[SIZE:%.*]] = ptrtoint i8* [[SIZEWITNESS]]
|
||||
// CHECK: [[ALIGN:%.*]] = and {{.*}} [[FLAGS]], 255
|
||||
// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK: [[SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
|
||||
// CHECK: [[SIZE:%.*]] = load [[INT]], [[INT]]* [[SIZE_ADDR]]
|
||||
// CHECK: [[ALIGN:%.*]] = and {{.*}}, 255
|
||||
// CHECK: [[PTR:%.*]] = call noalias i8* @swift_slowAlloc({{.*}} [[SIZE]], {{.*}} [[ALIGN]])
|
||||
// CHECK: [[ADDR:%.*]] = bitcast %swift.opaque* %1 to i8**
|
||||
// CHECK: store i8* [[PTR]], i8** [[ADDR]]
|
||||
@@ -158,11 +158,11 @@ bb0:
|
||||
// CHECK: [[CAST:%.*]] = bitcast %swift.type* %0 to i8***
|
||||
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{.*}} -1
|
||||
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
|
||||
// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 9
|
||||
// CHECK: [[FLAGSWITNESS:%.*]] = load i8*, i8** [[FLAGS_ADDR]]
|
||||
// CHECK: [[FLAGS:%.*]] = ptrtoint i8* [[FLAGSWITNESS]] to i{{.*}}
|
||||
// CHECK: [[ISNOTINLINE:%.*]] = and {{.*}} [[FLAGS]], 131072
|
||||
// CHECK: [[ISINLINE:%.*]] = icmp eq {{.*}} [[ISNOTINLINE]], 0
|
||||
// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 10
|
||||
// CHECK: [[FLAGS:%.*]] = load i32, i32* [[FLAGS_ADDR]]
|
||||
// CHECK: [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
|
||||
// CHECK: [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
|
||||
// CHECK: br i1 [[ISINLINE]], label %done, label %outline.projectValueInBuffer
|
||||
//
|
||||
// CHECK: outline.projectValueInBuffer:
|
||||
|
||||
@@ -42,14 +42,14 @@ entry(%p : $*(), %i: $Builtin.Word):
|
||||
}
|
||||
|
||||
// CHECK: define{{( protected)?}} {{.*}}void @dynamic_size(%swift.opaque* noalias nocapture, i64, %swift.type* %T) {{.*}} {
|
||||
// CHECK: %3 = bitcast %swift.type* %T to i8***
|
||||
// CHECK-NEXT: %4 = getelementptr inbounds i8**, i8*** %3, i64 -1
|
||||
// CHECK-NEXT: %T.valueWitnesses = load i8**, i8*** %4, align 8
|
||||
// CHECK-NEXT: %5 = getelementptr inbounds i8*, i8** %T.valueWitnesses, i32 10
|
||||
// CHECK-NEXT: %6 = load i8*, i8** %5, align 8
|
||||
// CHECK-NEXT: %stride = ptrtoint i8* %6 to i64
|
||||
// CHECK-NEXT: %7 = mul nsw i64 %1, %stride
|
||||
// CHECK-NEXT: %8 = getelementptr inbounds i8, i8* %2, i64 %7
|
||||
// CHECK: [[T0:%.*]] = bitcast %swift.type* %T to i8***
|
||||
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8**, i8*** [[T0]], i64 -1
|
||||
// CHECK-NEXT: [[VWT:%T.valueWitnesses]] = load i8**, i8*** [[T1]], align 8
|
||||
// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK: [[STRIDE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 9
|
||||
// CHECK: [[STRIDE:%.*]] = load i64, i64* [[STRIDE_ADDR]]
|
||||
// CHECK-NEXT: [[T0:%.*]] = mul nsw i64 %1, [[STRIDE]]
|
||||
// CHECK-NEXT: getelementptr inbounds i8, i8* %2, i64 [[T0]]
|
||||
|
||||
sil @dynamic_size : $@convention(thin) <T> (@in T, Builtin.Word) -> () {
|
||||
entry(%p : $*T, %i: $Builtin.Word):
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
import Swift
|
||||
|
||||
// CHECK-64: @"$s13indirect_enum5TreeAOWV" = internal constant {{.*}} i8* inttoptr ([[WORD:i64]] 8 to i8*), i8* inttoptr (i64 2424839 to i8*), i8* inttoptr (i64 8 to i8*)
|
||||
// CHECK-32: @"$s13indirect_enum5TreeAOWV" = internal constant {{.*}} i8* inttoptr ([[WORD:i32]] 4 to i8*), i8* inttoptr (i32 2424835 to i8*), i8* inttoptr (i32 4 to i8*)
|
||||
// CHECK-64: @"$s13indirect_enum5TreeAOWV" = internal constant %swift.enum_vwtable { {{.*}}, i64 8, i64 8, i32 2162695,
|
||||
// CHECK-32: @"$s13indirect_enum5TreeAOWV" = internal constant %swift.enum_vwtable { {{.*}}, i32 4, i32 4, i32 2162691,
|
||||
|
||||
// CHECK-NOT: define{{( protected)?}} private %swift.type** @get_field_types_TreeA
|
||||
indirect enum TreeA<T> {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -gnone -emit-ir %s | %FileCheck %s
|
||||
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -gnone -emit-ir %s | %FileCheck %s -DINT=i%target-ptrsize
|
||||
|
||||
// CHECK: [[OPAQUE:%swift.opaque]] = type opaque
|
||||
// CHECK: [[TYPE:%swift.type]] = type
|
||||
@@ -22,9 +22,9 @@ bb0(%x : $*T):
|
||||
// CHECK: [[TYPE_ADDR:%.*]] = bitcast %swift.type* %T to i8***
|
||||
// CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[TYPE_ADDR]], {{(i32|i64)}} -1
|
||||
// CHECK-NEXT: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
|
||||
// CHECK-NEXT: [[SIZE_WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
|
||||
// CHECK-NEXT: [[SIZE_WITNESS:%.*]] = load i8*, i8** [[SIZE_WITNESS_ADDR]]
|
||||
// CHECK-NEXT: [[SIZE:%.*]] = ptrtoint i8* [[SIZE_WITNESS]]
|
||||
// CHECK-NEXT: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK-NEXT: [[SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
|
||||
// CHECK-NEXT: [[SIZE:%.*]] = load [[INT]], [[INT]]* [[SIZE_ADDR]]
|
||||
// CHECK-NEXT: [[Y_ALLOCA:%.*]] = alloca i8, {{.*}} [[SIZE]], align 16
|
||||
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8({{(i32|i64)}} -1, i8* [[Y_ALLOCA]])
|
||||
// CHECK-NEXT: [[Y_TMP:%.*]] = bitcast i8* [[Y_ALLOCA]] to %swift.opaque*
|
||||
@@ -61,9 +61,9 @@ bb0(%x : $*T):
|
||||
// CHECK: [[TYPE_ADDR:%.*]] = bitcast %swift.type* %T to i8***
|
||||
// CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[TYPE_ADDR]], {{(i32|i64)}} -1
|
||||
// CHECK-NEXT: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
|
||||
// CHECK-NEXT: [[SIZE_WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
|
||||
// CHECK-NEXT: [[SIZE_WITNESS:%.*]] = load i8*, i8** [[SIZE_WITNESS_ADDR]]
|
||||
// CHECK-NEXT: [[SIZE:%.*]] = ptrtoint i8* [[SIZE_WITNESS]]
|
||||
// CHECK-NEXT: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK-NEXT: [[SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
|
||||
// CHECK-NEXT: [[SIZE:%.*]] = load [[INT]], [[INT]]* [[SIZE_ADDR]]
|
||||
// CHECK-NEXT: [[Y_ALLOCA:%.*]] = alloca i8, {{.*}} [[SIZE]], align 16
|
||||
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8({{(i32|i64)}} -1, i8* [[Y_ALLOCA]])
|
||||
// CHECK-NEXT: [[Y_TMP:%.*]] = bitcast i8* [[Y_ALLOCA]] to %swift.opaque*
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
// CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
|
||||
// CHECK: [[VWT:%.*]] = load i8**,
|
||||
// Allocate 'copy'.
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
|
||||
// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]],
|
||||
// CHECK: [[SIZE:%.*]] = ptrtoint i8* [[T1]] to [[INT]]
|
||||
// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK: [[SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
|
||||
// CHECK: [[SIZE:%.*]] = load [[INT]], [[INT]]* [[SIZE_ADDR]]
|
||||
// CHECK: [[ALLOCA:%.*]] = alloca i8, [[INT]] [[SIZE]],
|
||||
// CHECK: [[COPY:%.*]] = bitcast i8* [[ALLOCA]] to [[FOO:%T4main3FooV]]*
|
||||
// Perform 'initializeWithCopy' via the VWT instead of trying to inline it.
|
||||
|
||||
@@ -20,9 +20,9 @@ import OtherModule
|
||||
// CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
|
||||
// CHECK: [[VWT:%.*]] = load i8**,
|
||||
// Allocate 'copy'.
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
|
||||
// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]],
|
||||
// CHECK: [[SIZE:%.*]] = ptrtoint i8* [[T1]] to [[INT]]
|
||||
// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK: [[SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
|
||||
// CHECK: [[SIZE:%.*]] = load [[INT]], [[INT]]* [[SIZE_ADDR]]
|
||||
// CHECK: [[ALLOCA:%.*]] = alloca i8, [[INT]] [[SIZE]],
|
||||
// CHECK: [[COPY:%.*]] = bitcast i8* [[ALLOCA]] to [[FOO:%T11OtherModule3FooV]]*
|
||||
// Perform 'initializeWithCopy' via the VWT instead of trying to inline it.
|
||||
@@ -49,9 +49,9 @@ public func copyFoo(foo: Foo) -> Foo {
|
||||
// CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
|
||||
// CHECK: [[VWT:%.*]] = load i8**,
|
||||
// Allocate 'copy'.
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
|
||||
// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]],
|
||||
// CHECK: [[SIZE:%.*]] = ptrtoint i8* [[T1]] to [[INT]]
|
||||
// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK: [[SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
|
||||
// CHECK: [[SIZE:%.*]] = load [[INT]], [[INT]]* [[SIZE_ADDR]]
|
||||
// CHECK: [[ALLOCA:%.*]] = alloca i8, [[INT]] [[SIZE]],
|
||||
// CHECK: [[COPY:%.*]] = bitcast i8* [[ALLOCA]] to [[BAR:%T11OtherModule3BarV]]*
|
||||
// Perform 'initializeWithCopy' via the VWT instead of trying to inline it.
|
||||
|
||||
@@ -233,10 +233,14 @@ sil public_external @captured_fixed_and_dependent_params : $@convention(thin) <A
|
||||
// CHECK: [[T_METADATA_BASE:%.*]] = bitcast %swift.type* %T to i8***
|
||||
// CHECK: [[T_VWTABLE_ADDR:%.*]] = getelementptr {{.*}} [[T_METADATA_BASE]], [[WORD:i[0-9]+]] -1
|
||||
// CHECK: [[T_VWTABLE:%.*]] = load {{.*}} [[T_VWTABLE_ADDR]]
|
||||
// CHECK: [[T_FLAGS_ADDR:%.*]] = getelementptr {{.*}} [[T_VWTABLE]], i32 9
|
||||
// CHECK: [[T_FLAGS_PTR:%.*]] = load {{.*}} [[T_FLAGS_ADDR]]
|
||||
// CHECK: [[T_FLAGS:%.*]] = ptrtoint {{.*}} [[T_FLAGS_PTR]] to [[WORD]]
|
||||
// CHECK: [[T_ALIGN_MASK:%.*]] = and [[WORD]] [[T_FLAGS]], 255
|
||||
// CHECK: [[T_VWTABLE_CAST:%.*]] = bitcast i8** [[T_VWTABLE]] to %swift.vwtable*
|
||||
// CHECK: [[T_FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[T_VWTABLE_CAST]], i32 0, i32 10
|
||||
// CHECK: [[T_FLAGS:%.*]] = load i32, i32* [[T_FLAGS_ADDR]]
|
||||
// CHECK-64: [[T0:%.*]] = zext i32 [[T_FLAGS]] to i64
|
||||
// CHECK-64: [[T_ALIGN_MASK:%.*]] = and i64 [[T0]], 255
|
||||
// CHECK-32: [[T_ALIGN_MASK:%.*]] = and i32 [[T_FLAGS]], 255
|
||||
// CHECK-16: [[T0:%.*]] = trunc i32 [[T_FLAGS]] to i16
|
||||
// CHECK-16: [[T_ALIGN_MASK:%.*]] = and i16 [[T0]], 255
|
||||
// CHECK: [[T_ALIGN_MASK_NOT:%.*]] = xor [[WORD]] [[T_ALIGN_MASK]], -1
|
||||
// -- 32 is 64-bit offset of 'T' field, 16 for obj header + 8 for T metadata + 8 for SwiftClass field
|
||||
// CHECK-64: [[T_UP_TO_ALIGN_1:%.*]] = add i64 32, [[T_ALIGN_MASK]]
|
||||
@@ -245,9 +249,9 @@ sil public_external @captured_fixed_and_dependent_params : $@convention(thin) <A
|
||||
// CHECK: [[T_OFFSET:%.*]] = and [[WORD]] [[T_UP_TO_ALIGN_1]], [[T_ALIGN_MASK_NOT]]
|
||||
|
||||
// -- Add the size of T to start the Int field.
|
||||
// CHECK: [[T_SIZE_ADDR:%.*]] = getelementptr {{.*}} [[T_VWTABLE]], i32 8
|
||||
// CHECK: [[T_SIZE_PTR:%.*]] = load {{.*}} [[T_SIZE_ADDR]]
|
||||
// CHECK: [[T_SIZE:%.*]] = ptrtoint {{.*}} [[T_SIZE_PTR]] to [[WORD]]
|
||||
// CHECK: [[T_VWTABLE_CAST:%.*]] = bitcast i8** [[T_VWTABLE]] to %swift.vwtable*
|
||||
// CHECK: [[T_SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[T_VWTABLE_CAST]], i32 0, i32 8
|
||||
// CHECK: [[T_SIZE:%.*]] = load [[WORD]], [[WORD]]* [[T_SIZE_ADDR]]
|
||||
// CHECK: [[T_END:%.*]] = add [[WORD]] [[T_OFFSET]], [[T_SIZE]]
|
||||
|
||||
// -- Accumulate total alignment.
|
||||
|
||||
@@ -9,9 +9,9 @@ import Swift
|
||||
// 64: %T4main14Rdar15410780_CV = type <{ %TSSSg }>
|
||||
// 64: %TSSSg = type <{ [16 x i8] }>
|
||||
|
||||
// 64: @"$s4main14Rdar15410780_AVWV" = internal constant {{.*}} (i64 257
|
||||
// 64: @"$s4main14Rdar15410780_BVWV" = internal constant {{.*}} (i64 258
|
||||
// 64: @"$s4main14Rdar15410780_CVWV" = internal constant {{.*}} (i64 16
|
||||
// 64: @"$s4main14Rdar15410780_AVWV" = internal constant {{.*}} i64 257
|
||||
// 64: @"$s4main14Rdar15410780_BVWV" = internal constant {{.*}} i64 258
|
||||
// 64: @"$s4main14Rdar15410780_CVWV" = internal constant {{.*}} i64 16
|
||||
|
||||
|
||||
// 32: %T4main14Rdar15410780_AV = type <{ i2048, %Ts4Int8V }>
|
||||
@@ -20,9 +20,9 @@ import Swift
|
||||
// 32: %T4main14Rdar15410780_CV = type <{ %TSSSg }>
|
||||
// 32: %TSSSg = type <{ [12 x i8] }>
|
||||
|
||||
// 32: @"$s4main14Rdar15410780_AVWV" = internal constant {{.*}} (i32 257
|
||||
// 32: @"$s4main14Rdar15410780_BVWV" = internal constant {{.*}} (i32 258
|
||||
// 32: @"$s4main14Rdar15410780_CVWV" = internal constant {{.*}} (i32 12
|
||||
// 32: @"$s4main14Rdar15410780_AVWV" = internal constant {{.*}} i32 257
|
||||
// 32: @"$s4main14Rdar15410780_BVWV" = internal constant {{.*}} i32 258
|
||||
// 32: @"$s4main14Rdar15410780_CVWV" = internal constant {{.*}} i32 12
|
||||
|
||||
|
||||
// <rdar://problem/15410780>
|
||||
|
||||
@@ -25,9 +25,9 @@ public func functionWithResilientTypesSize(_ s: __owned Size, f: (__owned Size)
|
||||
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR]], [[INT]] -1
|
||||
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
|
||||
|
||||
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
|
||||
// CHECK: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
|
||||
// CHECK: [[WITNESS_FOR_SIZE:%.*]] = ptrtoint i8* [[WITNESS]]
|
||||
// CHECK-NEXT: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
||||
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
|
||||
// CHECK: [[WITNESS_FOR_SIZE:%.*]] = load [[INT]], [[INT]]* [[WITNESS_ADDR]]
|
||||
// CHECK: [[ALLOCA:%.*]] = alloca i8, {{.*}} [[WITNESS_FOR_SIZE]], align 16
|
||||
// CHECK: [[STRUCT_ADDR:%.*]] = bitcast i8* [[ALLOCA]] to %swift.opaque*
|
||||
|
||||
|
||||
@@ -28,7 +28,8 @@ struct ProtAndResilStruct {
|
||||
fooImp.foo(ptr: bar)
|
||||
}
|
||||
// CHECK-LABEL: define{{.*}} @"$s26struct_with_resilient_type18ProtAndResilStructV3baryyFTc"(%T26struct_with_resilient_type18ProtAndResilStructV* noalias nocapture)
|
||||
// CHECK: %flags.alignmentMask = and i64 %flags, 255
|
||||
// CHECK: [[T0:%.*]] = zext i32 %flags to i64
|
||||
// CHECK: %flags.alignmentMask = and i64 [[T0]], 255
|
||||
// CHECK: [[XOR_ALIGN:%.*]] = xor i64 %flags.alignmentMask, -1
|
||||
// CHECK: [[INIT_OFFSET:%.*]] = add i64 16, %flags.alignmentMask
|
||||
// CHECK: [[T0:%.*]] = and i64 [[INIT_OFFSET]], [[XOR_ALIGN]]
|
||||
|
||||
@@ -48,19 +48,19 @@ struct TypeLayoutTest<T> {
|
||||
// CHECK: store i8** getelementptr inbounds (i8*, i8** @"$sBi64_WV", i32 8)
|
||||
var c: SSing
|
||||
// -- Multi-element structs use open-coded layouts
|
||||
// CHECK: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_16_8_0_pod, i32 0, i32 0)
|
||||
// CHECK: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_0_pod to i8**)
|
||||
var d: SMult
|
||||
// CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_[[REF_XI:[0-9a-f]+]]_bt, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_[[REF_XI:[0-9a-f]+]]_bt, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_[[REF_XI:[0-9a-f]+]]_bt to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_[[REF_XI:[0-9a-f]+]]_bt to i8**)
|
||||
var e: SMult2
|
||||
// CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_[[REF_XI]]_bt, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_[[REF_XI]]_bt, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_[[REF_XI]]_bt to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_[[REF_XI]]_bt to i8**)
|
||||
var f: SMult3
|
||||
// -- Single-case enum, shares layout of its field (Builtin.Int64)
|
||||
// CHECK: store i8** getelementptr inbounds (i8*, i8** @"$sBi64_WV", i32 8)
|
||||
var g: ESing
|
||||
// -- Multi-case enum, open-coded layout
|
||||
// CHECK: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_9_8_fe_pod, i32 0, i32 0)
|
||||
// CHECK: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_9_8_fe_pod to i8**)
|
||||
var h: EMult
|
||||
// -- Single-element generic struct, shares layout of its field (T)
|
||||
// CHECK: [[T_LAYOUT:%.*]] = getelementptr inbounds i8*, i8** [[T_VALUE_WITNESSES]], i32 8
|
||||
|
||||
@@ -46,19 +46,19 @@ struct TypeLayoutTest<T> {
|
||||
// CHECK: store i8** getelementptr inbounds (i8*, i8** @"$sBi64_WV", i32 8)
|
||||
var c: SSing
|
||||
// -- Multi-element structs use open-coded layouts
|
||||
// CHECK: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_16_8_0_pod, i32 0, i32 0)
|
||||
// CHECK: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_0_pod to i8**)
|
||||
var d: SMult
|
||||
// CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_7fffffff_bt, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_1000_bt, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_7fffffff_bt to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_1000_bt to i8**)
|
||||
var e: SMult2
|
||||
// CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_7fffffff_bt, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_1000_bt, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_7fffffff_bt to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_1000_bt to i8**)
|
||||
var f: SMult3
|
||||
// -- Single-case enum, shares layout of its field (Builtin.Int64)
|
||||
// CHECK: store i8** getelementptr inbounds (i8*, i8** @"$sBi64_WV", i32 8)
|
||||
var g: ESing
|
||||
// -- Multi-case enum, open-coded layout
|
||||
// CHECK: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_9_8_fe_pod, i32 0, i32 0)
|
||||
// CHECK: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_9_8_fe_pod to i8**)
|
||||
var h: EMult
|
||||
// -- Single-element generic struct, shares layout of its field (T)
|
||||
// CHECK: [[T_LAYOUT:%.*]] = getelementptr inbounds i8*, i8** [[T_VALUE_WITNESSES]], i32 8
|
||||
|
||||
@@ -11,35 +11,35 @@ struct ReferenceStorageTypeLayout<T, Native : C, Unknown : AnyObject> {
|
||||
var z: T
|
||||
|
||||
// -- Known-Swift-refcounted type
|
||||
// CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_[[REF_XI:[0-9a-f][0-9a-f][0-9a-f]+]]_pod, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_[[REF_XI:[0-9a-f][0-9a-f][0-9a-f]+]]_pod, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_[[REF_XI:[0-9a-f][0-9a-f][0-9a-f]+]]_pod to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_[[REF_XI:[0-9a-f][0-9a-f][0-9a-f]+]]_pod to i8**)
|
||||
unowned(unsafe) var cu: C
|
||||
// CHECK-native-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_[[REF_XI]]_bt, i32 0, i32 0)
|
||||
// CHECK-objc-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_1_bt, i32 0, i32 0)
|
||||
// CHECK-native-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_[[REF_XI]]_bt, i32 0, i32 0)
|
||||
// CHECK-objc-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_1_bt, i32 0, i32 0)
|
||||
// CHECK-native-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_[[REF_XI]]_bt to i8**)
|
||||
// CHECK-objc-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_1_bt to i8**)
|
||||
// CHECK-native-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_[[REF_XI]]_bt to i8**)
|
||||
// CHECK-objc-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_1_bt to i8**)
|
||||
unowned(safe) var cs: C
|
||||
// CHECK-64: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_8_0, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_4_4_0, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_0 to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_0 to i8**)
|
||||
weak var cwo: C?
|
||||
// CHECK-64: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_8_0, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_4_4_0, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_0 to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_0 to i8**)
|
||||
weak var cwi: C!
|
||||
|
||||
// -- Known-Swift-refcounted archetype
|
||||
// CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_[[REF_XI]]_pod, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_[[REF_XI]]_pod, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_[[REF_XI]]_pod to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_[[REF_XI]]_pod to i8**)
|
||||
unowned(unsafe) var nu: Native
|
||||
// CHECK-native-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_[[REF_XI]]_bt, i32 0, i32 0)
|
||||
// CHECK-objc-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_1_bt, i32 0, i32 0)
|
||||
// CHECK-native-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_[[REF_XI]]_bt, i32 0, i32 0)
|
||||
// CHECK-objc-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_1_bt, i32 0, i32 0)
|
||||
// CHECK-native-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_[[REF_XI]]_bt to i8**)
|
||||
// CHECK-objc-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_1_bt to i8**)
|
||||
// CHECK-native-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_[[REF_XI]]_bt to i8**)
|
||||
// CHECK-objc-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_1_bt to i8**)
|
||||
unowned(safe) var nc: Native
|
||||
// CHECK-64: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_8_0, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_4_4_0, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_0 to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_0 to i8**)
|
||||
weak var nwo: Native?
|
||||
// CHECK-64: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_8_0, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_4_4_0, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_0 to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_0 to i8**)
|
||||
weak var nwi: Native!
|
||||
|
||||
// -- Open-code layout for protocol types with witness tables. Note:
|
||||
@@ -47,81 +47,81 @@ struct ReferenceStorageTypeLayout<T, Native : C, Unknown : AnyObject> {
|
||||
// when ObjC interop is disabled.
|
||||
// 2) 0x7fffffff is the max extra inhabitant count, but not all types in
|
||||
// all scenarios.
|
||||
// CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_[[REF_XI]]_pod, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_[[REF_XI]]_pod, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_[[REF_XI]]_pod to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_[[REF_XI]]_pod to i8**)
|
||||
unowned(unsafe) var pu: P
|
||||
// CHECK-native-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_[[REF_XI]]_bt, i32 0, i32 0)
|
||||
// CHECK-objc-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_7fffffff, i32 0, i32 0)
|
||||
// CHECK-native-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_[[REF_XI]]_bt, i32 0, i32 0)
|
||||
// CHECK-objc-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_7fffffff, i32 0, i32 0)
|
||||
// CHECK-native-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_[[REF_XI]]_bt to i8**)
|
||||
// CHECK-objc-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_7fffffff to i8**)
|
||||
// CHECK-native-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_[[REF_XI]]_bt to i8**)
|
||||
// CHECK-objc-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_7fffffff to i8**)
|
||||
unowned(safe) var ps: P
|
||||
// CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_7fffffff, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_7fffffff, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_7fffffff to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_7fffffff to i8**)
|
||||
weak var pwo: P?
|
||||
// CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_7fffffff, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_7fffffff, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_7fffffff to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_7fffffff to i8**)
|
||||
weak var pwi: P!
|
||||
|
||||
// CHECK-native-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[REF_XI]]_bt, i32 0, i32 0)
|
||||
// CHECK-objc-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff, i32 0, i32 0)
|
||||
// CHECK-native-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_[[REF_XI]]_bt, i32 0, i32 0)
|
||||
// CHECK-objc-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff, i32 0, i32 0)
|
||||
// CHECK-native-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_[[REF_XI]]_bt to i8**)
|
||||
// CHECK-objc-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_7fffffff to i8**)
|
||||
// CHECK-native-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_[[REF_XI]]_bt to i8**)
|
||||
// CHECK-objc-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_7fffffff to i8**)
|
||||
unowned(safe) var pqs: P & Q
|
||||
// CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[REF_XI]]_pod, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_[[REF_XI]]_pod, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_[[REF_XI]]_pod to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_[[REF_XI]]_pod to i8**)
|
||||
unowned(unsafe) var pqu: P & Q
|
||||
// CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_7fffffff to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_7fffffff to i8**)
|
||||
weak var pqwo: (P & Q)?
|
||||
// CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_7fffffff to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_7fffffff to i8**)
|
||||
weak var pqwi: (P & Q)!
|
||||
|
||||
// CHECK-native-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[REF_XI]]_bt, i32 0, i32 0)
|
||||
// CHECK-objc-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff_bt, i32 0, i32 0)
|
||||
// CHECK-native-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_[[REF_XI]]_bt, i32 0, i32 0)
|
||||
// CHECK-objc-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff_bt, i32 0, i32 0)
|
||||
// CHECK-native-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_[[REF_XI]]_bt to i8**)
|
||||
// CHECK-objc-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_7fffffff_bt to i8**)
|
||||
// CHECK-native-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_[[REF_XI]]_bt to i8**)
|
||||
// CHECK-objc-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_7fffffff_bt to i8**)
|
||||
unowned(safe) var pqcs: P & Q & C
|
||||
// CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[REF_XI]]_pod, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_[[REF_XI]]_pod, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_[[REF_XI]]_pod to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_[[REF_XI]]_pod to i8**)
|
||||
unowned(unsafe) var pqcu: P & Q & C
|
||||
// CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_7fffffff to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_7fffffff to i8**)
|
||||
weak var pqcwo: (P & Q & C)?
|
||||
// CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_7fffffff to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_7fffffff to i8**)
|
||||
weak var pqcwi: (P & Q & C)!
|
||||
|
||||
// -- Unknown-refcounted existential without witness tables.
|
||||
// CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_[[REF_XI]]_pod, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_[[REF_XI]]_pod, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_[[REF_XI]]_pod to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_[[REF_XI]]_pod to i8**)
|
||||
unowned(unsafe) var aou: AnyObject
|
||||
// CHECK-native-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_[[REF_XI]]_bt, i32 0, i32 0)
|
||||
// CHECK-objc-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_1, i32 0, i32 0)
|
||||
// CHECK-native-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_[[REF_XI]]_bt, i32 0, i32 0)
|
||||
// CHECK-objc-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_1, i32 0, i32 0)
|
||||
// CHECK-native-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_[[REF_XI]]_bt to i8**)
|
||||
// CHECK-objc-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_1 to i8**)
|
||||
// CHECK-native-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_[[REF_XI]]_bt to i8**)
|
||||
// CHECK-objc-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_1 to i8**)
|
||||
unowned(safe) var aos: AnyObject
|
||||
// CHECK-64: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_8_0, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_4_4_0, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_0 to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_0 to i8**)
|
||||
weak var aowo: AnyObject?
|
||||
// CHECK-64: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_8_0, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_4_4_0, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_0 to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_0 to i8**)
|
||||
weak var aowi: AnyObject!
|
||||
|
||||
// -- Unknown-refcounted archetype
|
||||
// CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_[[REF_XI]]_pod, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_[[REF_XI]]_pod, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_[[REF_XI]]_pod to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_[[REF_XI]]_pod to i8**)
|
||||
unowned(unsafe) var uu: Unknown
|
||||
// CHECK-native-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_[[REF_XI]]_bt, i32 0, i32 0)
|
||||
// CHECK-objc-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_1, i32 0, i32 0)
|
||||
// CHECK-native-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_[[REF_XI]]_bt, i32 0, i32 0)
|
||||
// CHECK-objc-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_1, i32 0, i32 0)
|
||||
// CHECK-native-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_[[REF_XI]]_bt to i8**)
|
||||
// CHECK-objc-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_1 to i8**)
|
||||
// CHECK-native-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_[[REF_XI]]_bt to i8**)
|
||||
// CHECK-objc-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_1 to i8**)
|
||||
unowned(safe) var us: Unknown
|
||||
// CHECK-64: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_8_0, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_4_4_0, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_0 to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_0 to i8**)
|
||||
weak var uwo: Unknown?
|
||||
// CHECK-64: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_8_0, i32 0, i32 0)
|
||||
// CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_4_4_0, i32 0, i32 0)
|
||||
// CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_0 to i8**)
|
||||
// CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_0 to i8**)
|
||||
weak var uwi: Unknown!
|
||||
}
|
||||
|
||||
|
||||
@@ -28,9 +28,9 @@ public struct A {
|
||||
}
|
||||
|
||||
// size 8
|
||||
// flags 0x130007 == 1245191 (non-POD, non-inline, non-bitwise-takable)
|
||||
// stride 8
|
||||
// CHECK: @"$s4weak1AVWV" = {{.*}} i8* inttoptr (i64 8 to i8*), i8* inttoptr (i64 1245191 to i8*), i8* inttoptr (i64 8 to i8*)]
|
||||
// flags 0x130007 == 1245191 (non-POD, non-inline, non-bitwise-takable)
|
||||
// CHECK: @"$s4weak1AVWV" = {{.*}} i64 8, i64 8, i32 1245191,
|
||||
|
||||
sil @test_weak_load_store : $@convention(thin) (@inout A, Optional<C>) -> () {
|
||||
bb0(%0 : $*A, %1 : $Optional<C>):
|
||||
|
||||
@@ -16,33 +16,55 @@
|
||||
|
||||
using namespace swift;
|
||||
|
||||
static unsigned byte_getExtraInhabitantTag(const OpaqueValue *src,
|
||||
const Metadata *self) {
|
||||
uint8_t byte = *reinterpret_cast<const uint8_t*>(src);
|
||||
if (byte > 253)
|
||||
return byte - 253;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned byte_getEnumTagSinglePayload(const OpaqueValue *value,
|
||||
unsigned numEmptyCases,
|
||||
const Metadata *self) {
|
||||
return swift_getEnumTagSinglePayloadGeneric(value, numEmptyCases, self,
|
||||
byte_getExtraInhabitantTag);
|
||||
}
|
||||
|
||||
static void byte_storeExtraInhabitantTag(OpaqueValue *dest, unsigned tag,
|
||||
const Metadata *self) {
|
||||
assert(tag > 0 && tag <= 2);
|
||||
*reinterpret_cast<uint8_t*>(dest) = 253 + tag;
|
||||
}
|
||||
|
||||
static void byte_storeEnumTagSinglePayload(OpaqueValue *value,
|
||||
unsigned tag,
|
||||
unsigned numEmptyCases,
|
||||
const Metadata *self) {
|
||||
swift_storeEnumTagSinglePayloadGeneric(value, tag, numEmptyCases, self,
|
||||
byte_storeExtraInhabitantTag);
|
||||
}
|
||||
|
||||
// Just use the normal operations for copying i8.
|
||||
#define byte_initializeBufferWithCopyOfBuffer \
|
||||
VALUE_WITNESS_SYM(Bi8_).initializeBufferWithCopyOfBuffer
|
||||
#define byte_destroy VALUE_WITNESS_SYM(Bi8_).destroy
|
||||
#define byte_initializeWithCopy VALUE_WITNESS_SYM(Bi8_).initializeWithCopy
|
||||
#define byte_assignWithCopy VALUE_WITNESS_SYM(Bi8_).assignWithCopy
|
||||
#define byte_initializeWithTake VALUE_WITNESS_SYM(Bi8_).initializeWithTake
|
||||
#define byte_assignWithTake VALUE_WITNESS_SYM(Bi8_).assignWithTake
|
||||
|
||||
// Mock up a value witness table for Builtin.Int8 will 254 and 255 as extra
|
||||
// inhabitants.
|
||||
ExtraInhabitantsValueWitnessTable Int8WithExtraInhabitantValueWitness
|
||||
= {
|
||||
// ValueWitnessTable
|
||||
ValueWitnessTable{
|
||||
ValueWitnessTable Int8WithExtraInhabitantValueWitness = {
|
||||
#define WANT_ONLY_REQUIRED_VALUE_WITNESSES
|
||||
#define VALUE_WITNESS(LOWER_ID, UPPER_ID) VALUE_WITNESS_SYM(Bi8_).LOWER_ID,
|
||||
#define VALUE_WITNESS(LOWER_ID, UPPER_ID) byte_##LOWER_ID,
|
||||
#define DATA_VALUE_WITNESS(LOWER_ID, UPPER_ID, TYPE)
|
||||
#include "swift/ABI/ValueWitness.def"
|
||||
VALUE_WITNESS_SYM(Bi8_).size,
|
||||
VALUE_WITNESS_SYM(Bi8_).flags.withExtraInhabitants(true),
|
||||
VALUE_WITNESS_SYM(Bi8_).stride
|
||||
},
|
||||
// extraInhabitantFlags
|
||||
ExtraInhabitantFlags().withNumExtraInhabitants(2),
|
||||
// storeExtraInhabitant
|
||||
[](OpaqueValue *dest, int index, const Metadata *self) {
|
||||
*reinterpret_cast<uint8_t*>(dest) = 254 + index;
|
||||
},
|
||||
// getExtraInhabitantIndex
|
||||
[](const OpaqueValue *src, const Metadata *self) -> int {
|
||||
uint8_t byte = *reinterpret_cast<const uint8_t*>(src);
|
||||
if (byte >= 254)
|
||||
return byte - 254;
|
||||
return -1;
|
||||
}
|
||||
VALUE_WITNESS_SYM(Bi8_).size,
|
||||
VALUE_WITNESS_SYM(Bi8_).stride,
|
||||
VALUE_WITNESS_SYM(Bi8_).flags,
|
||||
/*extraInhabitantCount*/ 2
|
||||
};
|
||||
|
||||
FullMetadata<OpaqueMetadata> XI_TMBi8_ = {
|
||||
@@ -58,10 +80,10 @@ OpaqueValue *asOpaque(void *v) {
|
||||
}
|
||||
|
||||
int test_getEnumCaseSinglePayload(std::initializer_list<uint8_t> repr,
|
||||
const FullOpaqueMetadata &metadata,
|
||||
unsigned numEmptyCases) {
|
||||
return swift_getEnumCaseSinglePayload(asOpaque(repr.begin()),
|
||||
&metadata.base, numEmptyCases);
|
||||
const FullOpaqueMetadata &metadata,
|
||||
unsigned numEmptyCases) {
|
||||
return metadata.base.vw_getEnumTagSinglePayload(asOpaque(repr.begin()),
|
||||
numEmptyCases);
|
||||
}
|
||||
|
||||
TEST(EnumTest, getEnumCaseSinglePayload) {
|
||||
@@ -110,10 +132,9 @@ bool test_storeEnumTagSinglePayload(std::initializer_list<uint8_t> after,
|
||||
buf.resize(before.size());
|
||||
memcpy(buf.data(), before.begin(), before.size());
|
||||
|
||||
swift_storeEnumTagSinglePayload(asOpaque(buf.data()),
|
||||
&metadata.base,
|
||||
whichCase,
|
||||
numEmptyCases);
|
||||
metadata.base.vw_storeEnumTagSinglePayload(asOpaque(buf.data()),
|
||||
whichCase,
|
||||
numEmptyCases);
|
||||
|
||||
return memcmp(buf.data(), after.begin(), after.size()) == 0;
|
||||
}
|
||||
|
||||
@@ -6,14 +6,14 @@ int $sBpN;
|
||||
int $sBi32_WV;
|
||||
int $sBi64_WV;
|
||||
int $sBi8_WV;
|
||||
void swift_getEnumCaseSinglePayload(void) {}
|
||||
void swift_getGenericMetadata(void) {}
|
||||
void swift_checkMetadataState(void) {}
|
||||
void swift_slowAlloc(void) {}
|
||||
void swift_slowDealloc(void) {}
|
||||
void swift_storeEnumTagSinglePayload(void) {}
|
||||
void swift_allocateGenericValueMetadata(void) {}
|
||||
void swift_initEnumMetadataSinglePayload(void) {}
|
||||
void swift_getEnumTagSinglePayloadGeneric(void) {}
|
||||
void swift_storeEnumTagSinglePayloadGeneric(void) {}
|
||||
void swift_retain(){}
|
||||
void swift_allocBox(){}
|
||||
void swift_getWitnessTable(void) {}
|
||||
|
||||
Reference in New Issue
Block a user