From 94c70dbcd4743e0bbe846a5f31386be1c340051f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Mon, 13 Jan 2025 00:08:12 +0200 Subject: [PATCH] [Triple] Ignore the vendor field for MinGW, wrt LTO/IR compatibility For MinGW environments, the regular C/C++ toolchains usually use "w64" for the vendor field in triples, while Rust toolchains usually use "pc" in the vendor field. The differences in the vendor field have no bearing on whether the IR is compatible on this platform. (This probably goes for most other OSes as well, but limiting the scope of the change to the specific case.) Add a unit test for the isCompatibleWith, including some existing test cases found in existing tests. --- llvm/lib/TargetParser/Triple.cpp | 21 +++++++++--- llvm/unittests/TargetParser/TripleTest.cpp | 38 ++++++++++++++++++++++ 2 files changed, 54 insertions(+), 5 deletions(-) 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