-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Name platform-specific module files using a normalized target triple #22842
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
652cdfc
70ba0aa
0df6ff4
c1cc51d
3f58a79
6476098
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,8 @@ | |
//===----------------------------------------------------------------------===// | ||
|
||
#include "swift/Basic/Platform.h" | ||
#include "llvm/ADT/StringExtras.h" | ||
#include "llvm/ADT/StringSwitch.h" | ||
#include "llvm/ADT/Triple.h" | ||
|
||
using namespace swift; | ||
|
@@ -188,3 +190,126 @@ StringRef swift::getMajorArchitectureName(const llvm::Triple &Triple) { | |
return Triple.getArchName(); | ||
} | ||
} | ||
|
||
// The code below is responsible for normalizing target triples into the form | ||
// used to name target-specific swiftmodule, swiftinterface, and swiftdoc files. | ||
// If two triples have incompatible ABIs or can be distinguished by Swift #if | ||
// declarations, they should normalize to different values. | ||
// | ||
// This code is only really used on platforms with toolchains supporting fat | ||
// binaries (a single binary containing multiple architectures). On these | ||
// platforms, this code should strip unnecessary details from target triple | ||
// components and map synonyms to canonical values. Even values which don't need | ||
// any special canonicalization should be documented here as comments. | ||
// | ||
// (Fallback behavior does not belong here; it should be implemented in code | ||
// that calls this function, most importantly in SerializedModuleLoaderBase.) | ||
// | ||
// If you're trying to refer to this code to understand how Swift behaves and | ||
// you're unfamiliar with LLVM internals, here's a cheat sheet for reading it: | ||
// | ||
// * llvm::Triple is the type for a target name. It's a bit of a misnomer, | ||
// because it can contain three or four values: arch-vendor-os[-environment]. | ||
// | ||
// * In .Cases and .Case, the last argument is the value the arguments before it | ||
// map to. That is, `.Cases("bar", "baz", "foo")` will return "foo" if it sees | ||
// "bar" or "baz". | ||
// | ||
// * llvm::Optional is similar to a Swift Optional: it either contains a value | ||
// or represents the absence of one. `None` is equivalent to `nil`; leading | ||
// `*` is equivalent to trailing `!`; conversion to `bool` is a not-`None` | ||
// check. | ||
|
||
static StringRef | ||
getArchForAppleTargetSpecificModuleTriple(const llvm::Triple &triple) { | ||
auto tripleArchName = triple.getArchName(); | ||
|
||
return llvm::StringSwitch<StringRef>(tripleArchName) | ||
.Cases("arm64", "aarch64", "arm64") | ||
.Cases("x86_64", "amd64", "x86_64") | ||
.Cases("i386", "i486", "i586", "i686", "i786", "i886", "i986", | ||
"i386") | ||
.Cases("unknown", "", "unknown") | ||
// These values are also supported, but are handled by the default case below: | ||
// .Case ("armv7s", "armv7s") | ||
// .Case ("armv7k", "armv7k") | ||
// .Case ("armv7", "armv7") | ||
.Default(tripleArchName); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This catch-all would cover many of the cases above; I mention them separately because I expect that build system engineers and others who don't often work in the Swift compiler may need to read this code, and I want to be extra-clear about what's supported. (A few other parts of this implementation, like the use of arguably unnecessary helper functions with wordy names, are also influenced by that.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be good to add a comment about why you mention them separately so that future maintainers will know why this is the case and how to add support for additional architectures. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you want to not have a default, and conditionalize calling this based on the OS instead? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This already is effectively conditionalized on (I suppose one answer is that we ought to centralize our many disparate notions of OS, architecture, and environment into a single source of truth, but that's not something I want to tackle in this PR.) |
||
} | ||
|
||
static StringRef | ||
getVendorForAppleTargetSpecificModuleTriple(const llvm::Triple &triple) { | ||
// We unconditionally normalize to "apple" because it's relatively common for | ||
// build systems to omit the vendor name or use an incorrect one like | ||
// "unknown". Most parts of the compiler ignore the vendor, so you might not | ||
// notice such a mistake. | ||
// | ||
// Please don't depend on this behavior--specify 'apple' if you're building | ||
// for an Apple platform. | ||
|
||
assert(triple.isOSDarwin() && | ||
"shouldn't normalize non-Darwin triple to 'apple'"); | ||
|
||
return "apple"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Although we previously considered not normalizing the vendor, I discovered later that the Swift benchmark suite currently builds with an empty vendor field. I plan to fix that, but it made me rethink that decision. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There should probably be a comment explaining why you're doing this. |
||
} | ||
|
||
static StringRef | ||
getOSForAppleTargetSpecificModuleTriple(const llvm::Triple &triple) { | ||
auto tripleOSName = triple.getOSName(); | ||
|
||
// Truncate the OS name before the first digit. "Digit" here is ASCII '0'-'9'. | ||
auto tripleOSNameNoVersion = tripleOSName.take_until(llvm::isDigit); | ||
|
||
return llvm::StringSwitch<StringRef>(tripleOSNameNoVersion) | ||
.Cases("macos", "macosx", "darwin", "macos") | ||
.Cases("unknown", "", "unknown") | ||
// These values are also supported, but are handled by the default case below: | ||
// .Case ("ios", "ios") | ||
// .Case ("tvos", "tvos") | ||
// .Case ("watchos", "watchos") | ||
.Default(tripleOSNameNoVersion); | ||
} | ||
|
||
static Optional<StringRef> | ||
getEnvironmentForAppleTargetSpecificModuleTriple(const llvm::Triple &triple) { | ||
auto tripleEnvironment = triple.getEnvironmentName(); | ||
|
||
// If the environment is empty, infer a "simulator" environment based on the | ||
// OS and architecture combination. This feature is deprecated and exists for | ||
// backwards compatibility only; build systems should pass the "simulator" | ||
// environment explicitly if they know they're building for a simulator. | ||
if (tripleEnvironment == "" && swift::tripleIsAnySimulator(triple)) | ||
return StringRef("simulator"); | ||
|
||
return llvm::StringSwitch<Optional<StringRef>>(tripleEnvironment) | ||
.Cases("unknown", "", None) | ||
// These values are also supported, but are handled by the default case below: | ||
// .Case ("simulator", StringRef("simulator")) | ||
.Default(tripleEnvironment); | ||
} | ||
|
||
llvm::Triple swift::getTargetSpecificModuleTriple(const llvm::Triple &triple) { | ||
// isOSDarwin() returns true for all Darwin-style OSes, including macOS, iOS, | ||
// etc. | ||
if (triple.isOSDarwin()) { | ||
StringRef newArch = getArchForAppleTargetSpecificModuleTriple(triple); | ||
|
||
StringRef newVendor = getVendorForAppleTargetSpecificModuleTriple(triple); | ||
|
||
StringRef newOS = getOSForAppleTargetSpecificModuleTriple(triple); | ||
|
||
Optional<StringRef> newEnvironment = | ||
getEnvironmentForAppleTargetSpecificModuleTriple(triple); | ||
|
||
if (!newEnvironment) | ||
// Generate an arch-vendor-os triple. | ||
return llvm::Triple(newArch, newVendor, newOS); | ||
|
||
// Generate an arch-vendor-os-environment triple. | ||
return llvm::Triple(newArch, newVendor, newOS, *newEnvironment); | ||
} | ||
|
||
// Other platforms get no normalization. | ||
return triple; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: alphabet