Index: include/llvm/ADT/Triple.h =================================================================== --- include/llvm/ADT/Triple.h +++ include/llvm/ADT/Triple.h @@ -181,7 +181,9 @@ UnknownEnvironment, GNU, + GNUABI32, GNUABI64, + GNUABIN32, GNUEABI, GNUEABIHF, GNUX32, @@ -189,6 +191,10 @@ EABI, EABIHF, Android, + Android64, + ABI32, + ABIN32, + ABI64, Musl, MuslEABI, MuslEABIHF, @@ -490,7 +496,8 @@ bool isGNUEnvironment() const { EnvironmentType Env = getEnvironment(); - return Env == Triple::GNU || Env == Triple::GNUABI64 || + return Env == Triple::GNU || Env == Triple::GNUABI32 || + Env == Triple::GNUABIN32 || Env == Triple::GNUABI64 || Env == Triple::GNUEABI || Env == Triple::GNUEABIHF || Env == Triple::GNUX32; } @@ -598,7 +605,10 @@ } /// Tests whether the target is Android - bool isAndroid() const { return getEnvironment() == Triple::Android; } + bool isAndroid() const { + EnvironmentType Env = getEnvironment(); + return Env == Triple::Android || Env == Triple::Android64; + } bool isAndroidVersionLT(unsigned Major) const { assert(isAndroid() && "Not an Android triple!"); @@ -710,6 +720,22 @@ /// architecture if no such variant can be found. llvm::Triple getLittleEndianArchVariant() const; + /// Form a triple with variant of the current architecture and the specified + /// ABI. + /// + /// Generally speaking the target specifies the ABI in the triple if the ABI + /// has a large effect on the output (e.g. ELFCLASS32/ELFCLASS64, REL/RELA, + /// different sets of relocs) and/or is not link-compatible with other ABI's. + /// If the ABI is fairly small in effect (e.g. calling convention) then and/or + /// is link-compatible with other ABI's then MCTargetOptions is preferable. + /// + /// \param ABI The ABI name to use. If it is an empty string then the triple's + /// default is used. + /// \returns A new triple with the requested ABI or an unknown architecture + /// if no such variant can be found. Also, an ABI name that is + /// consistent with the triple. + std::pair getABIVariant(StringRef ABI) const; + /// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting. /// /// \param Arch the architecture name (e.g., "armv7s"). If it is an empty Index: lib/Support/Triple.cpp =================================================================== --- lib/Support/Triple.cpp +++ lib/Support/Triple.cpp @@ -208,7 +208,12 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) { switch (Kind) { case UnknownEnvironment: return "unknown"; + case ABI32: return "abi32"; + case ABIN32: return "abin32"; + case ABI64: return "abi64"; case GNU: return "gnu"; + case GNUABI32: return "gnuabi32"; + case GNUABIN32: return "gnuabin32"; case GNUABI64: return "gnuabi64"; case GNUEABIHF: return "gnueabihf"; case GNUEABI: return "gnueabi"; @@ -217,6 +222,7 @@ case EABI: return "eabi"; case EABIHF: return "eabihf"; case Android: return "android"; + case Android64: return "android64"; case Musl: return "musl"; case MuslEABI: return "musleabi"; case MuslEABIHF: return "musleabihf"; @@ -484,14 +490,20 @@ static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) { return StringSwitch(EnvironmentName) + .StartsWith("abi32", Triple::ABI32) + .StartsWith("abin32", Triple::ABIN32) + .StartsWith("abi64", Triple::ABI64) .StartsWith("eabihf", Triple::EABIHF) .StartsWith("eabi", Triple::EABI) + .StartsWith("gnuabi32", Triple::GNUABI32) + .StartsWith("gnuabin32", Triple::GNUABIN32) .StartsWith("gnuabi64", Triple::GNUABI64) .StartsWith("gnueabihf", Triple::GNUEABIHF) .StartsWith("gnueabi", Triple::GNUEABI) .StartsWith("gnux32", Triple::GNUX32) .StartsWith("code16", Triple::CODE16) .StartsWith("gnu", Triple::GNU) + .StartsWith("android64", Triple::Android64) .StartsWith("android", Triple::Android) .StartsWith("musleabihf", Triple::MuslEABIHF) .StartsWith("musleabi", Triple::MuslEABI) @@ -1468,6 +1480,99 @@ } } +std::pair Triple::getABIVariant(StringRef ABI) const { + Triple T(*this); + switch (getArch()) { + default: + if (ABI.empty()) + return std::make_pair(T, ABI); + T.setArch(Triple::UnknownArch); + return std::make_pair(T, ABI); + + case Triple::arm: + case Triple::armeb: + case Triple::aarch64: + case Triple::aarch64_be: + case Triple::thumb: + case Triple::thumbeb: + if (ABI.empty() || ABI == "aapcs16" || ABI == "darwinpcs" || + ABI == "ilp32" || ABI.startswith("apcs") || ABI.startswith("aapcs")) + return std::make_pair(T, ABI); + T.setArch(Triple::UnknownArch); + return std::make_pair(T, ABI); + + case Triple::ppc64: + case Triple::ppc64le: + if (ABI.empty() || ABI.startswith("elfv1") || ABI.startswith("elfv2")) + return std::make_pair(T, ABI); + T.setArch(Triple::UnknownArch); + return std::make_pair(T, ABI); + + case Triple::mips: + case Triple::mipsel: + case Triple::mips64: + case Triple::mips64el: { + if (ABI.empty()) { + if (getArch() == Triple::mips || getArch() == Triple::mipsel) + ABI = "o32"; + else + ABI = "n64"; + } + + // For MIPS the ABI name provided by a separate option supersedes + // the environment specified in a triple. Let's adjust the triple + // accordingly. + switch (T.getEnvironment()) { + default: + T.setEnvironment(Triple::UnknownEnvironment); + break; + case Triple::Android: + case Triple::Android64: + T.setEnvironment(StringSwitch(ABI) + .Case("o32", Triple::Android) + .Case("n64", Triple::Android64) + .Default(Triple::UnknownEnvironment)); + break; + case Triple::UnknownEnvironment: + case Triple::ABI32: + case Triple::ABIN32: + case Triple::ABI64: + T.setEnvironment(StringSwitch(ABI) + .Case("o32", Triple::ABI32) + .Case("n32", Triple::ABIN32) + .Case("n64", Triple::ABI64) + .Default(Triple::UnknownEnvironment)); + break; + case Triple::GNU: + case Triple::GNUABI32: + case Triple::GNUABIN32: + case Triple::GNUABI64: + T.setEnvironment(StringSwitch(ABI) + .Case("o32", Triple::GNUABI32) + .Case("n32", Triple::GNUABIN32) + .Case("n64", Triple::GNUABI64) + .Default(Triple::UnknownEnvironment)); + break; + } + + if (T.getEnvironment() == Triple::UnknownEnvironment) { + T.setArch(Triple::UnknownArch); + return std::make_pair(T, ABI); + } + + // We have to keep the Arch and Environment in sync at the moment + // due to a false correlation between mips/mipsel and O32 + // and mips64/mips64el and N64 that is required by the MIPS backend. + if (ABI == "o32") + T = T.get32BitArchVariant(); + else if (ABI == "n32" || ABI == "n64") + T = T.get64BitArchVariant(); + + return std::make_pair(T, ABI); + } + } +} + StringRef Triple::getARMCPUForArch(StringRef MArch) const { if (MArch.empty()) MArch = getArchName(); Index: lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp +++ lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp @@ -55,7 +55,19 @@ return MipsABIInfo::N32(); if (Options.getABIName().startswith("n64")) return MipsABIInfo::N64(); + assert(Options.getABIName().empty() && "Unknown ABI option for MIPS"); + if (TT.getEnvironment() == Triple::ABI32 || + TT.getEnvironment() == Triple::Android || + TT.getEnvironment() == Triple::GNUABI32) + return MipsABIInfo::O32(); + if (TT.getEnvironment() == Triple::ABIN32 || + TT.getEnvironment() == Triple::GNUABIN32) + return MipsABIInfo::N32(); + if (TT.getEnvironment() == Triple::ABI64 || + TT.getEnvironment() == Triple::Android64 || + TT.getEnvironment() == Triple::GNUABI64) + return MipsABIInfo::N64(); if (TT.getArch() == Triple::mips64 || TT.getArch() == Triple::mips64el) return MipsABIInfo::N64(); Index: test/CodeGen/Mips/compactbranches/no-beqzc-bnezc.ll =================================================================== --- test/CodeGen/Mips/compactbranches/no-beqzc-bnezc.ll +++ test/CodeGen/Mips/compactbranches/no-beqzc-bnezc.ll @@ -1,7 +1,9 @@ -; RUN: llc -march=mipsel -mcpu=mips32r6 -disable-mips-delay-filler < %s | FileCheck %s +; RUN: llc -march=mipsel -mcpu=mips32r6 -disable-mips-delay-filler < %s \ +; RUN: | FileCheck %s --check-prefixes=CHECK,O32 ; RUN: llc -march=mips -mcpu=mips32r6 -disable-mips-delay-filler < %s -filetype=obj \ ; RUN: -o - | llvm-objdump -d - | FileCheck %s -check-prefix=ENCODING -; RUN: llc -march=mipsel -mcpu=mips64r6 -disable-mips-delay-filler -target-abi=n64 < %s | FileCheck %s +; RUN: llc -march=mipsel -mcpu=mips64r6 -disable-mips-delay-filler -target-abi=n64 < %s \ +; RUN: | FileCheck %s --check-prefixes=CHECK,N64 ; RUN: llc -march=mips -mcpu=mips64r6 -disable-mips-delay-filler -target-abi=n64 < %s -filetype=obj \ ; RUN: -o - | llvm-objdump -d - | FileCheck %s -check-prefix=ENCODING @@ -103,7 +105,8 @@ define i32 @f6(i32 %a) { ; CHECK-LABEL: f6: -; CHECK: beqzc ${{[0-9]+}}, $BB +; O32: beqzc ${{[0-9]+}}, $BB +; N64: beqzc ${{[0-9]+}}, .LBB %cmp = icmp eq i32 %a, 0 br i1 %cmp, label %if.then, label %if.end @@ -117,7 +120,8 @@ define i32 @f7(i32 %a) { ; CHECK-LABEL: f7: -; CHECK: bnezc ${{[0-9]+}}, $BB +; O32: bnezc ${{[0-9]+}}, $BB +; N64: bnezc ${{[0-9]+}}, .LBB %cmp = icmp eq i32 0, %a br i1 %cmp, label %if.then, label %if.end Index: test/MC/Mips/expansion-jal-sym-pic.s =================================================================== --- test/MC/Mips/expansion-jal-sym-pic.s +++ test/MC/Mips/expansion-jal-sym-pic.s @@ -200,8 +200,8 @@ # ELF-O32-NEXT: 27 39 00 58 addiu $25, $25, 88 # ELF-O32-NEXT: R_MIPS_LO16 .text -# N32: lw $25, %got_disp($tmp0)($gp) # encoding: [0x8f,0x99,A,A] -# N32: # fixup A - offset: 0, value: %got_disp($tmp0), kind: fixup_Mips_GOT_DISP +# N32: lw $25, %got_disp(.Ltmp0)($gp) # encoding: [0x8f,0x99,A,A] +# N32: # fixup A - offset: 0, value: %got_disp(.Ltmp0), kind: fixup_Mips_GOT_DISP # ELF-N32: 8f 99 00 00 lw $25, 0($gp) # ELF-N32-NEXT: R_MIPS_GOT_DISP/R_MIPS_NONE/R_MIPS_NONE .Ltmp0 Index: tools/llc/llc.cpp =================================================================== --- tools/llc/llc.cpp +++ tools/llc/llc.cpp @@ -451,6 +451,16 @@ Options.MCOptions.PreserveAsmComments = PreserveComments; Options.MCOptions.IASSearchPaths = IncludeDirs; + // Adjust and make consistent the triple and ABIName if we can. + std::tie(TheTriple, Options.MCOptions.ABIName) = + TheTriple.getABIVariant(Options.MCOptions.ABIName); + if (TheTriple.getArch() == Triple::UnknownArch) { + errs() << argv[0] + << ": error: invalid ABI name: " << Options.MCOptions.ABIName + << "\n"; + return 1; + } + std::unique_ptr Target( TheTarget->createTargetMachine(TheTriple.getTriple(), CPUStr, FeaturesStr, Options, getRelocModel(), CMModel, OLvl)); Index: tools/llvm-mc/llvm-mc.cpp =================================================================== --- tools/llvm-mc/llvm-mc.cpp +++ tools/llvm-mc/llvm-mc.cpp @@ -469,6 +469,16 @@ // construct the Triple object. Triple TheTriple(TripleName); + // Adjust and make consistent the triple and ABIName if we can. + std::tie(TheTriple, MCOptions.ABIName) = + TheTriple.getABIVariant(MCOptions.ABIName); + if (TheTriple.getArch() == Triple::UnknownArch) { + errs() << ProgName << ": error: invalid ABI name: " << MCOptions.ABIName + << "\n"; + return 1; + } + TripleName = TheTriple.str(); + ErrorOr> BufferPtr = MemoryBuffer::getFileOrSTDIN(InputFilename); if (std::error_code EC = BufferPtr.getError()) { Index: unittests/ADT/TripleTest.cpp =================================================================== --- unittests/ADT/TripleTest.cpp +++ unittests/ADT/TripleTest.cpp @@ -284,6 +284,42 @@ EXPECT_EQ(Triple::FreeBSD, T.getOS()); EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment()); + T = Triple("mips-mti-linux-gnu"); + EXPECT_EQ(Triple::mips, T.getArch()); + EXPECT_EQ(Triple::MipsTechnologies, T.getVendor()); + EXPECT_EQ(Triple::Linux, T.getOS()); + EXPECT_EQ(Triple::GNU, T.getEnvironment()); + + T = Triple("mipsel-img-linux-gnu"); + EXPECT_EQ(Triple::mipsel, T.getArch()); + EXPECT_EQ(Triple::ImaginationTechnologies, T.getVendor()); + EXPECT_EQ(Triple::Linux, T.getOS()); + EXPECT_EQ(Triple::GNU, T.getEnvironment()); + + T = Triple("mips64-mti-linux-gnu"); + EXPECT_EQ(Triple::mips64, T.getArch()); + EXPECT_EQ(Triple::MipsTechnologies, T.getVendor()); + EXPECT_EQ(Triple::Linux, T.getOS()); + EXPECT_EQ(Triple::GNU, T.getEnvironment()); + + T = Triple("mips64el-img-linux-gnu"); + EXPECT_EQ(Triple::mips64el, T.getArch()); + EXPECT_EQ(Triple::ImaginationTechnologies, T.getVendor()); + EXPECT_EQ(Triple::Linux, T.getOS()); + EXPECT_EQ(Triple::GNU, T.getEnvironment()); + + T = Triple("mips64el-img-linux-gnuabin32"); + EXPECT_EQ(Triple::mips64el, T.getArch()); + EXPECT_EQ(Triple::ImaginationTechnologies, T.getVendor()); + EXPECT_EQ(Triple::Linux, T.getOS()); + EXPECT_EQ(Triple::GNUABIN32, T.getEnvironment()); + + T = Triple("mips64el-unknown-linux-gnuabi64"); + EXPECT_EQ(Triple::mips64el, T.getArch()); + EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); + EXPECT_EQ(Triple::Linux, T.getOS()); + EXPECT_EQ(Triple::GNUABI64, T.getEnvironment()); + T = Triple("huh"); EXPECT_EQ(Triple::UnknownArch, T.getArch()); } @@ -841,6 +877,164 @@ EXPECT_EQ(Triple::le64, T.getLittleEndianArchVariant().getArch()); } +TEST(TripleTest, ABIVariants) { + Triple T, MutatedT; + StringRef MutatedABI; + EXPECT_EQ(Triple::UnknownArch, T.getABIVariant("").first.getArch()); + EXPECT_EQ(Triple::UnknownArch, T.getABIVariant("32").first.getArch()); + + T.setArch(Triple::UnknownArch); + EXPECT_EQ(Triple::UnknownArch, T.getABIVariant("").first.getArch()); + EXPECT_EQ(Triple::UnknownArch, T.getABIVariant("32").first.getArch()); + + // Try a triple that doesn't mutate the triple in getABIVariant(). + // This should leave the triple and abi unchanged. + T = Triple("x86_64-pc-linux-gnu"); + std::tie(MutatedT, MutatedABI) = T.getABIVariant(""); + EXPECT_EQ(T, MutatedT); + EXPECT_EQ("", MutatedABI); + + // Try an unsupported ABI name. This should change the arch component of the + // triple to UnknownArch. Other parts of the result are undefined. + std::tie(MutatedT, MutatedABI) = T.getABIVariant("32"); + EXPECT_EQ(Triple::UnknownArch, MutatedT.getArch()); + + for (const auto &TripleStr : + {"mips-linux-gnu", "mipsel-linux-gnu", "mips-mti-linux-gnu", + "mipsel-img-linux-gnu", "mips64-linux-gnu", "mips64el-linux-gnu", + "mips64-mti-linux-gnu", "mips64el-img-linux-gnu"}) { + T = Triple(Triple::normalize(TripleStr)); + std::pair Default = T.getABIVariant(""); + std::pair O32 = T.getABIVariant("o32"); + std::pair N32 = T.getABIVariant("n32"); + std::pair N64 = T.getABIVariant("n64"); + + EXPECT_EQ(T.getArch(), Default.first.getArch()); + EXPECT_EQ(T.get32BitArchVariant().getArch(), O32.first.getArch()); + EXPECT_EQ(T.get64BitArchVariant().getArch(), N32.first.getArch()); + EXPECT_EQ(T.get64BitArchVariant().getArch(), N64.first.getArch()); + + EXPECT_EQ(T.getVendor(), Default.first.getVendor()); + EXPECT_EQ(T.getVendor(), O32.first.getVendor()); + EXPECT_EQ(T.getVendor(), N32.first.getVendor()); + EXPECT_EQ(T.getVendor(), N64.first.getVendor()); + + EXPECT_EQ(T.getOS(), Default.first.getOS()); + EXPECT_EQ(T.getOS(), O32.first.getOS()); + EXPECT_EQ(T.getOS(), N32.first.getOS()); + EXPECT_EQ(T.getOS(), N64.first.getOS()); + + EXPECT_EQ((T.getArch() == Triple::mips64 || T.getArch() == Triple::mips64el) + ? Triple::GNUABI64 + : Triple::GNUABI32, + Default.first.getEnvironment()); + EXPECT_EQ(Triple::GNUABI32, O32.first.getEnvironment()); + EXPECT_EQ(Triple::GNUABIN32, N32.first.getEnvironment()); + EXPECT_EQ(Triple::GNUABI64, N64.first.getEnvironment()); + + EXPECT_EQ((T.getArch() == Triple::mips64 || T.getArch() == Triple::mips64el) + ? "n64" + : "o32", + Default.second); + EXPECT_EQ("o32", O32.second); + EXPECT_EQ("n32", N32.second); + EXPECT_EQ("n64", N64.second); + + // Try an unsupported ABI name. This should change the arch component of the + // triple to UnknownArch. Other values are undefined. + std::pair Foo = T.getABIVariant("foo"); + EXPECT_EQ(Triple::UnknownArch, Foo.first.getArch()); + } + + for (const auto &TripleStr : + {"mipsel-linux-android", "mips64el-linux-android"}) { + T = Triple(Triple::normalize(TripleStr)); + std::pair Default = T.getABIVariant(""); + std::pair O32 = T.getABIVariant("o32"); + std::pair N32 = T.getABIVariant("n32"); + std::pair N64 = T.getABIVariant("n64"); + + EXPECT_EQ(T.getArch(), Default.first.getArch()); + EXPECT_EQ(T.get32BitArchVariant().getArch(), O32.first.getArch()); + EXPECT_EQ(T.get64BitArchVariant().getArch(), N64.first.getArch()); + + EXPECT_EQ(T.getVendor(), Default.first.getVendor()); + EXPECT_EQ(T.getVendor(), O32.first.getVendor()); + EXPECT_EQ(T.getVendor(), N64.first.getVendor()); + + EXPECT_EQ(T.getOS(), Default.first.getOS()); + EXPECT_EQ(T.getOS(), O32.first.getOS()); + EXPECT_EQ(T.getOS(), N64.first.getOS()); + + EXPECT_EQ((T.getArch() == Triple::mips64 || T.getArch() == Triple::mips64el) + ? Triple::Android64 + : Triple::Android, + Default.first.getEnvironment()); + EXPECT_EQ(Triple::Android, O32.first.getEnvironment()); + EXPECT_EQ(Triple::Android64, N64.first.getEnvironment()); + + EXPECT_EQ((T.getArch() == Triple::mips64 || T.getArch() == Triple::mips64el) + ? "n64" + : "o32", + Default.second); + EXPECT_EQ("o32", O32.second); + EXPECT_EQ("n64", N64.second); + + // Try an unsupported ABI name. This should change the arch component of the + // triple to UnknownArch. Other values are undefined. + std::pair Foo = T.getABIVariant("foo"); + EXPECT_EQ(Triple::UnknownArch, Foo.first.getArch()); + + // N32 is known to LLVM but unsupported for Android. + EXPECT_EQ(Triple::UnknownArch, N32.first.getArch()); + } + + for (const auto &TripleStr : + {"mips-linux", "mipsel-linux", "mips-mti-linux", "mipsel-img-linux", + "mips-unknown-freebsd", "mips64-linux", "mips64el-linux", + "mips64-mti-linux", "mips64el-img-linux", "mips64-unknown-freebsd"}) { + T = Triple(Triple::normalize(TripleStr)); + std::pair Default = T.getABIVariant(""); + std::pair O32 = T.getABIVariant("o32"); + std::pair N32 = T.getABIVariant("n32"); + std::pair N64 = T.getABIVariant("n64"); + std::pair Foo = T.getABIVariant("foo"); + + EXPECT_EQ(T.getArch(), Default.first.getArch()); + EXPECT_EQ(T.get32BitArchVariant().getArch(), O32.first.getArch()); + EXPECT_EQ(T.get64BitArchVariant().getArch(), N32.first.getArch()); + EXPECT_EQ(T.get64BitArchVariant().getArch(), N64.first.getArch()); + EXPECT_EQ(Triple::UnknownArch, Foo.first.getArch()); + + EXPECT_EQ(T.getVendor(), Default.first.getVendor()); + EXPECT_EQ(T.getVendor(), O32.first.getVendor()); + EXPECT_EQ(T.getVendor(), N32.first.getVendor()); + EXPECT_EQ(T.getVendor(), N64.first.getVendor()); + + EXPECT_EQ(T.getOS(), Default.first.getOS()); + EXPECT_EQ(T.getOS(), O32.first.getOS()); + EXPECT_EQ(T.getOS(), N32.first.getOS()); + EXPECT_EQ(T.getOS(), N64.first.getOS()); + + EXPECT_EQ((T.getArch() == Triple::mips64 || T.getArch() == Triple::mips64el) + ? Triple::ABI64 + : Triple::ABI32, + Default.first.getEnvironment()); + EXPECT_EQ(Triple::ABI32, O32.first.getEnvironment()); + EXPECT_EQ(Triple::ABIN32, N32.first.getEnvironment()); + EXPECT_EQ(Triple::ABI64, N64.first.getEnvironment()); + + EXPECT_EQ((T.getArch() == Triple::mips64 || T.getArch() == Triple::mips64el) + ? "n64" + : "o32", + Default.second); + EXPECT_EQ("o32", O32.second); + EXPECT_EQ("n32", N32.second); + EXPECT_EQ("n64", N64.second); + EXPECT_EQ("foo", Foo.second); + } +} + TEST(TripleTest, getOSVersion) { Triple T; unsigned Major, Minor, Micro;