Skip to content

Commit df9778e

Browse files
committed
[Compatibility53] Add compatibility library for 5.3 and backport tuple Equatable conformance
Fix some comments Unnecessary cast
1 parent e60ef84 commit df9778e

16 files changed

+669
-13
lines changed

include/swift/Frontend/BackDeploymentLibs.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
BACK_DEPLOYMENT_LIB((5, 0), all, "swiftCompatibility50")
2828
BACK_DEPLOYMENT_LIB((5, 1), all, "swiftCompatibility51")
29+
BACK_DEPLOYMENT_LIB((5, 3), all, "swiftCompatibility53")
2930
BACK_DEPLOYMENT_LIB((5, 0), executable, "swiftCompatibilityDynamicReplacements")
3031

3132
#undef BACK_DEPLOYMENT_LIB

lib/Basic/Platform.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -378,8 +378,10 @@ swift::getSwiftRuntimeCompatibilityVersionForTarget(
378378
} else if (Minor <= 15) {
379379
if (Micro <= 3) {
380380
return llvm::VersionTuple(5, 1);
381-
} else {
381+
} else if (Micro <= 4) {
382382
return llvm::VersionTuple(5, 2);
383+
} else {
384+
return llvm::VersionTuple(5, 3);
383385
}
384386
}
385387
} else if (Major == 11) {
@@ -399,8 +401,10 @@ swift::getSwiftRuntimeCompatibilityVersionForTarget(
399401
} else if (Major <= 13) {
400402
if (Minor <= 3) {
401403
return llvm::VersionTuple(5, 1);
402-
} else {
404+
} else if (Minor <= 4) {
403405
return llvm::VersionTuple(5, 2);
406+
} else {
407+
return llvm::VersionTuple(5, 3);
404408
}
405409
}
406410
} else if (Triple.isWatchOS()) {
@@ -410,8 +414,10 @@ swift::getSwiftRuntimeCompatibilityVersionForTarget(
410414
} else if (Major <= 6) {
411415
if (Minor <= 1) {
412416
return llvm::VersionTuple(5, 1);
413-
} else {
417+
} else if (Minor <= 2) {
414418
return llvm::VersionTuple(5, 2);
419+
} else {
420+
return llvm::VersionTuple(5, 3);
415421
}
416422
}
417423
}

lib/Driver/DarwinToolChains.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -378,19 +378,18 @@ toolchains::Darwin::addArgsToLinkStdlib(ArgStringList &Arguments,
378378
// have an older Swift runtime.
379379
SmallString<128> SharedResourceDirPath;
380380
getResourceDirPath(SharedResourceDirPath, context.Args, /*Shared=*/true);
381-
Optional<llvm::VersionTuple> runtimeCompatibilityVersion;
381+
Optional<llvm::VersionTuple> runtimeCompatibilityVersion
382+
= llvm::VersionTuple();
382383

383384
if (context.Args.hasArg(options::OPT_runtime_compatibility_version)) {
384385
auto value = context.Args.getLastArgValue(
385386
options::OPT_runtime_compatibility_version);
386-
if (value.equals("5.0")) {
387-
runtimeCompatibilityVersion = llvm::VersionTuple(5, 0);
388-
} else if (value.equals("5.1")) {
389-
runtimeCompatibilityVersion = llvm::VersionTuple(5, 1);
390-
} else if (value.equals("none")) {
391-
runtimeCompatibilityVersion = None;
392-
} else {
393-
// TODO: diagnose unknown runtime compatibility version?
387+
if (runtimeCompatibilityVersion->tryParse(value)) {
388+
if (value.equals("none")) {
389+
runtimeCompatibilityVersion = None;
390+
} else {
391+
// TODO: diagnose unknown runtime compatibility version?
392+
}
394393
}
395394
} else if (job.getKind() == LinkKind::Executable) {
396395
runtimeCompatibilityVersion

lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,6 +1598,8 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
15981598
runtimeCompatibilityVersion = llvm::VersionTuple(5, 0);
15991599
} else if (version.equals("5.1")) {
16001600
runtimeCompatibilityVersion = llvm::VersionTuple(5, 1);
1601+
} else if (version.equals("5.3")) {
1602+
runtimeCompatibilityVersion = llvm::VersionTuple(5, 3);
16011603
} else {
16021604
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
16031605
versionArg->getAsString(Args), version);

stdlib/toolchain/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,5 @@ set(COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_WATCHOS "2.0")
5353
add_subdirectory(legacy_layouts)
5454
add_subdirectory(Compatibility50)
5555
add_subdirectory(Compatibility51)
56+
add_subdirectory(Compatibility53)
5657
add_subdirectory(CompatibilityDynamicReplacements)

stdlib/toolchain/Compatibility50/ProtocolConformance.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
//===----------------------------------------------------------------------===//
1919

2020
#include "Overrides.h"
21+
#include "../Compatibility53/Overrides.h"
2122
#include "../../public/runtime/Private.h"
2223
#include "swift/Basic/Lazy.h"
2324
#include <dlfcn.h>
@@ -94,6 +95,13 @@ swift::swift50override_conformsToProtocol(const Metadata *type,
9495
static OnceToken_t token;
9596
SWIFT_ONCE_F(token, registerAddImageCallback, nullptr);
9697

98+
// The Swift 5.4 runtime added support for builtin conformances. Call 5.3's
99+
// backported implementation to handle that here.
100+
if (auto result =
101+
swift53override_conformsToProtocol(type, protocol,
102+
original_conformsToProtocol))
103+
return result;
104+
97105
// The implementation of swift_conformsToProtocol in Swift 5.0 would return
98106
// a false negative answer when asking whether a subclass conforms using
99107
// a conformance from a superclass. Work around this by walking up the

stdlib/toolchain/Compatibility51/Overrides.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "CompatibilityOverride.h"
1818
#include "Overrides.h"
19+
#include "../Compatibility53/Overrides.h"
1920

2021
#include <dlfcn.h>
2122
#include <mach-o/dyld.h>
@@ -33,6 +34,11 @@ struct OverrideSection {
3334
OverrideSection Swift51Overrides
3435
__attribute__((used, section("__DATA,__swift51_hooks"))) = {
3536
.version = 0,
37+
// We use the same hook for conformsToProtocol as we do for a 5.3
38+
// runtime, so reference the override from the Compatibility53 library.
39+
// If we're back deploying to Swift 5.1, we also have to support 5.3, so
40+
// the Compatibility53 library is always linked when the 51 library is.
41+
.conformsToProtocol = swift53override_conformsToProtocol,
3642
.conformsToSwiftProtocol = swift51override_conformsToSwiftProtocol,
3743
};
3844

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
//===--- BuiltinProtocolConformances.cpp ----------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Definitions of some builtin protocol witnesses.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "Overrides.h"
18+
#include "swift/Basic/Lazy.h"
19+
#include "swift/Runtime/BuiltinProtocolConformances.h"
20+
#include "swift/Runtime/Casting.h"
21+
#include <dlfcn.h>
22+
#include <mach-o/dyld.h>
23+
24+
using namespace swift;
25+
26+
static const ProtocolDescriptor *getEquatableDescriptor() {
27+
auto descriptor = SWIFT_LAZY_CONSTANT(
28+
reinterpret_cast<const ProtocolDescriptor *>(
29+
dlsym(RTLD_DEFAULT, "$sSQMp")));
30+
return descriptor;
31+
}
32+
33+
static const WitnessTable *conformsToProtocol(const Metadata *type,
34+
const ProtocolDescriptor *protocol) {
35+
using Fn = const WitnessTable *(const Metadata *, const ProtocolDescriptor *);
36+
auto func = SWIFT_LAZY_CONSTANT(
37+
reinterpret_cast<Fn *>(
38+
dlsym(RTLD_DEFAULT, "swift_conformsToProtocol")));
39+
return func(type, protocol);
40+
}
41+
42+
#define TUPLE_EQUATABLE_WT SYMBOL("_swift_tupleEquatable_wt")
43+
44+
// Define the conformance descriptor for tuple Equatable. We do this in
45+
// assembly to work around relative reference issues.
46+
__asm(
47+
" .section __DATA,__data\n"
48+
" .globl " TUPLE_EQUATABLE_CONF "\n"
49+
" .p2align 2\n"
50+
TUPLE_EQUATABLE_CONF ":\n"
51+
// This is an indirectable relative reference to the Equatable protocol
52+
// descriptor. However, this is 0 here because the compatibility libraries
53+
// can't have a dependency on libswiftCore (which is where Equatable lives).
54+
" .long 0\n"
55+
// 769 is the MetadataKind::Tuple
56+
" .long 769\n"
57+
// This is a direct relative reference to the witness table defined below.
58+
" .long ((" TUPLE_EQUATABLE_WT ") - (" TUPLE_EQUATABLE_CONF ")) - 8\n"
59+
// 32 are the ConformanceFlags with the type reference bit set to MetadataKind.
60+
" .long 32\n"
61+
);
62+
63+
extern const ProtocolConformanceDescriptor _swift_tupleEquatable_conf;
64+
65+
// Due to the fact that the compatibility libraries can't have a hard
66+
// dependency to libswiftCore (which is where the Equatable protocol desciptor
67+
// lives), we have to manually implant this before calling any user code.
68+
__attribute__((constructor))
69+
void _emplaceEquatableDescriptor() {
70+
auto tupleEquatableConf = const_cast<int32_t *>(
71+
reinterpret_cast<const int32_t *>(&_swift_tupleEquatable_conf));
72+
auto equatable = getEquatableDescriptor();
73+
74+
// This is an indirectable pointer.
75+
*tupleEquatableConf = intptr_t(equatable) - intptr_t(tupleEquatableConf);
76+
}
77+
78+
template<unsigned int NumWitnesses>
79+
struct _WitnessTable {
80+
const ProtocolConformanceDescriptor *Conformance;
81+
const void *Witnesses[NumWitnesses];
82+
};
83+
84+
SWIFT_RUNTIME_EXPORT
85+
const _WitnessTable<1> _swift_tupleEquatable_wt = {
86+
&_swift_tupleEquatable_conf,
87+
{
88+
reinterpret_cast<void *>(_swift_tupleEquatable_equals)
89+
}
90+
};
91+
92+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
93+
bool swift::_swift_tupleEquatable_equals(OpaqueValue *tuple1,
94+
OpaqueValue *tuple2,
95+
SWIFT_CONTEXT Metadata *swiftSelf,
96+
Metadata *Self, void *witnessTable) {
97+
auto tuple = cast<TupleTypeMetadata>(Self);
98+
99+
// Loop through all elements, and check if both tuples element is equal.
100+
for (size_t i = 0; i != tuple->NumElements; i += 1) {
101+
auto elt = tuple->getElement(i);
102+
103+
// Ensure we actually have a conformance to Equatable for this element type.
104+
auto equatable = getEquatableDescriptor();
105+
auto conformance = conformsToProtocol(elt.Type, equatable);
106+
107+
// If we don't have a conformance then something somewhere messed up in
108+
// deciding that this tuple type was Equatable...??
109+
if (!conformance)
110+
swift_unreachable("Tuple equality requires that all elements be \
111+
Equatable.");
112+
113+
// Get the respective values from both tuples.
114+
auto value1 = reinterpret_cast<OpaqueValue *>(
115+
reinterpret_cast<char *>(tuple1) + elt.Offset);
116+
auto value2 = reinterpret_cast<OpaqueValue *>(
117+
reinterpret_cast<char *>(tuple2) + elt.Offset);
118+
119+
// Grab the specific witness for this element type.
120+
auto equatableTable = reinterpret_cast<void * const *>(conformance);
121+
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);
126+
127+
// Call the equal function.
128+
auto result = equals(value1, value2, elt.Type, elt.Type, conformance);
129+
130+
// If the values aren't equal, this tuple isn't equal. :)
131+
if (!result)
132+
return false;
133+
}
134+
135+
// Otherwise this tuple has value equality with all elements.
136+
return true;
137+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
set(library_name "swiftCompatibility53")
2+
3+
add_swift_target_library("${library_name}" STATIC
4+
BuiltinProtocolConformances.cpp
5+
Overrides.cpp
6+
ProtocolConformance.cpp
7+
8+
TARGET_SDKS ${SWIFT_APPLE_PLATFORMS}
9+
10+
C_COMPILE_FLAGS ${CXX_COMPILE_FLAGS}
11+
LINK_FLAGS ${CXX_LINK_FLAGS}
12+
SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS}
13+
DEPLOYMENT_VERSION_OSX ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_OSX}
14+
DEPLOYMENT_VERSION_IOS ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_IOS}
15+
DEPLOYMENT_VERSION_TVOS ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_TVOS}
16+
DEPLOYMENT_VERSION_WATCHOS ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_WATCHOS}
17+
18+
INSTALL_IN_COMPONENT compiler
19+
INSTALL_WITH_SHARED)
20+
21+
22+
# FIXME: We need a more flexible mechanism to add lipo targets generated by
23+
# add_swift_target_library to the ALL target. Until then this hack is necessary
24+
# to ensure these libraries build.
25+
foreach(sdk ${SWIFT_SDKS})
26+
set(target_name "${library_name}-${SWIFT_SDK_${sdk}_LIB_SUBDIR}")
27+
if(NOT TARGET "${target_name}")
28+
continue()
29+
endif()
30+
31+
set_target_properties("${target_name}"
32+
PROPERTIES
33+
EXCLUDE_FROM_ALL FALSE)
34+
endforeach()

0 commit comments

Comments
 (0)