diff --git a/include/llvm/ADT/Triple.h b/include/llvm/ADT/Triple.h new file mode 100644 index 00000000000..f146c0f37ff --- /dev/null +++ b/include/llvm/ADT/Triple.h @@ -0,0 +1,196 @@ +//===-- llvm/ADT/Triple.h - Target triple helper class ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_TRIPLE_H +#define LLVM_ADT_TRIPLE_H + +#include + +namespace llvm { + +/// Triple - Helper class for working with target triples. +/// +/// Target triples are strings in the format of: +/// ARCHITECTURE-VENDOR-OPERATING_SYSTEM +/// or +/// ARCHITECTURE-VENDOR-OPERATING_SYSTEM-ENVIRONMENT +/// +/// This class is used for clients which want to support arbitrary +/// target triples, but also want to implement certain special +/// behavior for particular targets. This class isolates the mapping +/// from the components of the target triple to well known IDs. +/// +/// See autoconf/config.guess for a glimpse into what they look like +/// in practice. +class Triple { +public: + enum ArchType { + UnknownArch, + + x86, // i?86 + ppc, // powerpc + ppc64, // powerpc64 + x86_64, // amd64, x86_64 + + InvalidArch + }; + enum VendorType { + UnknownVendor, + + Apple, + PC + }; + enum OSType { + UnknownOS, + + Darwin, + FreeBSD, + Linux + }; + +private: + std::string Data; + + /// The parsed arch type (or InvalidArch if uninitialized). + mutable ArchType Arch; + + /// The parsed vendor type. + mutable VendorType Vendor; + + /// The parsed OS type. + mutable OSType OS; + + bool isInitialized() const { return Arch != InvalidArch; } + void Parse() const; + +public: + /// @name Constructors + /// @{ + + Triple() : Data(""), Arch(InvalidArch) {} + explicit Triple(const char *Str) : Data(Str), Arch(InvalidArch) {} + + /// @} + /// @name Typed Component Access + /// @{ + + /// getArch - Get the parsed architecture type of this triple. + ArchType getArch() const { + if (!isInitialized()) Parse(); + return Arch; + } + + /// getVendor - Get the parsed vendor type of this triple. + VendorType getVendor() const { + if (!isInitialized()) Parse(); + return Vendor; + } + + /// getOS - Get the parsed operating system type of this triple. + OSType getOS() const { + if (!isInitialized()) Parse(); + return OS; + } + + /// hasEnvironment - Does this triple have the optional environment + /// (fourth) component? + bool hasEnvironment() const { + return getEnvironmentName() != ""; + } + + /// @} + /// @name Direct Component Access + /// @{ + + const std::string &getTriple() const { return Data; } + + // FIXME: Invent a lightweight string representation for these to + // use. + + /// getArchName - Get the architecture (first) component of the + /// triple. + std::string getArchName() const; + + /// getVendorName - Get the vendor (second) component of the triple. + std::string getVendorName() const; + + /// getOSName - Get the operating system (third) component of the + /// triple. + std::string getOSName() const; + + /// getEnvironmentName - Get the optional environment (fourth) + /// component of the triple, or "" if empty. + std::string getEnvironmentName() const; + + /// getOSAndEnvironmentName - Get the operating system and optional + /// environment components as a single string (separated by a '-' + /// if the environment component is present). + std::string getOSAndEnvironmentName() const; + + /// @} + /// @name Mutators + /// @{ + + /// setArch - Set the architecture (first) component of the triple + /// to a known type. + void setArch(ArchType Kind); + + /// setVendor - Set the vendor (second) component of the triple to a + /// known type. + void setVendor(VendorType Kind); + + /// setOS - Set the operating system (third) component of the triple + /// to a known type. + void setOS(OSType Kind); + + /// setTriple - Set all components to the new triple \arg Str. + void setTriple(const std::string &Str); + + /// setArchName - Set the architecture (first) component of the + /// triple by name. + void setArchName(const std::string &Str); + + /// setVendorName - Set the vendor (second) component of the triple + /// by name. + void setVendorName(const std::string &Str); + + /// setOSName - Set the operating system (third) component of the + /// triple by name. + void setOSName(const std::string &Str); + + /// setEnvironmentName - Set the optional environment (fourth) + /// component of the triple by name. + void setEnvironmentName(const std::string &Str); + + /// setOSAndEnvironmentName - Set the operating system and optional + /// environment components with a single string. + void setOSAndEnvironmentName(const std::string &Str); + + /// @} + /// @name Static helpers for IDs. + /// @{ + + /// getArchTypeName - Get the canonical name for the \arg Kind + /// architecture. + static const char *getArchTypeName(ArchType Kind); + + /// getVendorTypeName - Get the canonical name for the \arg Kind + /// vendor. + static const char *getVendorTypeName(VendorType Kind); + + /// getOSTypeName - Get the canonical name for the \arg Kind vendor. + static const char *getOSTypeName(OSType Kind); + + /// @} +}; + +} // End llvm namespace + + +#endif diff --git a/lib/Support/Triple.cpp b/lib/Support/Triple.cpp new file mode 100644 index 00000000000..6324ead707d --- /dev/null +++ b/lib/Support/Triple.cpp @@ -0,0 +1,183 @@ +//===--- Triple.cpp - Target triple helper class --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Triple.h" +#include +using namespace llvm; + +// + +const char *Triple::getArchTypeName(ArchType Kind) { + switch (Kind) { + case InvalidArch: return ""; + case UnknownArch: return "unknown"; + + case x86: return "i386"; + case x86_64: return "x86_64"; + case ppc: return "powerpc"; + case ppc64: return "powerpc64"; + } + + return ""; +} + +const char *Triple::getVendorTypeName(VendorType Kind) { + switch (Kind) { + case UnknownVendor: return "unknown"; + + case Apple: return "apple"; + case PC: return "PC"; + } + + return ""; +} + +const char *Triple::getOSTypeName(OSType Kind) { + switch (Kind) { + case UnknownOS: return "unknown"; + + case Darwin: return "darwin"; + case FreeBSD: return "freebsd"; + case Linux: return "linux"; + } + + return ""; +} + +// + +void Triple::Parse() const { + assert(!isInitialized() && "Invalid parse call."); + + std::string ArchName = getArchName(); + if (ArchName.size() == 4 && ArchName[0] == 'i' && + ArchName[2] == '8' && ArchName[3] == '6') + Arch = x86; + else if (ArchName == "amd64" || ArchName == "x86_64") + Arch = x86_64; + else if (ArchName == "powerpc") + Arch = ppc; + else if (ArchName == "powerpc64") + Arch = ppc64; + else + Arch = UnknownArch; + + std::string VendorName = getVendorName(); + if (VendorName == "apple") + Vendor = Apple; + else if (VendorName == "pc") + Vendor = PC; + else + Vendor = UnknownVendor; + + std::string OSName = getOSName(); + if (memcmp(&OSName[0], "darwin", 6) == 0) + OS = Darwin; + else if (memcmp(&OSName[0], "freebsd", 7) == 0) + OS = FreeBSD; + else if (memcmp(&OSName[0], "linux", 5) == 0) + OS = Linux; + else + OS = UnknownOS; + + assert(isInitialized() && "Failed to initialize!"); +} + +static std::string extract(const std::string &A, + std::string::size_type begin, + std::string::size_type end) { + if (begin == std::string::npos) + return ""; + if (end == std::string::npos) + return A.substr(begin); + return A.substr(begin, end - begin); +} + +static std::string extract1(const std::string &A, + std::string::size_type begin, + std::string::size_type end) { + if (begin == std::string::npos || begin == end) + return ""; + return extract(A, begin + 1, end); +} + +std::string Triple::getArchName() const { + std::string Tmp = Data; + return extract(Tmp, 0, Tmp.find('-')); +} + +std::string Triple::getVendorName() const { + std::string Tmp = Data; + Tmp = extract1(Tmp, Tmp.find('-'), std::string::npos); + return extract(Tmp, 0, Tmp.find('-')); +} + +std::string Triple::getOSName() const { + std::string Tmp = Data; + Tmp = extract1(Tmp, Tmp.find('-'), std::string::npos); + Tmp = extract1(Tmp, Tmp.find('-'), std::string::npos); + return extract(Tmp, 0, Tmp.find('-')); +} + +std::string Triple::getEnvironmentName() const { + std::string Tmp = Data; + Tmp = extract1(Tmp, Tmp.find('-'), std::string::npos); + Tmp = extract1(Tmp, Tmp.find('-'), std::string::npos); + Tmp = extract1(Tmp, Tmp.find('-'), std::string::npos); + return extract(Tmp, 0, std::string::npos); +} + +std::string Triple::getOSAndEnvironmentName() const { + std::string Tmp = Data; + Tmp = extract1(Tmp, Tmp.find('-'), std::string::npos); + Tmp = extract1(Tmp, Tmp.find('-'), std::string::npos); + return extract(Tmp, 0, std::string::npos); +} + +void Triple::setTriple(const std::string &Str) { + Data = Str; + Arch = InvalidArch; +} + +void Triple::setArch(ArchType Kind) { + setArchName(getArchTypeName(Kind)); +} + +void Triple::setVendor(VendorType Kind) { + setVendorName(getVendorTypeName(Kind)); +} + +void Triple::setOS(OSType Kind) { + setOSName(getOSTypeName(Kind)); +} + +void Triple::setArchName(const std::string &Str) { + setTriple(Str + "-" + getVendorName() + "-" + getOSAndEnvironmentName()); +} + +void Triple::setVendorName(const std::string &Str) { + setTriple(getArchName() + "-" + Str + "-" + getOSAndEnvironmentName()); +} + +void Triple::setOSName(const std::string &Str) { + if (hasEnvironment()) + setTriple(getArchName() + "-" + getVendorName() + "-" + Str + + "-" + getEnvironmentName()); + else + setTriple(getArchName() + "-" + getVendorName() + "-" + Str); +} + +void Triple::setEnvironmentName(const std::string &Str) { + setTriple(getArchName() + "-" + getVendorName() + "-" + getOSName() + + "-" + Str); +} + +void Triple::setOSAndEnvironmentName(const std::string &Str) { + setTriple(getArchName() + "-" + getVendorName() + "-" + Str); +} diff --git a/unittests/ADT/TripleTest.cpp b/unittests/ADT/TripleTest.cpp new file mode 100644 index 00000000000..771d1c75d91 --- /dev/null +++ b/unittests/ADT/TripleTest.cpp @@ -0,0 +1,137 @@ +//===----------- Triple.cpp - Triple unit tests ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" +#include "llvm/ADT/Triple.h" + +using namespace llvm; + +namespace { + +TEST(TripleTest, BasicParsing) { + Triple T; + + T = Triple(""); + EXPECT_EQ(T.getArchName(), ""); + EXPECT_EQ(T.getVendorName(), ""); + EXPECT_EQ(T.getOSName(), ""); + EXPECT_EQ(T.getEnvironmentName(), ""); + + T = Triple("-"); + EXPECT_EQ(T.getArchName(), ""); + EXPECT_EQ(T.getVendorName(), ""); + EXPECT_EQ(T.getOSName(), ""); + EXPECT_EQ(T.getEnvironmentName(), ""); + + T = Triple("--"); + EXPECT_EQ(T.getArchName(), ""); + EXPECT_EQ(T.getVendorName(), ""); + EXPECT_EQ(T.getOSName(), ""); + EXPECT_EQ(T.getEnvironmentName(), ""); + + T = Triple("---"); + EXPECT_EQ(T.getArchName(), ""); + EXPECT_EQ(T.getVendorName(), ""); + EXPECT_EQ(T.getOSName(), ""); + EXPECT_EQ(T.getEnvironmentName(), ""); + + T = Triple("----"); + EXPECT_EQ(T.getArchName(), ""); + EXPECT_EQ(T.getVendorName(), ""); + EXPECT_EQ(T.getOSName(), ""); + EXPECT_EQ(T.getEnvironmentName(), "-"); + + T = Triple("a"); + EXPECT_EQ(T.getArchName(), "a"); + EXPECT_EQ(T.getVendorName(), ""); + EXPECT_EQ(T.getOSName(), ""); + EXPECT_EQ(T.getEnvironmentName(), ""); + + T = Triple("a-b"); + EXPECT_EQ(T.getArchName(), "a"); + EXPECT_EQ(T.getVendorName(), "b"); + EXPECT_EQ(T.getOSName(), ""); + EXPECT_EQ(T.getEnvironmentName(), ""); + + T = Triple("a-b-c"); + EXPECT_EQ(T.getArchName(), "a"); + EXPECT_EQ(T.getVendorName(), "b"); + EXPECT_EQ(T.getOSName(), "c"); + EXPECT_EQ(T.getEnvironmentName(), ""); + + T = Triple("a-b-c-d"); + EXPECT_EQ(T.getArchName(), "a"); + EXPECT_EQ(T.getVendorName(), "b"); + EXPECT_EQ(T.getOSName(), "c"); + EXPECT_EQ(T.getEnvironmentName(), "d"); +} + +TEST(TripleTest, ParsedIDs) { + Triple T; + + T = Triple("i386-apple-darwin"); + EXPECT_EQ(T.getArch(), Triple::x86); + EXPECT_EQ(T.getVendor(), Triple::Apple); + EXPECT_EQ(T.getOS(), Triple::Darwin); + + T = Triple("x86_64-pc-linux-gnu"); + EXPECT_EQ(T.getArch(), Triple::x86_64); + EXPECT_EQ(T.getVendor(), Triple::PC); + EXPECT_EQ(T.getOS(), Triple::Linux); + + T = Triple("powerpc-dunno-notsure"); + EXPECT_EQ(T.getArch(), Triple::ppc); + EXPECT_EQ(T.getVendor(), Triple::UnknownVendor); + EXPECT_EQ(T.getOS(), Triple::UnknownOS); + + T = Triple("huh"); + EXPECT_EQ(T.getArch(), Triple::UnknownArch); +} + +TEST(TripleTest, MutateName) { + Triple T; + EXPECT_EQ(T.getArch(), Triple::UnknownArch); + EXPECT_EQ(T.getVendor(), Triple::UnknownVendor); + EXPECT_EQ(T.getOS(), Triple::UnknownOS); + + T.setArchName("i386"); + EXPECT_EQ(T.getArch(), Triple::x86); + EXPECT_EQ(T.getTriple(), "i386--"); + + T.setVendorName("pc"); + EXPECT_EQ(T.getArch(), Triple::x86); + EXPECT_EQ(T.getVendor(), Triple::PC); + EXPECT_EQ(T.getTriple(), "i386-pc-"); + + T.setOSName("linux"); + EXPECT_EQ(T.getArch(), Triple::x86); + EXPECT_EQ(T.getVendor(), Triple::PC); + EXPECT_EQ(T.getOS(), Triple::Linux); + EXPECT_EQ(T.getTriple(), "i386-pc-linux"); + + T.setEnvironmentName("gnu"); + EXPECT_EQ(T.getArch(), Triple::x86); + EXPECT_EQ(T.getVendor(), Triple::PC); + EXPECT_EQ(T.getOS(), Triple::Linux); + EXPECT_EQ(T.getTriple(), "i386-pc-linux-gnu"); + + T.setOSName("freebsd"); + EXPECT_EQ(T.getArch(), Triple::x86); + EXPECT_EQ(T.getVendor(), Triple::PC); + EXPECT_EQ(T.getOS(), Triple::FreeBSD); + EXPECT_EQ(T.getTriple(), "i386-pc-freebsd-gnu"); + + T.setOSAndEnvironmentName("darwin"); + EXPECT_EQ(T.getArch(), Triple::x86); + EXPECT_EQ(T.getVendor(), Triple::PC); + EXPECT_EQ(T.getOS(), Triple::Darwin); + EXPECT_EQ(T.getTriple(), "i386-pc-darwin"); +} + +}