diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h index 7fd5278f1ed53..6b9e80dc8743a 100644 --- a/llvm/include/llvm/TargetParser/Triple.h +++ b/llvm/include/llvm/TargetParser/Triple.h @@ -463,6 +463,27 @@ class Triple { const std::string &str() const { return Data; } + /// Return the triple string but only keep the first \p N components. + /// + /// The returned string will preserve the first \p N components exactly the + /// same as the original (including the leading "-" and the value, empty or + /// not). + /// + /// E.g. Triple("arm64-apple-ios").str(5) == "arm64-apple-ios" + /// E.g. Triple("arm64-apple-ios--").str(5) == "arm64-apple-ios--" + /// E.g. Triple("arm64-apple-ios--").str(4) == "arm64-apple-ios-" + /// E.g. Triple("arm64-apple-ios--").str(3) == "arm64-apple-ios" + /// E.g. Triple("arm64-apple-ios--").str(2) == "arm64-apple" + /// E.g. Triple("arm64-apple-ios--").str(1) == "arm64" + /// E.g. Triple("arm64-apple-ios--").str(0) == "" + /// + /// This method does not normalize any triple strings. Clients that need to + /// handle the non-canonical triples that users often specify should use the + /// normalize method. + /// + /// \returns the (shorterned) triple string. + StringRef str(size_t N) const; + const std::string &getTriple() const { return Data; } /// Whether the triple is empty / default constructed. diff --git a/llvm/lib/TargetParser/Triple.cpp b/llvm/lib/TargetParser/Triple.cpp index 6a559ff023caa..0fdb62c473e73 100644 --- a/llvm/lib/TargetParser/Triple.cpp +++ b/llvm/lib/TargetParser/Triple.cpp @@ -2107,6 +2107,30 @@ std::string Triple::merge(const Triple &Other) const { return Other.str(); } +StringRef Triple::str(size_t N) const { + // If empty, return empty + if (N == 0 || Data == "") + return ""; + + // If keeping all components, return a full clone + if (N >= 5) + return Data; + + // Find the N-th separator (which is after the N'th component) + size_t p = StringRef::npos; + for (uint32_t i = 0; i < N; ++i) { + p = Data.find('-', p + 1); + if (p == StringRef::npos) + break; + } + + // Create a triple + if (p == StringRef::npos) + return Data; + else + return StringRef(Data).substr(0, p); +} + bool Triple::isMacOSXVersionLT(unsigned Major, unsigned Minor, unsigned Micro) const { assert(isMacOSX() && "Not an OS X triple!"); diff --git a/llvm/unittests/TargetParser/TripleTest.cpp b/llvm/unittests/TargetParser/TripleTest.cpp index bbd12e6d0e412..ba91e91d08a21 100644 --- a/llvm/unittests/TargetParser/TripleTest.cpp +++ b/llvm/unittests/TargetParser/TripleTest.cpp @@ -2926,4 +2926,97 @@ TEST(TripleTest, isCompatibleWith) { EXPECT_TRUE(DoTest(C.B, C.A, C.Result)); } } + +TEST(TripleTest, StrFirstN) { + // Empty triple + { + llvm::Triple triple; + ASSERT_EQ(triple.str(), ""); + ASSERT_EQ(triple.str(5), ""); + } + + // Normal triple with 3 components + { + llvm::Triple triple("arm64-apple-ios"); + ASSERT_EQ(triple.str(), "arm64-apple-ios"); + ASSERT_EQ(triple.str(5), "arm64-apple-ios"); + ASSERT_EQ(triple.str(4), "arm64-apple-ios"); + ASSERT_EQ(triple.str(3), "arm64-apple-ios"); + ASSERT_EQ(triple.str(2), "arm64-apple"); + ASSERT_EQ(triple.str(1), "arm64"); + ASSERT_EQ(triple.str(0), ""); + } + + // Normal triple with 4 components + { + llvm::Triple triple("arm64-apple-ios-simulator"); + ASSERT_EQ(triple.str(), "arm64-apple-ios-simulator"); + ASSERT_EQ(triple.str(5), "arm64-apple-ios-simulator"); + ASSERT_EQ(triple.str(4), "arm64-apple-ios-simulator"); + ASSERT_EQ(triple.str(3), "arm64-apple-ios"); + ASSERT_EQ(triple.str(2), "arm64-apple"); + ASSERT_EQ(triple.str(1), "arm64"); + ASSERT_EQ(triple.str(0), ""); + } + + // Normal triple with 5 components + { + llvm::Triple triple("arm64-apple-ios-simulator-macho"); + ASSERT_EQ(triple.str(), "arm64-apple-ios-simulator-macho"); + ASSERT_EQ(triple.str(5), "arm64-apple-ios-simulator-macho"); + ASSERT_EQ(triple.str(4), "arm64-apple-ios-simulator"); + ASSERT_EQ(triple.str(3), "arm64-apple-ios"); + ASSERT_EQ(triple.str(2), "arm64-apple"); + ASSERT_EQ(triple.str(1), "arm64"); + ASSERT_EQ(triple.str(0), ""); + } + + // Empty vendor and os + { + llvm::Triple triple("arm64---simulator-macho"); + ASSERT_EQ(triple.str(), "arm64---simulator-macho"); + ASSERT_EQ(triple.str(5), "arm64---simulator-macho"); + ASSERT_EQ(triple.str(4), "arm64---simulator"); + ASSERT_EQ(triple.str(3), "arm64--"); + ASSERT_EQ(triple.str(2), "arm64-"); + ASSERT_EQ(triple.str(1), "arm64"); + ASSERT_EQ(triple.str(0), ""); + } + + // Empty environment + { + llvm::Triple triple("arm64-apple-ios-"); + ASSERT_EQ(triple.str(), "arm64-apple-ios-"); + ASSERT_EQ(triple.str(5), "arm64-apple-ios-"); + ASSERT_EQ(triple.str(4), "arm64-apple-ios-"); + ASSERT_EQ(triple.str(3), "arm64-apple-ios"); + ASSERT_EQ(triple.str(2), "arm64-apple"); + ASSERT_EQ(triple.str(1), "arm64"); + ASSERT_EQ(triple.str(0), ""); + } + + // Empty object format + { + llvm::Triple triple("arm64-apple-ios-simulator-"); + ASSERT_EQ(triple.str(), "arm64-apple-ios-simulator-"); + ASSERT_EQ(triple.str(5), "arm64-apple-ios-simulator-"); + ASSERT_EQ(triple.str(4), "arm64-apple-ios-simulator"); + ASSERT_EQ(triple.str(3), "arm64-apple-ios"); + ASSERT_EQ(triple.str(2), "arm64-apple"); + ASSERT_EQ(triple.str(1), "arm64"); + ASSERT_EQ(triple.str(0), ""); + } + + // Empty environment, but has object format + { + llvm::Triple triple("arm64----macho"); + ASSERT_EQ(triple.str(), "arm64----macho"); + ASSERT_EQ(triple.str(5), "arm64----macho"); + ASSERT_EQ(triple.str(4), "arm64---"); + ASSERT_EQ(triple.str(3), "arm64--"); + ASSERT_EQ(triple.str(2), "arm64-"); + ASSERT_EQ(triple.str(1), "arm64"); + ASSERT_EQ(triple.str(0), ""); + } +} } // end anonymous namespace