From b061554caaf38c5e2dddf9af9f5d4b022ea08883 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Mon, 3 Dec 2007 22:06:55 +0000 Subject: [PATCH] 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. llvm-svn: 44551 --- clang/Basic/TargetInfo.cpp | 4 + clang/Driver/Targets.cpp | 100 ++++++++++++------------- clang/Driver/clang.cpp | 76 ++++++++++++++++++- clang/Driver/clang.h | 6 +- clang/include/clang/Basic/TargetInfo.h | 18 +++-- clang/test/Parser/portability.c | 2 +- 6 files changed, 147 insertions(+), 59 deletions(-) diff --git a/clang/Basic/TargetInfo.cpp b/clang/Basic/TargetInfo.cpp index ec91bdd1a25a..6038e614a538 100644 --- a/clang/Basic/TargetInfo.cpp +++ b/clang/Basic/TargetInfo.cpp @@ -52,6 +52,10 @@ void TargetInfo::getLongDoubleInfo(uint64_t &Size, unsigned &Align, //===----------------------------------------------------------------------===// +const char* TargetInfo::getTargetTriple() const { + return PrimaryTarget->getTargetTriple(); +} + /// DiagnoseNonPortability - When a use of a non-portable target feature is /// used, this method emits the diagnostic and marks the translation unit as /// non-portable. diff --git a/clang/Driver/Targets.cpp b/clang/Driver/Targets.cpp index 5a99f7a9257a..dbc0f7af09a5 100644 --- a/clang/Driver/Targets.cpp +++ b/clang/Driver/Targets.cpp @@ -18,25 +18,11 @@ #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/CommandLine.h" +#include +#include + 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 -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 @@ static void Define(std::vector &Buf, const char *Macro, namespace { class DarwinTargetInfo : public TargetInfoImpl { public: + DarwinTargetInfo(const std::string& triple) : TargetInfoImpl(triple) {} + virtual void getTargetDefines(std::vector &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 X86 { namespace { class DarwinPPCTargetInfo : public DarwinTargetInfo { public: + DarwinPPCTargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {} + virtual void getTargetDefines(std::vector &Defines) const { DarwinTargetInfo::getTargetDefines(Defines); getPowerPCDefines(Defines, false); @@ -536,6 +526,8 @@ public: namespace { class DarwinPPC64TargetInfo : public DarwinTargetInfo { public: + DarwinPPC64TargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {} + virtual void getTargetDefines(std::vector &Defines) const { DarwinTargetInfo::getTargetDefines(Defines); getPowerPCDefines(Defines, true); @@ -568,6 +560,8 @@ public: namespace { class DarwinI386TargetInfo : public DarwinTargetInfo { public: + DarwinI386TargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {} + virtual void getTargetDefines(std::vector &Defines) const { DarwinTargetInfo::getTargetDefines(Defines); getX86Defines(Defines, false); @@ -600,6 +594,8 @@ public: namespace { class DarwinX86_64TargetInfo : public DarwinTargetInfo { public: + DarwinX86_64TargetInfo(const std::string& triple) :DarwinTargetInfo(triple) {} + virtual void getTargetDefines(std::vector &Defines) const { DarwinTargetInfo::getTargetDefines(Defines); getX86Defines(Defines, true); @@ -632,7 +628,7 @@ public: 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 @@ public: // 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& 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/clang/Driver/clang.cpp b/clang/Driver/clang.cpp index f26fb994b9eb..5a27d8fd13e0 100644 --- a/clang/Driver/clang.cpp +++ b/clang/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 using namespace clang; @@ -389,6 +390,67 @@ static void InitializeDiagnostics(Diagnostic &Diags) { Diags.setDiagnosticMapping(diag::warn_floatingpoint_eq, diag::MAP_IGNORE); } +//===----------------------------------------------------------------------===// +// Target Triple Processing. +//===----------------------------------------------------------------------===// + +static llvm::cl::opt +TargetTriple("triple", + llvm::cl::desc("Specify target triple (e.g. i686-apple-darwin9).")); + +static llvm::cl::list +Archs("arch", + llvm::cl::desc("Specify target architecture (e.g. i686).")); + +namespace { + class TripleProcessor { + llvm::StringMap TriplesProcessed; + std::vector& triples; + public: + TripleProcessor(std::vector& 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& 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 @@ int main(int argc, char **argv) { // 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 triples; + CreateTargetTriples(triples); + fprintf(stderr, "Targets:"); + for (std::vector::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/clang/Driver/clang.h b/clang/Driver/clang.h index fd11590854e6..eadeb7012612 100644 --- a/clang/Driver/clang.h +++ b/clang/Driver/clang.h @@ -14,6 +14,9 @@ #ifndef LLVM_CLANG_CLANG_H #define LLVM_CLANG_CLANG_H +#include +#include + namespace clang { class Preprocessor; struct LangOptions; @@ -33,7 +36,8 @@ MinimalAction *CreatePrintParserActionsAction(IdentifierTable &); /// 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& triples, + Diagnostic &Diags); /// EmitLLVMFromASTs - Implement -emit-llvm, which generates llvm IR from C. void EmitLLVMFromASTs(Preprocessor &PP, unsigned MainFileID, diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index a86023a6379d..07292f78ce14 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -245,11 +245,10 @@ public: return static_cast(Size); } - const char *getTargetTriple() { - // FIXME ! - return "i686-apple-darwin9"; - } - const char *getTargetDescription() { + /// getTargetTriple - Return the target triple of the primary target. + const char *getTargetTriple() const; + + const char *getTargetDescription() const { // FIXME ! // Hard code darwin-x86 for now. return "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:\ @@ -270,10 +269,17 @@ class TargetInfoImpl { protected: unsigned WCharWidth; /// sizeof(wchar_t) in bits. Default value is 32. unsigned WCharAlign; /// alignof(wchar_t) in bits. Default value is 32. + std::string Triple; public: - TargetInfoImpl() : WCharWidth(32), WCharAlign(32) {} + TargetInfoImpl(const std::string& triple) + : WCharWidth(32), WCharAlign(32), Triple(triple) {} + virtual ~TargetInfoImpl() {} + /// getTargetTriple - Return the string representing the target triple this + /// TargetInfoImpl object was created from. + const char* getTargetTriple() const { return Triple.c_str(); } + /// getTargetDefines - Return a list of the target-specific #define values set /// when compiling to this target. Each string should be of the form /// "#define X Y\n". diff --git a/clang/test/Parser/portability.c b/clang/test/Parser/portability.c index a96aee5c655d..b6e97152859c 100644 --- a/clang/test/Parser/portability.c +++ b/clang/test/Parser/portability.c @@ -1,4 +1,4 @@ -// RUN: clang -arch ppc -arch linux -fsyntax-only %s 2>&1 | grep note | wc -l | grep 1 +// RUN: clang -arch ppc -arch bogusW16W16 -fsyntax-only %s 2>&1 | grep note | wc -l | grep 1 // wchar_t varies across targets. void *X = L"foo";