Driver: Move Clang "triple" computation routines to method on the

ToolChain. This fixes a potenial bad cast when running Clang on PPC code, since
the tool chain in effect is not a subclass of the Darwin one, but we were
treating it like it was.
 - This introduces some gross code duplication, but the right fix for it is to
   just move the Driver to start depending on the targets in libBasic, so I am
   not planning on fixing it immediately.

llvm-svn: 111856
This commit is contained in:
Daniel Dunbar 2010-08-23 22:35:37 +00:00
parent f10f9bec83
commit 82eb4ce476
5 changed files with 192 additions and 81 deletions

View File

@ -18,6 +18,7 @@
namespace clang {
namespace driver {
class ArgList;
class Compilation;
class DerivedArgList;
class Driver;
@ -141,6 +142,17 @@ public:
/// UseSjLjExceptions - Does this tool chain use SjLj exceptions.
virtual bool UseSjLjExceptions() const { return false; }
/// ComputeLLVMTriple - Return the LLVM target triple to use, after taking
/// command line arguments into account.
virtual std::string ComputeLLVMTriple(const ArgList &Args) const;
/// ComputeEffectiveClangTriple - Return the Clang triple to use for this
/// target, which may take into account the command line arguments. For
/// example, on Darwin the -mmacosx-version-min= command line argument (which
/// sets the deployment target) determines the version in the triple passed to
/// Clang.
virtual std::string ComputeEffectiveClangTriple(const ArgList &Args) const;
};
} // end namespace driver

View File

@ -10,8 +10,12 @@
#include "clang/Driver/ToolChain.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/HostInfo.h"
#include "clang/Driver/Options.h"
using namespace clang::driver;
@ -38,3 +42,135 @@ std::string ToolChain::GetProgramPath(const char *Name, bool WantFile) const {
types::ID ToolChain::LookupTypeForExtension(const char *Ext) const {
return types::lookupTypeForExtension(Ext);
}
/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targetting.
//
// FIXME: tblgen this.
static const char *getARMTargetCPU(const ArgList &Args,
const llvm::Triple &Triple) {
// FIXME: Warn on inconsistent use of -mcpu and -march.
// If we have -mcpu=, use that.
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
return A->getValue(Args);
llvm::StringRef MArch;
if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
// Otherwise, if we have -march= choose the base CPU for that arch.
MArch = A->getValue(Args);
} else {
// Otherwise, use the Arch from the triple.
MArch = Triple.getArchName();
}
if (MArch == "armv2" || MArch == "armv2a")
return "arm2";
if (MArch == "armv3")
return "arm6";
if (MArch == "armv3m")
return "arm7m";
if (MArch == "armv4" || MArch == "armv4t")
return "arm7tdmi";
if (MArch == "armv5" || MArch == "armv5t")
return "arm10tdmi";
if (MArch == "armv5e" || MArch == "armv5te")
return "arm1026ejs";
if (MArch == "armv5tej")
return "arm926ej-s";
if (MArch == "armv6" || MArch == "armv6k")
return "arm1136jf-s";
if (MArch == "armv6j")
return "arm1136j-s";
if (MArch == "armv6z" || MArch == "armv6zk")
return "arm1176jzf-s";
if (MArch == "armv6t2")
return "arm1156t2-s";
if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a")
return "cortex-a8";
if (MArch == "armv7r" || MArch == "armv7-r")
return "cortex-r4";
if (MArch == "armv7m" || MArch == "armv7-m")
return "cortex-m3";
if (MArch == "ep9312")
return "ep9312";
if (MArch == "iwmmxt")
return "iwmmxt";
if (MArch == "xscale")
return "xscale";
// If all else failed, return the most base CPU LLVM supports.
return "arm7tdmi";
}
/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular
/// CPU.
//
// FIXME: This is redundant with -mcpu, why does LLVM use this.
// FIXME: tblgen this, or kill it!
static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU) {
if (CPU == "arm7tdmi" || CPU == "arm7tdmi-s" || CPU == "arm710t" ||
CPU == "arm720t" || CPU == "arm9" || CPU == "arm9tdmi" ||
CPU == "arm920" || CPU == "arm920t" || CPU == "arm922t" ||
CPU == "arm940t" || CPU == "ep9312")
return "v4t";
if (CPU == "arm10tdmi" || CPU == "arm1020t")
return "v5";
if (CPU == "arm9e" || CPU == "arm926ej-s" || CPU == "arm946e-s" ||
CPU == "arm966e-s" || CPU == "arm968e-s" || CPU == "arm10e" ||
CPU == "arm1020e" || CPU == "arm1022e" || CPU == "xscale" ||
CPU == "iwmmxt")
return "v5e";
if (CPU == "arm1136j-s" || CPU == "arm1136jf-s" || CPU == "arm1176jz-s" ||
CPU == "arm1176jzf-s" || CPU == "mpcorenovfp" || CPU == "mpcore")
return "v6";
if (CPU == "arm1156t2-s" || CPU == "arm1156t2f-s")
return "v6t2";
if (CPU == "cortex-a8" || CPU == "cortex-a9")
return "v7";
return "";
}
std::string ToolChain::ComputeLLVMTriple(const ArgList &Args) const {
switch (getTriple().getArch()) {
default:
return getTripleString();
case llvm::Triple::arm:
case llvm::Triple::thumb: {
// FIXME: Factor into subclasses.
llvm::Triple Triple = getTriple();
// Thumb2 is the default for V7 on Darwin.
//
// FIXME: Thumb should just be another -target-feaure, not in the triple.
llvm::StringRef Suffix =
getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple));
bool ThumbDefault =
(Suffix == "v7" && getTriple().getOS() == llvm::Triple::Darwin);
std::string ArchName = "arm";
if (Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault))
ArchName = "thumb";
Triple.setArchName(ArchName + Suffix.str());
return Triple.getTriple();
}
}
}
std::string ToolChain::ComputeEffectiveClangTriple(const ArgList &Args) const {
// Diagnose use of -mmacosx-version-min and -miphoneos-version-min on
// non-Darwin.
if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ,
options::OPT_miphoneos_version_min_EQ))
getDriver().Diag(clang::diag::err_drv_clang_unsupported)
<< A->getAsString(Args);
return ComputeLLVMTriple(Args);
}

View File

@ -19,6 +19,7 @@
#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
@ -202,6 +203,38 @@ Darwin::~Darwin() {
delete it->second;
}
std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args) const {
llvm::Triple Triple(ComputeLLVMTriple(Args));
// If the target isn't initialized (e.g., an unknown Darwin platform, return
// the default triple).
if (!isTargetInitialized())
return Triple.getTriple();
unsigned Version[3];
getTargetVersion(Version);
// Mangle the target version into the OS triple component. For historical
// reasons that make little sense, the version passed here is the "darwin"
// version, which drops the 10 and offsets by 4. See inverse code when
// setting the OS version preprocessor define.
if (!isTargetIPhoneOS()) {
Version[0] = Version[1] + 4;
Version[1] = Version[2];
Version[2] = 0;
} else {
// Use the environment to communicate that we are targetting iPhoneOS.
Triple.setEnvironmentName("iphoneos");
}
llvm::SmallString<16> Str;
llvm::raw_svector_ostream(Str) << "darwin" << Version[0]
<< "." << Version[1] << "." << Version[2];
Triple.setOSName(Str.str());
return Triple.getTriple();
}
Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA) const {
Action::ActionClass Key;
if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
@ -763,6 +796,11 @@ bool Darwin::SupportsObjCGC() const {
return !isTargetIPhoneOS();
}
std::string
Darwin_Generic_GCC::ComputeEffectiveClangTriple(const ArgList &Args) const {
return ComputeLLVMTriple(Args);
}
/// Generic_GCC - A tool chain using the 'gcc' command to perform
/// all subcommands; this relies on gcc translating the majority of
/// command line options.

View File

@ -73,6 +73,8 @@ public:
Darwin(const HostInfo &Host, const llvm::Triple& Triple);
~Darwin();
std::string ComputeEffectiveClangTriple(const ArgList &Args) const;
/// @name Darwin Specific Toolchain API
/// {
@ -251,6 +253,8 @@ public:
Darwin_Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple)
: Generic_GCC(Host, Triple) {}
std::string ComputeEffectiveClangTriple(const ArgList &Args) const;
virtual const char *GetDefaultRelocationModel() const { return "pic"; }
};

View File

@ -337,35 +337,6 @@ static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU) {
return "";
}
/// getLLVMTriple - Get the LLVM triple to use for a particular toolchain, which
/// may depend on command line arguments.
static std::string getLLVMTriple(const ToolChain &TC, const ArgList &Args) {
switch (TC.getTriple().getArch()) {
default:
return TC.getTripleString();
case llvm::Triple::arm:
case llvm::Triple::thumb: {
// FIXME: Factor into subclasses.
llvm::Triple Triple = TC.getTriple();
// Thumb2 is the default for V7 on Darwin.
//
// FIXME: Thumb should just be another -target-feaure, not in the triple.
llvm::StringRef Suffix =
getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple));
bool ThumbDefault =
(Suffix == "v7" && TC.getTriple().getOS() == llvm::Triple::Darwin);
std::string ArchName = "arm";
if (Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault))
ArchName = "thumb";
Triple.setArchName(ArchName + Suffix.str());
return Triple.getTriple();
}
}
}
// FIXME: Move to target hook.
static bool isSignedCharDefault(const llvm::Triple &Triple) {
switch (Triple.getArch()) {
@ -694,55 +665,6 @@ static bool needsExceptions(const ArgList &Args, types::ID InputType,
}
}
/// getEffectiveClangTriple - Get the "effective" target triple, which is the
/// triple for the target but with the OS version potentially modified for
/// Darwin's -mmacosx-version-min.
static std::string getEffectiveClangTriple(const Driver &D,
const ToolChain &TC,
const ArgList &Args) {
llvm::Triple Triple(getLLVMTriple(TC, Args));
// Handle -mmacosx-version-min and -miphoneos-version-min.
if (Triple.getOS() != llvm::Triple::Darwin) {
// Diagnose use of -mmacosx-version-min and -miphoneos-version-min on
// non-Darwin.
if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ,
options::OPT_miphoneos_version_min_EQ))
D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
} else {
const toolchains::Darwin &DarwinTC(
reinterpret_cast<const toolchains::Darwin&>(TC));
// If the target isn't initialized (e.g., an unknown Darwin platform, return
// the default triple).
if (!DarwinTC.isTargetInitialized())
return Triple.getTriple();
unsigned Version[3];
DarwinTC.getTargetVersion(Version);
// Mangle the target version into the OS triple component. For historical
// reasons that make little sense, the version passed here is the "darwin"
// version, which drops the 10 and offsets by 4. See inverse code when
// setting the OS version preprocessor define.
if (!DarwinTC.isTargetIPhoneOS()) {
Version[0] = Version[1] + 4;
Version[1] = Version[2];
Version[2] = 0;
} else {
// Use the environment to communicate that we are targetting iPhoneOS.
Triple.setEnvironmentName("iphoneos");
}
llvm::SmallString<16> Str;
llvm::raw_svector_ostream(Str) << "darwin" << Version[0]
<< "." << Version[1] << "." << Version[2];
Triple.setOSName(Str.str());
}
return Triple.getTriple();
}
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@ -762,7 +684,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Add the "effective" target triple.
CmdArgs.push_back("-triple");
std::string TripleStr = getEffectiveClangTriple(D, getToolChain(), Args);
std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args);
CmdArgs.push_back(Args.MakeArgString(TripleStr));
// Select the appropriate action.
@ -1543,7 +1465,6 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
assert(Inputs.size() == 1 && "Unexpected number of inputs.");
@ -1556,7 +1477,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
// Add the "effective" target triple.
CmdArgs.push_back("-triple");
std::string TripleStr = getEffectiveClangTriple(D, getToolChain(), Args);
std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args);
CmdArgs.push_back(Args.MakeArgString(TripleStr));
// Set the output mode, we currently only expect to be used as a real