diff --git a/llvm/include/llvm/ADT/Triple.h b/llvm/include/llvm/ADT/Triple.h --- a/llvm/include/llvm/ADT/Triple.h +++ b/llvm/include/llvm/ADT/Triple.h @@ -19,6 +19,8 @@ namespace llvm { +class VersionTuple; + /// Triple - Helper class for working with autoconf configuration names. For /// historical reasons, we also call these 'triples' (they used to contain /// exactly three fields). @@ -438,17 +440,7 @@ /// compatibility, which handles supporting skewed version numbering schemes /// used by the "darwin" triples. bool isMacOSXVersionLT(unsigned Major, unsigned Minor = 0, - unsigned Micro = 0) const { - assert(isMacOSX() && "Not an OS X triple!"); - - // If this is OS X, expect a sane version number. - if (getOS() == Triple::MacOSX) - return isOSVersionLT(Major, Minor, Micro); - - // Otherwise, compare to the "Darwin" number. - assert(Major == 10 && "Unexpected major version"); - return isOSVersionLT(Minor + 4, Micro, 0); - } + unsigned Micro = 0) const; /// isMacOSX - Is this a Mac OS X triple. For legacy reasons, we support both /// "darwin" and "osx" as OS X triples. @@ -902,6 +894,10 @@ static ArchType getArchTypeForLLVMName(StringRef Str); /// @} + + /// Returns a canonicalized OS version number for the specified OS. + static VersionTuple getCanonicalVersionForOS(OSType OSKind, + const VersionTuple &Version); }; } // End llvm namespace diff --git a/llvm/lib/Support/Triple.cpp b/llvm/lib/Support/Triple.cpp --- a/llvm/lib/Support/Triple.cpp +++ b/llvm/lib/Support/Triple.cpp @@ -15,6 +15,7 @@ #include "llvm/Support/Host.h" #include "llvm/Support/SwapByteOrder.h" #include "llvm/Support/TargetParser.h" +#include "llvm/Support/VersionTuple.h" #include #include using namespace llvm; @@ -1086,17 +1087,23 @@ // Darwin version numbers are skewed from OS X versions. if (Major < 4) return false; - Micro = 0; - Minor = Major - 4; - Major = 10; + if (Major <= 19) { + Micro = 0; + Minor = Major - 4; + Major = 10; + } else { + Micro = 0; + Minor = 0; + // darwin20+ corresponds to macOS 11+. + Major = 11 + Major - 20; + } break; case MacOSX: // Default to 10.4. if (Major == 0) { Major = 10; Minor = 4; - } - if (Major != 10) + } else if (Major < 10) return false; break; case IOS: @@ -1600,6 +1607,23 @@ return Other.str(); } +bool Triple::isMacOSXVersionLT(unsigned Major, unsigned Minor, + unsigned Micro) const { + assert(isMacOSX() && "Not an OS X triple!"); + + // If this is OS X, expect a sane version number. + if (getOS() == Triple::MacOSX) + return isOSVersionLT(Major, Minor, Micro); + + // Otherwise, compare to the "Darwin" number. + if (Major == 10) { + return isOSVersionLT(Minor + 4, Micro, 0); + } else { + assert(Major >= 11 && "Unexpected major version"); + return isOSVersionLT(Major - 11 + 20, Minor, Micro); + } +} + StringRef Triple::getARMCPUForArch(StringRef MArch) const { if (MArch.empty()) MArch = getArchName(); @@ -1662,3 +1686,16 @@ llvm_unreachable("invalid arch name"); } + +VersionTuple Triple::getCanonicalVersionForOS(OSType OSKind, + const VersionTuple &Version) { + switch (OSKind) { + case MacOSX: + // macOS 10.16 is canonicalized to macOS 11. + if (Version == VersionTuple(10, 16)) + return VersionTuple(11, 0); + LLVM_FALLTHROUGH; + default: + return Version; + } +} diff --git a/llvm/unittests/ADT/TripleTest.cpp b/llvm/unittests/ADT/TripleTest.cpp --- a/llvm/unittests/ADT/TripleTest.cpp +++ b/llvm/unittests/ADT/TripleTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/Triple.h" +#include "llvm/Support/VersionTuple.h" #include "gtest/gtest.h" using namespace llvm; @@ -1222,6 +1223,44 @@ EXPECT_EQ((unsigned)0, Minor); EXPECT_EQ((unsigned)0, Micro); + T = Triple("x86_64-apple-macos11.0"); + EXPECT_TRUE(T.isMacOSX()); + EXPECT_FALSE(T.isiOS()); + EXPECT_FALSE(T.isArch16Bit()); + EXPECT_FALSE(T.isArch32Bit()); + EXPECT_TRUE(T.isArch64Bit()); + T.getMacOSXVersion(Major, Minor, Micro); + EXPECT_EQ((unsigned)11, Major); + EXPECT_EQ((unsigned)0, Minor); + EXPECT_EQ((unsigned)0, Micro); + + T = Triple("arm64-apple-macosx11.5.8"); + EXPECT_TRUE(T.isMacOSX()); + EXPECT_FALSE(T.isiOS()); + EXPECT_FALSE(T.isArch16Bit()); + EXPECT_FALSE(T.isArch32Bit()); + EXPECT_TRUE(T.isArch64Bit()); + T.getMacOSXVersion(Major, Minor, Micro); + EXPECT_EQ((unsigned)11, Major); + EXPECT_EQ((unsigned)5, Minor); + EXPECT_EQ((unsigned)8, Micro); + + // 10.16 forms a valid triple, even though it's not + // a version of a macOS. + T = Triple("x86_64-apple-macos10.16"); + EXPECT_TRUE(T.isMacOSX()); + T.getMacOSXVersion(Major, Minor, Micro); + EXPECT_EQ((unsigned)10, Major); + EXPECT_EQ((unsigned)16, Minor); + EXPECT_EQ((unsigned)0, Micro); + + T = Triple("x86_64-apple-darwin20"); + EXPECT_TRUE(T.isMacOSX()); + T.getMacOSXVersion(Major, Minor, Micro); + EXPECT_EQ((unsigned)11, Major); + EXPECT_EQ((unsigned)0, Minor); + EXPECT_EQ((unsigned)0, Micro); + T = Triple("armv7-apple-ios"); EXPECT_FALSE(T.isMacOSX()); EXPECT_TRUE(T.isiOS()); @@ -1273,6 +1312,27 @@ EXPECT_FALSE(T.isSimulatorEnvironment()); } +TEST(TripleTest, isMacOSVersionLT) { + Triple T = Triple("x86_64-apple-macos11"); + EXPECT_TRUE(T.isMacOSXVersionLT(11, 1, 0)); + EXPECT_FALSE(T.isMacOSXVersionLT(10, 15, 0)); + + T = Triple("x86_64-apple-darwin20"); + EXPECT_TRUE(T.isMacOSXVersionLT(11, 1, 0)); + EXPECT_FALSE(T.isMacOSXVersionLT(11, 0, 0)); + EXPECT_FALSE(T.isMacOSXVersionLT(10, 15, 0)); +} + +TEST(TripleTest, CanonicalizeOSVersion) { + EXPECT_EQ(VersionTuple(10, 15, 4), + Triple::getCanonicalVersionForOS(Triple::MacOSX, + VersionTuple(10, 15, 4))); + EXPECT_EQ(VersionTuple(11, 0), Triple::getCanonicalVersionForOS( + Triple::MacOSX, VersionTuple(10, 16))); + EXPECT_EQ(VersionTuple(20), + Triple::getCanonicalVersionForOS(Triple::Darwin, VersionTuple(20))); +} + TEST(TripleTest, FileFormat) { EXPECT_EQ(Triple::ELF, Triple("i686-unknown-linux-gnu").getObjectFormat()); EXPECT_EQ(Triple::ELF, Triple("i686-unknown-freebsd").getObjectFormat());