June 22, 2020·6 min read·engineeringswiftcompilerplatformsllvm

Swift starts upstreaming the Apple Silicon Mac target

The first upstream patch handles macOS version numbering, showing how a hardware transition reaches shared compiler infrastructure before Swift-specific support.

The first patch linked from Swift's Apple Silicon announcement concerns operating-system version numbers. That is a useful indication of how much a new target involves besides selecting a processor backend. In the June 22 announcement, Ted Kremenek says support will begin upstream in LLVM, followed by changes in the Swift compiler, package manager and standard library. Clang and LLDB are part of the same open-source support effort.

Apple's transition announcement sets the product context. It plans the first Apple Silicon Mac for the end of the year and describes a transition of about two years. Universal 2 binaries will support both Intel and Apple Silicon Macs, while Rosetta 2 will translate existing applications. Those are announced plans and development facilities. They do not mean every corresponding upstream Swift change has already landed.

I find Swift's design more useful when its implementation details have a clear explanation. This announcement gives one by linking the first infrastructure patch. A target is a contract among tools about architecture and operating-system behavior. The source change makes part of that contract inspectable before the rest of the work arrives.

A target has an operating system as well as an architecture

LLVM review D82337 adds support for macOS 11 numbering to the target-triple utilities. A triple identifies a compilation target through fields such as architecture, vendor and operating system, with an optional environment field. Despite the historical name, the representation can contain more than three fields.

The patch's tests include both an Intel target and an arm64 target using macOS version numbers. The architecture and operating-system fields answer different questions. An architecture identifies the instruction family, while the operating-system identity and version describe another part of the compilation environment. Changing one field does not justify silently inferring all the others.

For a compiler project, these values are operational data. A version comparison can determine whether a target is older than an operating-system release. Parsing the target incorrectly can therefore influence a later decision even when the compiler recognizes the processor. A new product name or version boundary has to pass through shared parsing and comparison utilities consistently.

This explains the ordering in Swift's announcement. LLVM supplies infrastructure used by other tools. Establishing the target interpretation there gives subsequent Clang and Swift work a common representation to use. The public patch is small enough to study directly, but its callers can be spread across the toolchain.

Darwin and macOS have different numbering schemes

The patch preserves support for both Darwin-style and macOS-style operating-system identifiers. Those identifiers do not use the same major version numbers. Existing code maps Darwin versions to macOS versions, so teaching a parser to accept the number eleven is only one part of the job.

Before the change, the Darwin conversion described in the diff produces a macOS major version of ten and derives its minor version from the Darwin major. The revised implementation keeps that behavior through Darwin 19. For Darwin 20 and above, it uses a macOS major version beginning at eleven and clears the minor and micro components in that conversion.

The unit test gives a concrete boundary case. A target with darwin20 must produce macOS version 11.0.0 through getMacOSXVersion. Existing tests for earlier versions remain around the new cases. This matters because a compatibility fix has to preserve interpretation of older targets while adding the new numbering scheme.

The same patch removes the assumption that a directly specified macOS target must have major version ten. A macOS major below ten remains invalid in that path, while eleven is accepted. The arm64 test uses a version with nonzero minor and micro components, checking that direct macOS parsing retains them.

Those details expose two different operations. Parsing an explicit macOS version reads the version supplied in the triple. Translating a Darwin version interprets another numbering scheme. Treating both as ordinary string extraction would miss why the patch needs separate cases.

Comparisons must translate the requested version too

A comparison function also changes. isMacOSXVersionLT compares a target against a requested macOS version while accounting for the target's operating-system identifier. If the target already uses the macOS identifier, the code compares versions directly. If it uses Darwin, the requested macOS version must be converted into the Darwin numbering scheme first.

For a requested macOS major of ten, the older minor-based mapping remains. For eleven or later, the new arithmetic maps the requested major to the corresponding Darwin major. The implementation asserts that this second case has an expected macOS major, rather than allowing arbitrary earlier numbers through the new calculation.

The tests compare a macOS 11 target against 11.1 and 10.15. They also compare a Darwin 20 target against 11.1, 11.0 and 10.15. These cases verify the relative ordering across the transition, including equality at the boundary. Equality is especially relevant because a less-than check should return false when the target meets the requested version exactly.

The practical implication extends beyond this helper. Any caller relying on the helper should receive the same answer whether its target is expressed through the macOS or Darwin form. A shared utility is useful only if the alternate spellings preserve that meaning. The tests specify the relationship that later compiler work can depend on.

Canonicalization is a separate operation

D82337 also introduces getCanonicalVersionForOS. Its macOS-specific case maps version 10.16 to 11.0. For other inputs, the function returns the supplied version. The review summary says upcoming Clang and Swift patches will use this utility.

This operation is narrower than parsing. The tests still allow a triple explicitly containing macOS 10.16 to parse with those components. Canonicalization is an additional step a caller can request. Keeping it separate avoids making every use of a version string silently rewrite its input.

That separation is useful in compatibility code because accepting a representation and deciding how to normalize it are different responsibilities. A parser may need to retain what a producer supplied. A comparison or availability operation may need a canonical version. Putting the conversion in a named function makes the decision visible to the code using it.

The tests also check that macOS 10.15.4 remains unchanged and that Darwin 20 is not rewritten by the macOS-specific canonicalization rule. This prevents the new utility from treating every occurrence of the number twenty or every Apple operating system as part of the same conversion.

I prefer this explicit treatment to platform assumptions scattered through unrelated components. It gives a reviewer a bounded rule to examine. It also gives tool authors a single operation to call when they need the normalization, instead of reproducing the mapping independently.

Development hardware serves a different purpose

Apple also announces a Universal App Quick Start Program. It includes beta development software and limited use of a Developer Transition Kit based on the A12Z Bionic system on a chip. The kit provides hardware for building and testing during the transition, and Apple requires its return at the end of the program. It is development equipment within a program, rather than the retail Mac promised for later in the year.

That distinction helps separate an application developer's immediate options from the open-source project's sequence of changes. Hardware access allows development work against the announced environment. Upstream target support makes the relevant compiler behavior available in the shared projects. Neither statement by itself establishes the completion of the other work.

Upstream support remains staged work

The committed LLVM change records the version-numbering implementation. Its tests are useful examples of the target strings the infrastructure must understand, including x86_64-apple-macos11.0 and arm64-apple-macosx11.5.8. The latter is test input. It is not a product-release forecast or a deployment requirement for applications.

That distinction matters when reading compiler tests during an announced platform transition. Tests often use arbitrary values to exercise parsing and comparison. A supported string in a unit test establishes behavior for that utility, without establishing that an operating-system release with that exact version exists.

Swift's own announcement keeps the remaining work specific. Changes will follow in the compiler and surrounding projects after the LLVM work. That leaves package tooling and the standard library as explicit parts of the port, alongside debugging. For contributors following the transition today, the linked review provides an initial piece of shared infrastructure to inspect, with further project changes still to come.