Skip to content

Commit 13b5bf4

Browse files
committed
[Compatibility53] Backport Tuple Comparable Conformance
Add protocol witnesses for Comparable requirements remove unused table
1 parent fd950eb commit 13b5bf4

File tree

2 files changed

+341
-16
lines changed

2 files changed

+341
-16
lines changed

stdlib/toolchain/Compatibility53/BuiltinProtocolConformances.cpp

Lines changed: 325 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ static const ProtocolDescriptor *getEquatableDescriptor() {
3030
return descriptor;
3131
}
3232

33+
static const ProtocolDescriptor *getComparableDescriptor() {
34+
auto descriptor = SWIFT_LAZY_CONSTANT(
35+
reinterpret_cast<const ProtocolDescriptor *>(
36+
dlsym(RTLD_DEFAULT, "$sSLMp")));
37+
return descriptor;
38+
}
39+
3340
static const WitnessTable *conformsToProtocol(const Metadata *type,
3441
const ProtocolDescriptor *protocol) {
3542
using Fn = const WitnessTable *(const Metadata *, const ProtocolDescriptor *);
@@ -39,6 +46,21 @@ static const WitnessTable *conformsToProtocol(const Metadata *type,
3946
return func(type, protocol);
4047
}
4148

49+
template<unsigned int NumWitnesses>
50+
struct _WitnessTable {
51+
const ProtocolConformanceDescriptor *Conformance;
52+
const void *Witnesses[NumWitnesses];
53+
};
54+
55+
using StaticInfixWitness = SWIFT_CC(swift) bool(OpaqueValue *, OpaqueValue *,
56+
SWIFT_CONTEXT const Metadata *,
57+
const Metadata *,
58+
const WitnessTable *);
59+
60+
//===----------------------------------------------------------------------===//
61+
// Tuple Equatable Conformance
62+
//===----------------------------------------------------------------------===//
63+
4264
#define TUPLE_EQUATABLE_WT SYMBOL("_swift_tupleEquatable_wt")
4365

4466
// Define the conformance descriptor for tuple Equatable. We do this in
@@ -66,7 +88,7 @@ extern const ProtocolConformanceDescriptor _swift_tupleEquatable_conf;
6688
// dependency to libswiftCore (which is where the Equatable protocol desciptor
6789
// lives), we have to manually implant this before calling any user code.
6890
__attribute__((constructor))
69-
void _emplaceEquatableDescriptor() {
91+
void _emplaceTupleEquatableDescriptor() {
7092
auto tupleEquatableConf = const_cast<int32_t *>(
7193
reinterpret_cast<const int32_t *>(&_swift_tupleEquatable_conf));
7294
auto equatable = getEquatableDescriptor();
@@ -75,12 +97,6 @@ void _emplaceEquatableDescriptor() {
7597
*tupleEquatableConf = intptr_t(equatable) - intptr_t(tupleEquatableConf);
7698
}
7799

78-
template<unsigned int NumWitnesses>
79-
struct _WitnessTable {
80-
const ProtocolConformanceDescriptor *Conformance;
81-
const void *Witnesses[NumWitnesses];
82-
};
83-
84100
SWIFT_RUNTIME_EXPORT
85101
const _WitnessTable<1> _swift_tupleEquatable_wt = {
86102
&_swift_tupleEquatable_conf,
@@ -119,10 +135,7 @@ bool swift::_swift_tupleEquatable_equals(OpaqueValue *tuple1,
119135
// Grab the specific witness for this element type.
120136
auto equatableTable = reinterpret_cast<void * const *>(conformance);
121137
auto equalsWitness = equatableTable[WitnessTableFirstRequirementOffset];
122-
using Fn = SWIFT_CC(swift) bool(OpaqueValue *, OpaqueValue *,
123-
SWIFT_CONTEXT const Metadata *,
124-
const Metadata *, const WitnessTable *);
125-
auto equals = reinterpret_cast<Fn *>(equalsWitness);
138+
auto equals = reinterpret_cast<StaticInfixWitness *>(equalsWitness);
126139

127140
// Call the equal function.
128141
auto result = equals(value1, value2, elt.Type, elt.Type, conformance);
@@ -135,3 +148,304 @@ bool swift::_swift_tupleEquatable_equals(OpaqueValue *tuple1,
135148
// Otherwise this tuple has value equality with all elements.
136149
return true;
137150
}
151+
152+
//===----------------------------------------------------------------------===//
153+
// Tuple Comparable Conformance
154+
//===----------------------------------------------------------------------===//
155+
156+
#define TUPLE_COMPARABLE_WT SYMBOL("_swift_tupleComparable_wt")
157+
158+
// Define the conformance descriptor for tuple Comparable. We do this in
159+
// assembly to work around relative reference issues.
160+
__asm(
161+
" .section __DATA,__data\n"
162+
" .globl " TUPLE_COMPARABLE_CONF "\n"
163+
" .p2align 2\n"
164+
TUPLE_COMPARABLE_CONF ":\n"
165+
// This is an indirectable relative reference to the Comparable protocol
166+
// descriptor. However, this is 0 here because the compatibility libraries
167+
// can't have a dependency on libswiftCore (which is where Comparable lives).
168+
" .long 0\n"
169+
// 769 is the MetadataKind::Tuple
170+
" .long 769\n"
171+
// This is a direct relative reference to the witness table defined below.
172+
" .long ((" TUPLE_COMPARABLE_WT ") - (" TUPLE_COMPARABLE_CONF ")) - 8\n"
173+
// 32 are the ConformanceFlags with the type reference bit set to MetadataKind.
174+
" .long 32\n"
175+
);
176+
177+
extern const ProtocolConformanceDescriptor _swift_tupleComparable_conf;
178+
179+
// Due to the fact that the compatibility libraries can't have a hard
180+
// dependency to libswiftCore (which is where the Comparable protocol desciptor
181+
// lives), we have to manually implant this before calling any user code.
182+
__attribute__((constructor))
183+
void _emplaceTupleComparableDescriptor() {
184+
auto tupleComparableConf = const_cast<int32_t *>(
185+
reinterpret_cast<const int32_t *>(&_swift_tupleComparable_conf));
186+
auto comparable = getComparableDescriptor();
187+
188+
// This is an indirectable pointer.
189+
*tupleComparableConf = intptr_t(comparable) - intptr_t(tupleComparableConf);
190+
}
191+
192+
// The base Equatable protocol is itself a requirement, thus the requirement
193+
// count is 5 (Equatable + 4 operators) and the witness is the tuple Equatable
194+
// table.
195+
SWIFT_RUNTIME_EXPORT
196+
const _WitnessTable<5> _swift_tupleComparable_wt = {
197+
&_swift_tupleComparable_conf,
198+
{
199+
reinterpret_cast<const void *>(&_swift_tupleEquatable_wt),
200+
reinterpret_cast<void *>(_swift_tupleComparable_lessThan),
201+
reinterpret_cast<void *>(_swift_tupleComparable_lessThanOrEqual),
202+
reinterpret_cast<void *>(_swift_tupleComparable_greaterThanOrEqual),
203+
reinterpret_cast<void *>(_swift_tupleComparable_greaterThan)
204+
}
205+
};
206+
207+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
208+
bool swift::_swift_tupleComparable_lessThan(OpaqueValue *tuple1,
209+
OpaqueValue *tuple2,
210+
SWIFT_CONTEXT Metadata *swiftSelf,
211+
Metadata *Self, void *witnessTable) {
212+
auto tuple = cast<TupleTypeMetadata>(Self);
213+
214+
// Loop through all elements, and check if both tuples element is equal.
215+
for (size_t i = 0; i != tuple->NumElements; i += 1) {
216+
auto elt = tuple->getElement(i);
217+
218+
// Ensure we actually have a conformance to Comparable for this element type.
219+
auto comparable = getComparableDescriptor();
220+
auto conformance = conformsToProtocol(elt.Type, comparable);
221+
222+
// If we don't have a conformance then something somewhere messed up in
223+
// deciding that this tuple type was Comparable...??
224+
if (!conformance)
225+
swift_unreachable("Tuple comparability requires that all elements \
226+
be Comparable.");
227+
228+
// Get the respective values from both tuples.
229+
auto value1 = reinterpret_cast<OpaqueValue *>(
230+
reinterpret_cast<char *>(tuple1) + elt.Offset);
231+
auto value2 = reinterpret_cast<OpaqueValue *>(
232+
reinterpret_cast<char *>(tuple2) + elt.Offset);
233+
234+
// First, grab the equatable conformance to prepare to check if the elements
235+
// are equal. (Since this require Equatable conformance, the witness table
236+
// is right after the conformance descriptor, which is at index 0.)
237+
auto comparableTable = reinterpret_cast<void * const *>(conformance);
238+
auto equatableTable = reinterpret_cast<void * const *>(comparableTable[1]);
239+
auto equalsWitness = equatableTable[WitnessTableFirstRequirementOffset];
240+
auto equals = reinterpret_cast<StaticInfixWitness *>(equalsWitness);
241+
242+
// Call the equal function.
243+
auto isEqual = equals(value1, value2, elt.Type, elt.Type,
244+
reinterpret_cast<const WitnessTable *>(equatableTable));
245+
246+
// If these are equal, skip to the next element.
247+
if (isEqual)
248+
continue;
249+
250+
// Now that we know they are not equal, we can call their less than function
251+
// and return the result.
252+
auto lessThanWitness = comparableTable[1 + WitnessTableFirstRequirementOffset];
253+
auto lessThan = reinterpret_cast<StaticInfixWitness *>(lessThanWitness);
254+
255+
// Call the less than function.
256+
auto isLessThan = lessThan(value1, value2, elt.Type, elt.Type, conformance);
257+
258+
return isLessThan;
259+
}
260+
261+
// Otherwise these tuples are completely equal, thus they are not less than
262+
// each other.
263+
return false;
264+
}
265+
266+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
267+
bool swift::_swift_tupleComparable_lessThanOrEqual(OpaqueValue *tuple1,
268+
OpaqueValue *tuple2,
269+
SWIFT_CONTEXT Metadata *swiftSelf,
270+
Metadata *Self,
271+
void *witnessTable) {
272+
auto tuple = cast<TupleTypeMetadata>(Self);
273+
274+
// Loop through all elements, and check if both tuples element is equal.
275+
for (size_t i = 0; i != tuple->NumElements; i += 1) {
276+
auto elt = tuple->getElement(i);
277+
278+
// Ensure we actually have a conformance to Comparable for this element type.
279+
auto comparable = getComparableDescriptor();
280+
auto conformance = conformsToProtocol(elt.Type, comparable);
281+
282+
// If we don't have a conformance then something somewhere messed up in
283+
// deciding that this tuple type was Comparable...??
284+
if (!conformance)
285+
swift_unreachable("Tuple comparability requires that all elements \
286+
be Comparable.");
287+
288+
// Get the respective values from both tuples.
289+
auto value1 = reinterpret_cast<OpaqueValue *>(
290+
reinterpret_cast<char *>(tuple1) + elt.Offset);
291+
auto value2 = reinterpret_cast<OpaqueValue *>(
292+
reinterpret_cast<char *>(tuple2) + elt.Offset);
293+
294+
// First, grab the equatable conformance to prepare to check if the elements
295+
// are equal. (Since this require Equatable conformance, the witness table
296+
// is right after the conformance descriptor, which is at index 0.)
297+
auto comparableTable = reinterpret_cast<void * const *>(conformance);
298+
auto equatableTable = reinterpret_cast<void * const *>(comparableTable[1]);
299+
auto equalsWitness = equatableTable[WitnessTableFirstRequirementOffset];
300+
auto equals = reinterpret_cast<StaticInfixWitness *>(equalsWitness);
301+
302+
// Call the equal function.
303+
auto isEqual = equals(value1, value2, elt.Type, elt.Type,
304+
reinterpret_cast<const WitnessTable *>(equatableTable));
305+
306+
// If these are equal, skip to the next element.
307+
if (isEqual)
308+
continue;
309+
310+
// Now that we know they are not equal, we can call their less than or equal
311+
// function and return the result.
312+
auto lessThanOrEqualWitness =
313+
comparableTable[WitnessTableFirstRequirementOffset + 2];
314+
auto lessThanOrEqual =
315+
reinterpret_cast<StaticInfixWitness *>(lessThanOrEqualWitness);
316+
317+
// Call the less than function.
318+
auto isLessThanOrEqual = lessThanOrEqual(value1, value2, elt.Type, elt.Type,
319+
conformance);
320+
321+
return isLessThanOrEqual;
322+
}
323+
324+
// Otherwise these tuples are completely equal.
325+
return true;
326+
}
327+
328+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
329+
bool swift::_swift_tupleComparable_greaterThanOrEqual(OpaqueValue *tuple1,
330+
OpaqueValue *tuple2,
331+
SWIFT_CONTEXT Metadata *swiftSelf,
332+
Metadata *Self,
333+
void *witnessTable) {
334+
auto tuple = cast<TupleTypeMetadata>(Self);
335+
336+
// Loop through all elements, and check if both tuples element is equal.
337+
for (size_t i = 0; i != tuple->NumElements; i += 1) {
338+
auto elt = tuple->getElement(i);
339+
340+
// Ensure we actually have a conformance to Comparable for this element type.
341+
auto comparable = getComparableDescriptor();
342+
auto conformance = conformsToProtocol(elt.Type, comparable);
343+
344+
// If we don't have a conformance then something somewhere messed up in
345+
// deciding that this tuple type was Comparable...??
346+
if (!conformance)
347+
swift_unreachable("Tuple comparability requires that all elements \
348+
be Comparable.");
349+
350+
// Get the respective values from both tuples.
351+
auto value1 = reinterpret_cast<OpaqueValue *>(
352+
reinterpret_cast<char *>(tuple1) + elt.Offset);
353+
auto value2 = reinterpret_cast<OpaqueValue *>(
354+
reinterpret_cast<char *>(tuple2) + elt.Offset);
355+
356+
// First, grab the equatable conformance to prepare to check if the elements
357+
// are equal. (Since this require Equatable conformance, the witness table
358+
// is right after the conformance descriptor, which is at index 0.)
359+
auto comparableTable = reinterpret_cast<void * const *>(conformance);
360+
auto equatableTable = reinterpret_cast<void * const *>(comparableTable[1]);
361+
auto equalsWitness = equatableTable[WitnessTableFirstRequirementOffset];
362+
auto equals = reinterpret_cast<StaticInfixWitness *>(equalsWitness);
363+
364+
// Call the equal function.
365+
auto isEqual = equals(value1, value2, elt.Type, elt.Type,
366+
reinterpret_cast<const WitnessTable *>(equatableTable));
367+
368+
// If these are equal, skip to the next element.
369+
if (isEqual)
370+
continue;
371+
372+
// Now that we know they are not equal, we can call their greater than or
373+
// equal function and return the result.
374+
auto greaterThanOrEqualWitness =
375+
comparableTable[WitnessTableFirstRequirementOffset + 3];
376+
auto greaterThanOrEqual =
377+
reinterpret_cast<StaticInfixWitness *>(greaterThanOrEqualWitness);
378+
379+
// Call the greater than or equal function.
380+
auto isGreaterThanOrEqual = greaterThanOrEqual(value1, value2, elt.Type,
381+
elt.Type, conformance);
382+
383+
return isGreaterThanOrEqual;
384+
}
385+
386+
// Otherwise these tuples are completely equal.
387+
return true;
388+
}
389+
390+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
391+
bool swift::_swift_tupleComparable_greaterThan(OpaqueValue *tuple1,
392+
OpaqueValue *tuple2,
393+
SWIFT_CONTEXT Metadata *swiftSelf,
394+
Metadata *Self,
395+
void *witnessTable) {
396+
auto tuple = cast<TupleTypeMetadata>(Self);
397+
398+
// Loop through all elements, and check if both tuples element is equal.
399+
for (size_t i = 0; i != tuple->NumElements; i += 1) {
400+
auto elt = tuple->getElement(i);
401+
402+
// Ensure we actually have a conformance to Comparable for this element type.
403+
auto comparable = getComparableDescriptor();
404+
auto conformance = conformsToProtocol(elt.Type, comparable);
405+
406+
// If we don't have a conformance then something somewhere messed up in
407+
// deciding that this tuple type was Comparable...??
408+
if (!conformance)
409+
swift_unreachable("Tuple comparability requires that all elements \
410+
be Comparable.");
411+
412+
// Get the respective values from both tuples.
413+
auto value1 = reinterpret_cast<OpaqueValue *>(
414+
reinterpret_cast<char *>(tuple1) + elt.Offset);
415+
auto value2 = reinterpret_cast<OpaqueValue *>(
416+
reinterpret_cast<char *>(tuple2) + elt.Offset);
417+
418+
// First, grab the equatable conformance to prepare to check if the elements
419+
// are equal. (Since this require Equatable conformance, the witness table
420+
// is right after the conformance descriptor, which is at index 0.)
421+
auto comparableTable = reinterpret_cast<void * const *>(conformance);
422+
auto equatableTable = reinterpret_cast<void * const *>(comparableTable[1]);
423+
auto equalsWitness = equatableTable[WitnessTableFirstRequirementOffset];
424+
auto equals = reinterpret_cast<StaticInfixWitness *>(equalsWitness);
425+
426+
// Call the equal function.
427+
auto isEqual = equals(value1, value2, elt.Type, elt.Type,
428+
reinterpret_cast<const WitnessTable *>(equatableTable));
429+
430+
// If these are equal, skip to the next element.
431+
if (isEqual)
432+
continue;
433+
434+
// Now that we know they are not equal, we can call their greater than
435+
// function and return the result.
436+
auto greaterThanWitness =
437+
comparableTable[WitnessTableFirstRequirementOffset + 4];
438+
auto greaterThan =
439+
reinterpret_cast<StaticInfixWitness *>(greaterThanWitness);
440+
441+
// Call the greater than function.
442+
auto isGreaterThan = greaterThan(value1, value2, elt.Type, elt.Type,
443+
conformance);
444+
445+
return isGreaterThan;
446+
}
447+
448+
// Otherwise these tuples are completely equal, thus they are not greater than
449+
// each other.
450+
return false;
451+
}

0 commit comments

Comments
 (0)