diff --git a/llvm/lib/TargetParser/Triple.cpp b/llvm/lib/TargetParser/Triple.cpp index 4c1de09e91f21c2..855889ac05620d3 100644 --- a/llvm/lib/TargetParser/Triple.cpp +++ b/llvm/lib/TargetParser/Triple.cpp @@ -2024,6 +2024,10 @@ bool Triple::isLittleEndian() const { } bool Triple::isCompatibleWith(const Triple &Other) const { + // On MinGW, C code is usually built with a "w64" vendor, while Rust + // often uses a "pc" vendor. + bool IgnoreVendor = isWindowsGNUEnvironment(); + // ARM and Thumb triples are compatible, if subarch, vendor and OS match. if ((getArch() == Triple::thumb && Other.getArch() == Triple::arm) || (getArch() == Triple::arm && Other.getArch() == Triple::thumb) || @@ -2034,17 +2038,24 @@ bool Triple::isCompatibleWith(const Triple &Other) const { getVendor() == Other.getVendor() && getOS() == Other.getOS(); else return getSubArch() == Other.getSubArch() && - getVendor() == Other.getVendor() && getOS() == Other.getOS() && + (getVendor() == Other.getVendor() || IgnoreVendor) && + getOS() == Other.getOS() && getEnvironment() == Other.getEnvironment() && getObjectFormat() == Other.getObjectFormat(); } - // If vendor is apple, ignore the version number. + // If vendor is apple, ignore the version number (the environment field) + // and the object format. if (getVendor() == Triple::Apple) return getArch() == Other.getArch() && getSubArch() == Other.getSubArch() && - getVendor() == Other.getVendor() && getOS() == Other.getOS(); - - return *this == Other; + (getVendor() == Other.getVendor() || IgnoreVendor) && + getOS() == Other.getOS(); + + return getArch() == Other.getArch() && getSubArch() == Other.getSubArch() && + (getVendor() == Other.getVendor() || IgnoreVendor) && + getOS() == Other.getOS() && + getEnvironment() == Other.getEnvironment() && + getObjectFormat() == Other.getObjectFormat(); } std::string Triple::merge(const Triple &Other) const { diff --git a/llvm/unittests/TargetParser/TripleTest.cpp b/llvm/unittests/TargetParser/TripleTest.cpp index 7fb7625f8c2d10a..3217014aa69af71 100644 --- a/llvm/unittests/TargetParser/TripleTest.cpp +++ b/llvm/unittests/TargetParser/TripleTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/TargetParser/Triple.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/VersionTuple.h" #include "gtest/gtest.h" @@ -2737,4 +2738,41 @@ TEST(TripleTest, DXILNormaizeWithVersion) { EXPECT_EQ("dxilv1.0-pc-shadermodel5.0-compute", Triple::normalize("dxil-shadermodel5.0-pc-compute")); } + +TEST(TripleTest, isCompatibleWith) { + struct { + const char *A; + const char *B; + bool Result; + } Cases[] = { + {"armv7-linux-gnueabihf", "thumbv7-linux-gnueabihf", true}, + {"armv4-none-unknown-eabi", "thumbv6-unknown-linux-gnueabihf", false}, + {"x86_64-apple-macosx10.9.0", "x86_64-apple-macosx10.10.0", true}, + {"x86_64-apple-macosx10.9.0", "i386-apple-macosx10.9.0", false}, + {"x86_64-apple-macosx10.9.0", "x86_64h-apple-macosx10.9.0", true}, + {"x86_64-unknown-linux-gnu", "x86_64-unknown-linux-gnu", true}, + {"x86_64-unknown-linux-gnu", "i386-unknown-linux-gnu", false}, + {"x86_64-unknown-linux-gnu", "x86_64h-unknown-linux-gnu", true}, + {"x86_64-pc-windows-gnu", "x86_64-pc-windows-msvc", false}, + {"x86_64-pc-windows-msvc", "x86_64-pc-windows-msvc-elf", false}, + {"i686-w64-windows-gnu", "i386-w64-windows-gnu", true}, + {"x86_64-w64-windows-gnu", "x86_64-pc-windows-gnu", true}, + {"armv7-w64-windows-gnu", "thumbv7-pc-windows-gnu", true}, + }; + + auto DoTest = [](const char *A, const char *B, + bool Result) -> testing::AssertionResult { + if (Triple(A).isCompatibleWith(Triple(B)) != Result) { + return testing::AssertionFailure() + << llvm::formatv("Triple {0} and {1} were expected to be {2}", A, + B, Result ? "compatible" : "incompatible"); + } + return testing::AssertionSuccess(); + }; + for (const auto &C : Cases) { + EXPECT_TRUE(DoTest(C.A, C.B, C.Result)); + // Test that the comparison is commutative. + EXPECT_TRUE(DoTest(C.B, C.A, C.Result)); + } +} } // end anonymous namespace