Skip to content

Commit 2ba7090

Browse files
committed
Remove the extra-inhabitant value witness functions.
This is essentially a long-belated follow-up to Arnold's swiftlang#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.
1 parent 4d7542c commit 2ba7090

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1707
-1442
lines changed

docs/Runtime.md

-2
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,7 @@ optimization.
260260
0000000000023a40 T _swift_assignExistentialWithCopy
261261
000000000001dbf0 T _swift_copyPOD
262262
000000000001c560 T _swift_getEnumCaseMultiPayload
263-
000000000001be60 T _swift_getEnumCaseSinglePayload
264263
000000000001c400 T _swift_storeEnumTagMultiPayload
265-
000000000001bf90 T _swift_storeEnumTagSinglePayload
266264
```
267265

268266
## Type metadata lookup

include/swift/ABI/Metadata.h

+9-20
Original file line numberDiff line numberDiff line change
@@ -295,10 +295,9 @@ class TargetValueWitnessTypes {
295295
// Handle the data witnesses explicitly so we can use more specific
296296
// types for the flags enums.
297297
typedef size_t size;
298-
typedef ValueWitnessFlags flags;
299298
typedef size_t stride;
300-
typedef ExtraInhabitantFlags extraInhabitantFlags;
301-
299+
typedef ValueWitnessFlags flags;
300+
typedef uint32_t extraInhabitantCount;
302301
};
303302

304303
struct TypeLayout;
@@ -376,16 +375,9 @@ template <typename Runtime> struct TargetValueWitnessTable {
376375

377376
/// The number of extra inhabitants, that is, bit patterns that do not form
378377
/// valid values of the type, in this type's binary representation.
379-
unsigned getNumExtraInhabitants() const;
380-
381-
/// Assert that this value witness table is an extra-inhabitants
382-
/// value witness table and return it as such.
383-
///
384-
/// This has an awful name because it's supposed to be internal to
385-
/// this file. Code outside this file should use LLVM's cast/dyn_cast.
386-
/// We don't want to use those here because we need to avoid accidentally
387-
/// introducing ABI dependencies on LLVM structures.
388-
const struct ExtraInhabitantsValueWitnessTable *_asXIVWT() const;
378+
unsigned getNumExtraInhabitants() const {
379+
return extraInhabitantCount;
380+
}
389381

390382
/// Assert that this value witness table is an enum value witness table
391383
/// and return it as such.
@@ -608,13 +600,6 @@ struct TargetMetadata {
608600
#define DATA_VALUE_WITNESS(LOWER, UPPER, TYPE)
609601
#include "swift/ABI/ValueWitness.def"
610602

611-
int vw_getExtraInhabitantIndex(const OpaqueValue *value) const {
612-
return getValueWitnesses()->_asXIVWT()->getExtraInhabitantIndex(value, this);
613-
}
614-
void vw_storeExtraInhabitant(OpaqueValue *value, int index) const {
615-
getValueWitnesses()->_asXIVWT()->storeExtraInhabitant(value, index, this);
616-
}
617-
618603
unsigned vw_getEnumTag(const OpaqueValue *value) const {
619604
return getValueWitnesses()->_asEVWT()->getEnumTag(const_cast<OpaqueValue*>(value), this);
620605
}
@@ -637,6 +622,10 @@ struct TargetMetadata {
637622
return getValueWitnesses()->getStride();
638623
}
639624

625+
unsigned vw_getNumExtraInhabitants() const {
626+
return getValueWitnesses()->getNumExtraInhabitants();
627+
}
628+
640629
/// Allocate an out-of-line buffer if values of this type don't fit in the
641630
/// ValueBuffer.
642631
/// NOTE: This is not a box for copy-on-write existentials.

include/swift/ABI/MetadataValues.h

+12-51
Original file line numberDiff line numberDiff line change
@@ -121,24 +121,27 @@ class TargetValueWitnessFlags {
121121
// flags of the field types can be mostly bitwise-or'ed together to derive the
122122
// flags for the struct. (The "non-inline" and "has-extra-inhabitants" bits
123123
// still require additional fixup.)
124-
enum : int_type {
124+
enum : uint32_t {
125125
AlignmentMask = 0x000000FF,
126+
// unused 0x0000FF00,
126127
IsNonPOD = 0x00010000,
127128
IsNonInline = 0x00020000,
128-
HasExtraInhabitants = 0x00040000,
129+
// unused 0x00040000,
129130
HasSpareBits = 0x00080000,
130131
IsNonBitwiseTakable = 0x00100000,
131132
HasEnumWitnesses = 0x00200000,
132133
Incomplete = 0x00400000,
133-
134-
// Everything else is reserved.
134+
// unused 0xFF800000,
135135
};
136136

137+
static constexpr const uint32_t MaxNumExtraInhabitants = 0x7FFFFFFF;
138+
137139
private:
138-
int_type Data;
140+
uint32_t Data;
141+
142+
explicit constexpr TargetValueWitnessFlags(uint32_t data) : Data(data) {}
139143

140144
public:
141-
explicit constexpr TargetValueWitnessFlags(int_type data) : Data(data) {}
142145
constexpr TargetValueWitnessFlags() : Data(0) {}
143146

144147
/// The required alignment of the first byte of an object of this
@@ -192,22 +195,12 @@ class TargetValueWitnessFlags {
192195
return TargetValueWitnessFlags((Data & ~IsNonBitwiseTakable) |
193196
(isBT ? 0 : IsNonBitwiseTakable));
194197
}
195-
/// True if this type's binary representation has extra inhabitants, that is,
196-
/// bit patterns that do not form valid values of the type.
197-
///
198-
/// If true, then the extra inhabitant value witness table entries are
199-
/// available in this type's value witness table.
200-
bool hasExtraInhabitants() const { return Data & HasExtraInhabitants; }
198+
201199
/// True if this type's binary representation is that of an enum, and the
202200
/// enum value witness table entries are available in this type's value
203201
/// witness table.
204202
bool hasEnumWitnesses() const { return Data & HasEnumWitnesses; }
205203
constexpr TargetValueWitnessFlags
206-
withExtraInhabitants(bool hasExtraInhabitants) const {
207-
return TargetValueWitnessFlags((Data & ~HasExtraInhabitants) |
208-
(hasExtraInhabitants ? HasExtraInhabitants : 0));
209-
}
210-
constexpr TargetValueWitnessFlags
211204
withEnumWitnesses(bool hasEnumWitnesses) const {
212205
return TargetValueWitnessFlags((Data & ~HasEnumWitnesses) |
213206
(hasEnumWitnesses ? HasEnumWitnesses : 0));
@@ -223,44 +216,12 @@ class TargetValueWitnessFlags {
223216
(isIncomplete ? Incomplete : 0));
224217
}
225218

226-
constexpr int_type getOpaqueValue() const { return Data; }
227-
static constexpr TargetValueWitnessFlags getFromOpaqueValue(int_type data) {
228-
return TargetValueWitnessFlags(data);
219+
constexpr uint32_t getOpaqueValue() const {
220+
return Data;
229221
}
230222
};
231223
using ValueWitnessFlags = TargetValueWitnessFlags<size_t>;
232224

233-
/// Flags stored in a value-witness table with extra inhabitants.
234-
template <typename int_type>
235-
class TargetExtraInhabitantFlags {
236-
public:
237-
enum : int_type {
238-
NumExtraInhabitantsMask = 0x7FFFFFFFU,
239-
ExtraInhabitantFlags
240-
};
241-
int_type Data;
242-
243-
constexpr TargetExtraInhabitantFlags(int_type data) : Data(data) {}
244-
245-
public:
246-
constexpr TargetExtraInhabitantFlags() : Data(0) {}
247-
/// The number of extra inhabitants in the type's representation.
248-
int getNumExtraInhabitants() const { return Data & NumExtraInhabitantsMask; }
249-
250-
constexpr TargetExtraInhabitantFlags
251-
withNumExtraInhabitants(unsigned numExtraInhabitants) const {
252-
return TargetExtraInhabitantFlags((Data & ~NumExtraInhabitantsMask) |
253-
numExtraInhabitants);
254-
}
255-
256-
constexpr int_type getOpaqueValue() const { return Data; }
257-
static constexpr TargetExtraInhabitantFlags getFromOpaqueValue(int_type data){
258-
return TargetExtraInhabitantFlags(data);
259-
}
260-
};
261-
using ExtraInhabitantFlags =
262-
TargetExtraInhabitantFlags<size_t>;
263-
264225
/// Flags for dynamic-cast operations.
265226
enum class DynamicCastFlags : size_t {
266227
/// All flags clear.

include/swift/ABI/ValueWitness.def

+24-91
Original file line numberDiff line numberDiff line change
@@ -23,39 +23,27 @@
2323
#if defined(WANT_ALL_VALUE_WITNESSES)
2424
#undef WANT_ALL_VALUE_WITNESSES
2525
#define WANT_REQUIRED_VALUE_WITNESSES 1
26-
#define WANT_EXTRA_INHABITANT_VALUE_WITNESSES 1
2726
#define WANT_ENUM_VALUE_WITNESSES 1
2827

2928
/// WANT_ONLY_REQUIRED_VALUE_WITNESSES
3029
/// Define this to expand only the required value witnesses.
3130
#elif defined(WANT_ONLY_REQUIRED_VALUE_WITNESSES)
3231
#undef WANT_ONLY_REQUIRED_VALUE_WITNESSES
3332
#define WANT_REQUIRED_VALUE_WITNESSES 1
34-
#define WANT_EXTRA_INHABITANT_VALUE_WITNESSES 0
35-
#define WANT_ENUM_VALUE_WITNESSES 0
36-
37-
/// WANT_ONLY_EXTRA_INHABITANT_VALUE_WITNESSES
38-
/// Define this to expand only the extra-inhabitant value witnesses.
39-
#elif defined(WANT_ONLY_EXTRA_INHABITANT_VALUE_WITNESSES)
40-
#undef WANT_ONLY_EXTRA_INHABITANT_VALUE_WITNESSES
41-
#define WANT_REQUIRED_VALUE_WITNESSES 0
42-
#define WANT_EXTRA_INHABITANT_VALUE_WITNESSES 1
4333
#define WANT_ENUM_VALUE_WITNESSES 0
4434

4535
/// WANT_ONLY_ENUM_VALUE_WITNESSES
4636
/// Define this to expand only the enum value witnesses.
4737
#elif defined(WANT_ONLY_ENUM_VALUE_WITNESSES)
4838
#undef WANT_ONLY_ENUM_VALUE_WITNESSES
4939
#define WANT_REQUIRED_VALUE_WITNESSES 0
50-
#define WANT_EXTRA_INHABITANT_VALUE_WITNESSES 0
5140
#define WANT_ENUM_VALUE_WITNESSES 1
5241

5342
/// WANT_REQUIRED_VALUE_WITNESSES
54-
/// WANT_EXTRA_INHABITANT_VALUE_WITNESSES
5543
/// WANT_ENUM_VALUE_WITNESSES
5644
/// Define all of these to control exactly what to expand.
5745
#else
58-
#if !defined(WANT_REQUIRED_VALUE_WITNESSES) || !defined(WANT_EXTRA_INHABITANT_VALUE_WITNESSES) || !defined(WANT_ENUM_VALUE_WITNESSES)
46+
#if !defined(WANT_REQUIRED_VALUE_WITNESSES) || !defined(WANT_ENUM_VALUE_WITNESSES)
5947
#error failed to define a WANT macro; possible typo?
6048
#endif
6149
#endif
@@ -206,7 +194,16 @@ BEGIN_VALUE_WITNESS_RANGE(TypeLayoutWitness,
206194
BEGIN_VALUE_WITNESS_RANGE(RequiredTypeLayoutWitness,
207195
Size)
208196

209-
/// SIZE_TYPE flags;
197+
/// SIZE_TYPE stride;
198+
///
199+
/// The required size per element of an array of this type. It is at least
200+
/// one, even for zero-sized types, like the empty tuple.
201+
DATA_VALUE_WITNESS(stride,
202+
Stride,
203+
SIZE_TYPE)
204+
205+
206+
/// UINT_TYPE flags;
210207
///
211208
/// The ValueWitnessAlignmentMask bits represent the required
212209
/// alignment of the first byte of an object of this type, expressed
@@ -222,97 +219,35 @@ BEGIN_VALUE_WITNESS_RANGE(RequiredTypeLayoutWitness,
222219
/// The ValueWitnessIsNonInline bit is set if the type cannot be
223220
/// represented in a fixed-size buffer or if it is not bitwise takable.
224221
///
225-
/// The Enum_HasExtraInhabitants bit is set if the type's binary
226-
/// representation has "extra inhabitants" that do not form valid values of
227-
/// the type, and the value witness table contains the ExtraInhabitantWitness
228-
/// entries.
222+
/// The ExtraInhabitantsMask bits represent the number of "extra inhabitants"
223+
/// of the bit representation of the value that do not form valid values of
224+
/// the type.
229225
///
230226
/// The Enum_HasSpareBits bit is set if the type's binary representation
231227
/// has unused bits.
232228
///
233229
/// The HasEnumWitnesses bit is set if the type is an enum type.
234230
DATA_VALUE_WITNESS(flags,
235231
Flags,
236-
SIZE_TYPE)
232+
UINT_TYPE)
237233

238-
/// SIZE_TYPE stride;
234+
/// UINT_TYPE extraInhabitantCount;
239235
///
240-
/// The required size per element of an array of this type. It is at least
241-
/// one, even for zero-sized types, like the empty tuple.
242-
DATA_VALUE_WITNESS(stride,
243-
Stride,
244-
SIZE_TYPE)
236+
/// The number of extra inhabitants in the type.
237+
DATA_VALUE_WITNESS(extraInhabitantCount,
238+
ExtraInhabitantCount,
239+
UINT_TYPE)
245240

246241
END_VALUE_WITNESS_RANGE(RequiredTypeLayoutWitness,
247-
Stride)
242+
ExtraInhabitantCount)
248243

249244
END_VALUE_WITNESS_RANGE(RequiredValueWitness,
250-
Stride)
251-
252-
#endif /* WANT_REQUIRED_VALUE_WITNESSES */
253-
254-
#if WANT_EXTRA_INHABITANT_VALUE_WITNESSES
255-
256-
// The following value witnesses are conditionally present based on
257-
// the Enum_HasExtraInhabitants bit of the flags.
258-
259-
/// SIZE_TYPE extraInhabitantFlags;
260-
///
261-
/// These bits are always present if the extra inhabitants witnesses are:
262-
///
263-
/// - The NumExtraInhabitantsMask bits contain the number of extra
264-
/// inhabitants of the type representation.
265-
///
266-
/// If the Enum_HasSpareBits flag is set in the value witness flags, these
267-
/// additional flags are available:
268-
///
269-
/// - The NumSpareBitsMask bits contain the number of (host-endian) contiguous
270-
/// spare bits in the type representation.
271-
/// - The SpareBitsShiftMask bits contain the (host-endian) bit offset of the
272-
/// lowest spare bit.
273-
DATA_VALUE_WITNESS(extraInhabitantFlags,
274-
ExtraInhabitantFlags,
275-
SIZE_TYPE)
276-
277-
BEGIN_VALUE_WITNESS_RANGE(ExtraInhabitantValueWitness,
278-
ExtraInhabitantFlags)
245+
ExtraInhabitantCount)
279246

280247
END_VALUE_WITNESS_RANGE(TypeLayoutWitness,
281-
ExtraInhabitantFlags)
282-
283-
/// void (*storeExtraInhabitant)(T *obj, int index, M *self);
284-
///
285-
/// Given an invalid object of this type, store the representation of an
286-
/// extra inhabitant of the type. The object will remain invalid, because
287-
/// an extra inhabitant is by definition an invalid representation of the
288-
/// type. index must be less than numExtraInhabitants.
289-
FUNCTION_VALUE_WITNESS(storeExtraInhabitant,
290-
StoreExtraInhabitant,
291-
VOID_TYPE,
292-
(MUTABLE_VALUE_TYPE, INT_TYPE, TYPE_TYPE))
293-
294-
BEGIN_VALUE_WITNESS_RANGE(ExtraInhabitantValueWitnessFunction,
295-
StoreExtraInhabitant)
296-
297-
/// int (*getExtraInhabitantIndex)(T *obj, M *self);
298-
///
299-
/// Given an invalid object of this type with an extra inhabitant
300-
/// representation, returns the index of the extra inhabitant representation.
301-
/// Returns -1 if the object is a valid value of the type. If non-negative,
302-
/// the return value is the same index that can be passed to
303-
/// storeExtraInhabitant to reproduce the representation.
304-
FUNCTION_VALUE_WITNESS(getExtraInhabitantIndex,
305-
GetExtraInhabitantIndex,
306-
INT_TYPE,
307-
(IMMUTABLE_VALUE_TYPE, TYPE_TYPE))
308-
309-
END_VALUE_WITNESS_RANGE(ExtraInhabitantValueWitnessFunction,
310-
GetExtraInhabitantIndex)
248+
ExtraInhabitantCount)
311249

312-
END_VALUE_WITNESS_RANGE(ExtraInhabitantValueWitness,
313-
GetExtraInhabitantIndex)
314-
315-
#endif /* WANT_EXTRA_INHABITANT_VALUE_WITNESSES */
250+
#endif /* WANT_REQUIRED_VALUE_WITNESSES */
316251

317252
#if WANT_ENUM_VALUE_WITNESSES
318253

@@ -372,9 +307,7 @@ END_VALUE_WITNESS_RANGE(ValueWitness,
372307
#undef FUNCTION_VALUE_WITNESS
373308
#undef VALUE_WITNESS
374309
#undef ENUM_VALUE_WITNESS
375-
#undef EXTRA_INHABITANT_VALUE_WITNESS
376310
#undef NON_REQUIRED_VALUE_WITNESS
377311
#undef REQUIRED_VALUE_WITNESS
378312
#undef WANT_ENUM_VALUE_WITNESSES
379-
#undef WANT_EXTRA_INHABITANT_VALUE_WITNESSES
380313
#undef WANT_REQUIRED_VALUE_WITNESSES

0 commit comments

Comments
 (0)