Implemented initial support for "-triple" option to the clang driver. This
replaces the functionality previously provided by just "-arch" (which is still
supported but has different semantics).
The new behavior is as follows:
(1) If the user does not specify -triple:
(a) If no -arch options are specified, the target triple used is the host
triple (in llvm/Config/config.h).
(b) If one or more -arch's are specified (and no -triple), then there is
one triple for each -arch, where the specified arch is substituted
for the arch in the host triple. Example:
host triple = i686-apple-darwin9
command: clang -arch ppc -arch ppc64 ...
triples used: ppc-apple-darwin9 ppc64-apple-darwin9
(2) The user does specify a -triple (only one allowed):
(a) If no -arch options are specified, the triple specified by -triple
is used. E.g clang -triple i686-apple-darwin9
(b) If one or more -arch options are specified, then the triple specified
by -triple is used as the primary target, and the arch's specified
by -arch are used to create secondary targets. For example:
clang -triple i686-apple-darwin9 -arch ppc -arch ppc64
has the following targets:
i686-apple-darwin9 (primary target)
ppc-apple-darwin9
ppc64-apple-darwin9
Other changes related to the changes to the driver:
- TargetInfoImpl now includes the triple string.
- TargetInfo::getTargetTriple returns the triple for its primary target.
- test case test/Parser/portability.c has been updated because "-arch linux" is
no longer valid ("linux" is an OS, not an arch); instead we use a bogus
architecture "bogusW16W16" where WCharWidth=16 and WCharAlign=16.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44551 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Driver/Targets.cpp b/Driver/Targets.cpp
index 5a99f7a..dbc0f7a 100644
--- a/Driver/Targets.cpp
+++ b/Driver/Targets.cpp
@@ -18,25 +18,11 @@
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/CommandLine.h"
+#include <algorithm>
+#include <cctype>
+
using namespace clang;
-/// Note: a hard coded list of targets is clearly silly, these should be
-/// dynamicly registered and loadable with "-load".
-enum SupportedTargets {
- target_ppc, target_ppc64,
- target_i386, target_x86_64,
- target_linux_i386
-};
-
-static llvm::cl::list<SupportedTargets>
-Archs("arch", llvm::cl::desc("Architectures to compile for"),
-llvm::cl::values(clEnumValN(target_ppc, "ppc", "32-bit Darwin PowerPC"),
- clEnumValN(target_ppc64, "ppc64", "64-bit Darwin PowerPC"),
- clEnumValN(target_i386, "i386", "32-bit Darwin X86"),
- clEnumValN(target_x86_64, "x86_64","64-bit Darwin X86"),
- clEnumValN(target_linux_i386,"linux", "Linux i386"),
- clEnumValEnd));
-
//===----------------------------------------------------------------------===//
// Common code shared among targets.
//===----------------------------------------------------------------------===//
@@ -55,6 +41,8 @@
namespace {
class DarwinTargetInfo : public TargetInfoImpl {
public:
+ DarwinTargetInfo(const std::string& triple) : TargetInfoImpl(triple) {}
+
virtual void getTargetDefines(std::vector<char> &Defs) const {
// FIXME: we need a real target configuration system. For now, only define
// __APPLE__ if the host has it.
@@ -504,6 +492,8 @@
namespace {
class DarwinPPCTargetInfo : public DarwinTargetInfo {
public:
+ DarwinPPCTargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {}
+
virtual void getTargetDefines(std::vector<char> &Defines) const {
DarwinTargetInfo::getTargetDefines(Defines);
getPowerPCDefines(Defines, false);
@@ -536,6 +526,8 @@
namespace {
class DarwinPPC64TargetInfo : public DarwinTargetInfo {
public:
+ DarwinPPC64TargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {}
+
virtual void getTargetDefines(std::vector<char> &Defines) const {
DarwinTargetInfo::getTargetDefines(Defines);
getPowerPCDefines(Defines, true);
@@ -568,6 +560,8 @@
namespace {
class DarwinI386TargetInfo : public DarwinTargetInfo {
public:
+ DarwinI386TargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {}
+
virtual void getTargetDefines(std::vector<char> &Defines) const {
DarwinTargetInfo::getTargetDefines(Defines);
getX86Defines(Defines, false);
@@ -600,6 +594,8 @@
namespace {
class DarwinX86_64TargetInfo : public DarwinTargetInfo {
public:
+ DarwinX86_64TargetInfo(const std::string& triple) :DarwinTargetInfo(triple) {}
+
virtual void getTargetDefines(std::vector<char> &Defines) const {
DarwinTargetInfo::getTargetDefines(Defines);
getX86Defines(Defines, true);
@@ -632,7 +628,7 @@
namespace {
class LinuxTargetInfo : public DarwinTargetInfo {
public:
- LinuxTargetInfo() {
+ LinuxTargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {
// Note: I have no idea if this is right, just for testing.
WCharWidth = 16;
WCharAlign = 16;
@@ -672,48 +668,52 @@
// Driver code
//===----------------------------------------------------------------------===//
+static bool IsX86(const std::string& TT) {
+ return (TT.size() >= 5 && TT[0] == 'i' && TT[2] == '8' && TT[3] == '6' &&
+ TT[4] == '-' && TT[1] - '3' < 6);
+}
+
/// CreateTarget - Create the TargetInfoImpl object for the specified target
/// enum value.
-static TargetInfoImpl *CreateTarget(SupportedTargets T) {
- switch (T) {
- default: assert(0 && "Unknown target!");
- case target_ppc: return new DarwinPPCTargetInfo();
- case target_ppc64: return new DarwinPPC64TargetInfo();
- case target_i386: return new DarwinI386TargetInfo();
- case target_x86_64: return new DarwinX86_64TargetInfo();
- case target_linux_i386: return new LinuxTargetInfo();
+static TargetInfoImpl *CreateTarget(const std::string& T) {
+ if (T.find("darwin") != std::string::npos) {
+ if (T.find("ppc-") == 0)
+ return new DarwinPPCTargetInfo(T);
+ else if (T.find("ppc64-") == 0)
+ return new DarwinPPC64TargetInfo(T);
+ else if (T.find("x86_64-") == 0)
+ return new DarwinX86_64TargetInfo(T);
+ else if (IsX86(T))
+ return new DarwinI386TargetInfo(T);
+ else if (T.find("bogusW16W16-") == 0) // For testing portability.
+ return new LinuxTargetInfo(T);
}
+ else {
+ // Make a copy of the triple that is all lowercase.
+ std::string T_lower(T);
+ std::transform(T_lower.begin(), T_lower.end(),
+ T_lower.begin(), (int(*)(int)) std::tolower);
+
+ if (T_lower.find("linux") != std::string::npos && IsX86(T))
+ return new LinuxTargetInfo(T);
+ }
+
+ assert (false && "Unknown target!");
}
/// CreateTargetInfo - Return the set of target info objects as specified by
/// the -arch command line option.
-TargetInfo *clang::CreateTargetInfo(Diagnostic &Diags) {
- // If the user didn't specify at least one architecture, auto-sense the
- // current host. TODO: This is a hack. :)
- if (Archs.empty()) {
-#ifndef __APPLE__
- // Assume non-apple = i386 for now.
- Archs.push_back(target_i386);
-#elif (defined(__POWERPC__) || defined (__ppc__) || defined(_POWER)) && \
- defined(__ppc64__)
- Archs.push_back(target_ppc64);
-#elif defined(__POWERPC__) || defined (__ppc__) || defined(_POWER)
- Archs.push_back(target_ppc);
-#elif defined(__x86_64__)
- Archs.push_back(target_x86_64);
-#elif defined(__i386__) || defined(i386) || defined(_M_IX86)
- Archs.push_back(target_i386);
-#else
- // Don't know what this is!
- return 0;
-#endif
- }
+TargetInfo *clang::CreateTargetInfo(const std::vector<std::string>& triples,
+ Diagnostic &Diags) {
+ assert (!triples.empty() && "No target triple.");
+
// Create the primary target and target info.
- TargetInfo *TI = new TargetInfo(CreateTarget(Archs[0]), &Diags);
+ TargetInfo *TI = new TargetInfo(CreateTarget(triples[0]), &Diags);
// Add all secondary targets.
- for (unsigned i = 1, e = Archs.size(); i != e; ++i)
- TI->AddSecondaryTarget(CreateTarget(Archs[i]));
+ for (unsigned i = 1, e = triples.size(); i != e; ++i)
+ TI->AddSecondaryTarget(CreateTarget(triples[i]));
+
return TI;
}
diff --git a/Driver/clang.cpp b/Driver/clang.cpp
index f26fb99..5a27d8f 100644
--- a/Driver/clang.cpp
+++ b/Driver/clang.cpp
@@ -36,6 +36,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/System/Signals.h"
+#include "llvm/Config/config.h"
#include <memory>
using namespace clang;
@@ -390,6 +391,67 @@
}
//===----------------------------------------------------------------------===//
+// Target Triple Processing.
+//===----------------------------------------------------------------------===//
+
+static llvm::cl::opt<std::string>
+TargetTriple("triple",
+ llvm::cl::desc("Specify target triple (e.g. i686-apple-darwin9)."));
+
+static llvm::cl::list<std::string>
+Archs("arch",
+ llvm::cl::desc("Specify target architecture (e.g. i686)."));
+
+namespace {
+ class TripleProcessor {
+ llvm::StringMap<char> TriplesProcessed;
+ std::vector<std::string>& triples;
+ public:
+ TripleProcessor(std::vector<std::string>& t) : triples(t) {}
+
+ void addTriple(const std::string& t) {
+ if (TriplesProcessed.find(t.c_str(),t.c_str()+t.size()) ==
+ TriplesProcessed.end()) {
+ triples.push_back(t);
+ TriplesProcessed.GetOrCreateValue(t.c_str(),t.c_str()+t.size());
+ }
+ }
+ };
+}
+
+static void CreateTargetTriples(std::vector<std::string>& triples) {
+ std::string base_triple;
+
+ // Initialize base triple. If a -triple option has been specified, use
+ // that triple. Otherwise, default to the host triple.
+ if (TargetTriple.getValue().empty())
+ base_triple = LLVM_HOSTTRIPLE;
+ else
+ base_triple = TargetTriple.getValue();
+
+ // Decompose the base triple into "arch" and suffix.
+ std::string::size_type firstDash = base_triple.find("-");
+
+ // FIXME: Make this a diagnostic.
+ assert (firstDash != std::string::npos);
+
+ std::string suffix(base_triple,firstDash+1);
+ // FIXME: Make this a diagnostic.
+ assert (!suffix.empty());
+
+ // Create triple cacher.
+ TripleProcessor tp(triples);
+
+ // Add the primary triple to our set of triples if we are using the
+ // host-triple with no archs or using a specified target triple.
+ if (!TargetTriple.getValue().empty() || Archs.empty())
+ tp.addTriple(base_triple);
+
+ for (unsigned i = 0, e = Archs.size(); i !=e; ++i)
+ tp.addTriple(Archs[i] + "-" + suffix);
+}
+
+//===----------------------------------------------------------------------===//
// Preprocessor Initialization
//===----------------------------------------------------------------------===//
@@ -914,7 +976,19 @@
// Get information about the targets being compiled for. Note that this
// pointer and the TargetInfoImpl objects are never deleted by this toy
// driver.
- TargetInfo *Target = CreateTargetInfo(Diags);
+ TargetInfo *Target;
+
+ { // Create triples, and create the TargetInfo.
+ std::vector<std::string> triples;
+ CreateTargetTriples(triples);
+ fprintf(stderr, "Targets:");
+ for (std::vector<std::string>::iterator I = triples.begin(), E = triples.end(); I !=E ; ++I)
+ fprintf (stderr, " %s", I->c_str());
+ fprintf(stderr,"\n");
+
+ Target = CreateTargetInfo(triples,Diags);
+ }
+
if (Target == 0) {
fprintf(stderr,
"Sorry, don't know what target this is, please use -arch.\n");
diff --git a/Driver/clang.h b/Driver/clang.h
index fd11590..eadeb70 100644
--- a/Driver/clang.h
+++ b/Driver/clang.h
@@ -14,6 +14,9 @@
#ifndef LLVM_CLANG_CLANG_H
#define LLVM_CLANG_CLANG_H
+#include <vector>
+#include <string>
+
namespace clang {
class Preprocessor;
struct LangOptions;
@@ -33,7 +36,8 @@
/// CreateTargetInfo - Return the set of target info objects as specified by
/// the -arch command line option.
-TargetInfo *CreateTargetInfo(Diagnostic &Diags);
+TargetInfo *CreateTargetInfo(const std::vector<std::string>& triples,
+ Diagnostic &Diags);
/// EmitLLVMFromASTs - Implement -emit-llvm, which generates llvm IR from C.
void EmitLLVMFromASTs(Preprocessor &PP, unsigned MainFileID,