diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Driver')
20 files changed, 3572 insertions, 3181 deletions
diff --git a/contrib/llvm/tools/clang/lib/Driver/Action.cpp b/contrib/llvm/tools/clang/lib/Driver/Action.cpp index 2b5bbee..ddd2d59 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Action.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Action.cpp @@ -11,6 +11,7 @@ #include "llvm/Support/ErrorHandling.h" #include <cassert> using namespace clang::driver; +using namespace llvm::opt; Action::~Action() { if (OwnsInputs) { diff --git a/contrib/llvm/tools/clang/lib/Driver/Arg.cpp b/contrib/llvm/tools/clang/lib/Driver/Arg.cpp deleted file mode 100644 index 93d70a9..0000000 --- a/contrib/llvm/tools/clang/lib/Driver/Arg.cpp +++ /dev/null @@ -1,123 +0,0 @@ -//===--- Arg.cpp - Argument Implementations -------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "clang/Driver/Arg.h" -#include "clang/Basic/LLVM.h" -#include "clang/Driver/ArgList.h" -#include "clang/Driver/Option.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Support/raw_ostream.h" - -using namespace clang::driver; -using clang::StringRef; - -Arg::Arg(const Option _Opt, StringRef S, unsigned _Index, const Arg *_BaseArg) - : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index), - Claimed(false), OwnsValues(false) { -} - -Arg::Arg(const Option _Opt, StringRef S, unsigned _Index, - const char *Value0, const Arg *_BaseArg) - : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index), - Claimed(false), OwnsValues(false) { - Values.push_back(Value0); -} - -Arg::Arg(const Option _Opt, StringRef S, unsigned _Index, - const char *Value0, const char *Value1, const Arg *_BaseArg) - : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index), - Claimed(false), OwnsValues(false) { - Values.push_back(Value0); - Values.push_back(Value1); -} - -Arg::~Arg() { - if (OwnsValues) { - for (unsigned i = 0, e = Values.size(); i != e; ++i) - delete[] Values[i]; - } -} - -void Arg::dump() const { - llvm::errs() << "<"; - - llvm::errs() << " Opt:"; - Opt.dump(); - - llvm::errs() << " Index:" << Index; - - llvm::errs() << " Values: ["; - for (unsigned i = 0, e = Values.size(); i != e; ++i) { - if (i) llvm::errs() << ", "; - llvm::errs() << "'" << Values[i] << "'"; - } - - llvm::errs() << "]>\n"; -} - -std::string Arg::getAsString(const ArgList &Args) const { - SmallString<256> Res; - llvm::raw_svector_ostream OS(Res); - - ArgStringList ASL; - render(Args, ASL); - for (ArgStringList::iterator - it = ASL.begin(), ie = ASL.end(); it != ie; ++it) { - if (it != ASL.begin()) - OS << ' '; - OS << *it; - } - - return OS.str(); -} - -void Arg::renderAsInput(const ArgList &Args, ArgStringList &Output) const { - if (!getOption().hasNoOptAsInput()) { - render(Args, Output); - return; - } - - for (unsigned i = 0, e = getNumValues(); i != e; ++i) - Output.push_back(getValue(i)); -} - -void Arg::render(const ArgList &Args, ArgStringList &Output) const { - switch (getOption().getRenderStyle()) { - case Option::RenderValuesStyle: - for (unsigned i = 0, e = getNumValues(); i != e; ++i) - Output.push_back(getValue(i)); - break; - - case Option::RenderCommaJoinedStyle: { - SmallString<256> Res; - llvm::raw_svector_ostream OS(Res); - OS << getSpelling(); - for (unsigned i = 0, e = getNumValues(); i != e; ++i) { - if (i) OS << ','; - OS << getValue(i); - } - Output.push_back(Args.MakeArgString(OS.str())); - break; - } - - case Option::RenderJoinedStyle: - Output.push_back(Args.GetOrMakeJoinedArgString( - getIndex(), getSpelling(), getValue(0))); - for (unsigned i = 1, e = getNumValues(); i != e; ++i) - Output.push_back(getValue(i)); - break; - - case Option::RenderSeparateStyle: - Output.push_back(Args.MakeArgString(getSpelling())); - for (unsigned i = 0, e = getNumValues(); i != e; ++i) - Output.push_back(getValue(i)); - break; - } -} diff --git a/contrib/llvm/tools/clang/lib/Driver/ArgList.cpp b/contrib/llvm/tools/clang/lib/Driver/ArgList.cpp deleted file mode 100644 index 4b8d151..0000000 --- a/contrib/llvm/tools/clang/lib/Driver/ArgList.cpp +++ /dev/null @@ -1,423 +0,0 @@ -//===--- ArgList.cpp - Argument List Management ---------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "clang/Driver/ArgList.h" -#include "clang/Driver/Arg.h" -#include "clang/Driver/DriverDiagnostic.h" -#include "clang/Driver/Option.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Support/raw_ostream.h" - -using namespace clang; -using namespace clang::driver; - -void arg_iterator::SkipToNextArg() { - for (; Current != Args.end(); ++Current) { - // Done if there are no filters. - if (!Id0.isValid()) - break; - - // Otherwise require a match. - const Option &O = (*Current)->getOption(); - if (O.matches(Id0) || - (Id1.isValid() && O.matches(Id1)) || - (Id2.isValid() && O.matches(Id2))) - break; - } -} - -// - -ArgList::ArgList() { -} - -ArgList::~ArgList() { -} - -void ArgList::append(Arg *A) { - Args.push_back(A); -} - -void ArgList::eraseArg(OptSpecifier Id) { - for (iterator it = begin(), ie = end(); it != ie; ) { - if ((*it)->getOption().matches(Id)) { - it = Args.erase(it); - ie = end(); - } else { - ++it; - } - } -} - -Arg *ArgList::getLastArgNoClaim(OptSpecifier Id) const { - // FIXME: Make search efficient? - for (const_reverse_iterator it = rbegin(), ie = rend(); it != ie; ++it) - if ((*it)->getOption().matches(Id)) - return *it; - return 0; -} - -Arg *ArgList::getLastArg(OptSpecifier Id) const { - Arg *Res = 0; - for (const_iterator it = begin(), ie = end(); it != ie; ++it) { - if ((*it)->getOption().matches(Id)) { - Res = *it; - Res->claim(); - } - } - - return Res; -} - -Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1) const { - Arg *Res = 0; - for (const_iterator it = begin(), ie = end(); it != ie; ++it) { - if ((*it)->getOption().matches(Id0) || - (*it)->getOption().matches(Id1)) { - Res = *it; - Res->claim(); - } - } - - return Res; -} - -Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1, - OptSpecifier Id2) const { - Arg *Res = 0; - for (const_iterator it = begin(), ie = end(); it != ie; ++it) { - if ((*it)->getOption().matches(Id0) || - (*it)->getOption().matches(Id1) || - (*it)->getOption().matches(Id2)) { - Res = *it; - Res->claim(); - } - } - - return Res; -} - -Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1, - OptSpecifier Id2, OptSpecifier Id3) const { - Arg *Res = 0; - for (const_iterator it = begin(), ie = end(); it != ie; ++it) { - if ((*it)->getOption().matches(Id0) || - (*it)->getOption().matches(Id1) || - (*it)->getOption().matches(Id2) || - (*it)->getOption().matches(Id3)) { - Res = *it; - Res->claim(); - } - } - - return Res; -} - -Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1, - OptSpecifier Id2, OptSpecifier Id3, - OptSpecifier Id4) const { - Arg *Res = 0; - for (const_iterator it = begin(), ie = end(); it != ie; ++it) { - if ((*it)->getOption().matches(Id0) || - (*it)->getOption().matches(Id1) || - (*it)->getOption().matches(Id2) || - (*it)->getOption().matches(Id3) || - (*it)->getOption().matches(Id4)) { - Res = *it; - Res->claim(); - } - } - - return Res; -} - -Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1, - OptSpecifier Id2, OptSpecifier Id3, - OptSpecifier Id4, OptSpecifier Id5) const { - Arg *Res = 0; - for (const_iterator it = begin(), ie = end(); it != ie; ++it) { - if ((*it)->getOption().matches(Id0) || - (*it)->getOption().matches(Id1) || - (*it)->getOption().matches(Id2) || - (*it)->getOption().matches(Id3) || - (*it)->getOption().matches(Id4) || - (*it)->getOption().matches(Id5)) { - Res = *it; - Res->claim(); - } - } - - return Res; -} - -Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1, - OptSpecifier Id2, OptSpecifier Id3, - OptSpecifier Id4, OptSpecifier Id5, - OptSpecifier Id6) const { - Arg *Res = 0; - for (const_iterator it = begin(), ie = end(); it != ie; ++it) { - if ((*it)->getOption().matches(Id0) || - (*it)->getOption().matches(Id1) || - (*it)->getOption().matches(Id2) || - (*it)->getOption().matches(Id3) || - (*it)->getOption().matches(Id4) || - (*it)->getOption().matches(Id5) || - (*it)->getOption().matches(Id6)) { - Res = *it; - Res->claim(); - } - } - - return Res; -} - -Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1, - OptSpecifier Id2, OptSpecifier Id3, - OptSpecifier Id4, OptSpecifier Id5, - OptSpecifier Id6, OptSpecifier Id7) const { - Arg *Res = 0; - for (const_iterator it = begin(), ie = end(); it != ie; ++it) { - if ((*it)->getOption().matches(Id0) || - (*it)->getOption().matches(Id1) || - (*it)->getOption().matches(Id2) || - (*it)->getOption().matches(Id3) || - (*it)->getOption().matches(Id4) || - (*it)->getOption().matches(Id5) || - (*it)->getOption().matches(Id6) || - (*it)->getOption().matches(Id7)) { - Res = *it; - Res->claim(); - } - } - - return Res; -} - -bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const { - if (Arg *A = getLastArg(Pos, Neg)) - return A->getOption().matches(Pos); - return Default; -} - -bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier PosAlias, OptSpecifier Neg, - bool Default) const { - if (Arg *A = getLastArg(Pos, PosAlias, Neg)) - return A->getOption().matches(Pos) || A->getOption().matches(PosAlias); - return Default; -} - -StringRef ArgList::getLastArgValue(OptSpecifier Id, - StringRef Default) const { - if (Arg *A = getLastArg(Id)) - return A->getValue(); - return Default; -} - -int ArgList::getLastArgIntValue(OptSpecifier Id, int Default, - clang::DiagnosticsEngine *Diags) const { - int Res = Default; - - if (Arg *A = getLastArg(Id)) { - if (StringRef(A->getValue()).getAsInteger(10, Res)) { - if (Diags) - Diags->Report(diag::err_drv_invalid_int_value) - << A->getAsString(*this) << A->getValue(); - } - } - - return Res; -} - -std::vector<std::string> ArgList::getAllArgValues(OptSpecifier Id) const { - SmallVector<const char *, 16> Values; - AddAllArgValues(Values, Id); - return std::vector<std::string>(Values.begin(), Values.end()); -} - -void ArgList::AddLastArg(ArgStringList &Output, OptSpecifier Id) const { - if (Arg *A = getLastArg(Id)) { - A->claim(); - A->render(*this, Output); - } -} - -void ArgList::AddLastArg(ArgStringList &Output, OptSpecifier Id0, - OptSpecifier Id1) const { - if (Arg *A = getLastArg(Id0, Id1)) { - A->claim(); - A->render(*this, Output); - } -} - -void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0, - OptSpecifier Id1, OptSpecifier Id2) const { - for (arg_iterator it = filtered_begin(Id0, Id1, Id2), - ie = filtered_end(); it != ie; ++it) { - (*it)->claim(); - (*it)->render(*this, Output); - } -} - -void ArgList::AddAllArgValues(ArgStringList &Output, OptSpecifier Id0, - OptSpecifier Id1, OptSpecifier Id2) const { - for (arg_iterator it = filtered_begin(Id0, Id1, Id2), - ie = filtered_end(); it != ie; ++it) { - (*it)->claim(); - for (unsigned i = 0, e = (*it)->getNumValues(); i != e; ++i) - Output.push_back((*it)->getValue(i)); - } -} - -void ArgList::AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0, - const char *Translation, - bool Joined) const { - for (arg_iterator it = filtered_begin(Id0), - ie = filtered_end(); it != ie; ++it) { - (*it)->claim(); - - if (Joined) { - Output.push_back(MakeArgString(StringRef(Translation) + - (*it)->getValue(0))); - } else { - Output.push_back(Translation); - Output.push_back((*it)->getValue(0)); - } - } -} - -void ArgList::ClaimAllArgs(OptSpecifier Id0) const { - for (arg_iterator it = filtered_begin(Id0), - ie = filtered_end(); it != ie; ++it) - (*it)->claim(); -} - -void ArgList::ClaimAllArgs() const { - for (const_iterator it = begin(), ie = end(); it != ie; ++it) - if (!(*it)->isClaimed()) - (*it)->claim(); -} - -const char *ArgList::MakeArgString(const Twine &T) const { - SmallString<256> Str; - T.toVector(Str); - return MakeArgString(Str.str()); -} - -const char *ArgList::GetOrMakeJoinedArgString(unsigned Index, - StringRef LHS, - StringRef RHS) const { - StringRef Cur = getArgString(Index); - if (Cur.size() == LHS.size() + RHS.size() && - Cur.startswith(LHS) && Cur.endswith(RHS)) - return Cur.data(); - - return MakeArgString(LHS + RHS); -} - -void ArgList::dump() { - llvm::errs() << "ArgList:"; - for (iterator it = begin(), ie = end(); it != ie; ++it) { - llvm::errs() << " " << (*it)->getSpelling(); - } - llvm::errs() << "\n"; -} - -// - -InputArgList::InputArgList(const char* const *ArgBegin, - const char* const *ArgEnd) - : NumInputArgStrings(ArgEnd - ArgBegin) { - ArgStrings.append(ArgBegin, ArgEnd); -} - -InputArgList::~InputArgList() { - // An InputArgList always owns its arguments. - for (iterator it = begin(), ie = end(); it != ie; ++it) - delete *it; -} - -unsigned InputArgList::MakeIndex(StringRef String0) const { - unsigned Index = ArgStrings.size(); - - // Tuck away so we have a reliable const char *. - SynthesizedStrings.push_back(String0); - ArgStrings.push_back(SynthesizedStrings.back().c_str()); - - return Index; -} - -unsigned InputArgList::MakeIndex(StringRef String0, - StringRef String1) const { - unsigned Index0 = MakeIndex(String0); - unsigned Index1 = MakeIndex(String1); - assert(Index0 + 1 == Index1 && "Unexpected non-consecutive indices!"); - (void) Index1; - return Index0; -} - -const char *InputArgList::MakeArgString(StringRef Str) const { - return getArgString(MakeIndex(Str)); -} - -// - -DerivedArgList::DerivedArgList(const InputArgList &_BaseArgs) - : BaseArgs(_BaseArgs) { -} - -DerivedArgList::~DerivedArgList() { - // We only own the arguments we explicitly synthesized. - for (iterator it = SynthesizedArgs.begin(), ie = SynthesizedArgs.end(); - it != ie; ++it) - delete *it; -} - -const char *DerivedArgList::MakeArgString(StringRef Str) const { - return BaseArgs.MakeArgString(Str); -} - -Arg *DerivedArgList::MakeFlagArg(const Arg *BaseArg, const Option Opt) const { - Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) + - Twine(Opt.getName())), - BaseArgs.MakeIndex(Opt.getName()), BaseArg); - SynthesizedArgs.push_back(A); - return A; -} - -Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option Opt, - StringRef Value) const { - unsigned Index = BaseArgs.MakeIndex(Value); - Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) + - Twine(Opt.getName())), - Index, BaseArgs.getArgString(Index), BaseArg); - SynthesizedArgs.push_back(A); - return A; -} - -Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option Opt, - StringRef Value) const { - unsigned Index = BaseArgs.MakeIndex(Opt.getName(), Value); - Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) + - Twine(Opt.getName())), - Index, BaseArgs.getArgString(Index + 1), BaseArg); - SynthesizedArgs.push_back(A); - return A; -} - -Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option Opt, - StringRef Value) const { - unsigned Index = BaseArgs.MakeIndex(Opt.getName().str() + Value.str()); - Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) + - Twine(Opt.getName())), Index, - BaseArgs.getArgString(Index) + Opt.getName().size(), - BaseArg); - SynthesizedArgs.push_back(A); - return A; -} diff --git a/contrib/llvm/tools/clang/lib/Driver/CC1AsOptions.cpp b/contrib/llvm/tools/clang/lib/Driver/CC1AsOptions.cpp index 9048043..22180c9 100644 --- a/contrib/llvm/tools/clang/lib/Driver/CC1AsOptions.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/CC1AsOptions.cpp @@ -8,27 +8,25 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/CC1AsOptions.h" -#include "clang/Driver/OptTable.h" -#include "clang/Driver/Option.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Option/OptTable.h" +#include "llvm/Option/Option.h" using namespace clang; using namespace clang::driver; -using namespace clang::driver::options; +using namespace llvm::opt; using namespace clang::driver::cc1asoptions; -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) +#define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE; #include "clang/Driver/CC1AsOptions.inc" -#undef OPTION #undef PREFIX static const OptTable::Info CC1AsInfoTable[] = { -#define PREFIX(NAME, VALUE) -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ HELPTEXT, METAVAR) \ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \ - FLAGS, OPT_##GROUP, OPT_##ALIAS }, + FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS }, #include "clang/Driver/CC1AsOptions.inc" +#undef OPTION }; namespace { @@ -36,8 +34,7 @@ namespace { class CC1AsOptTable : public OptTable { public: CC1AsOptTable() - : OptTable(CC1AsInfoTable, - sizeof(CC1AsInfoTable) / sizeof(CC1AsInfoTable[0])) {} + : OptTable(CC1AsInfoTable, llvm::array_lengthof(CC1AsInfoTable)) {} }; } diff --git a/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp b/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp index 1bff4a3..f077fd6 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp @@ -9,20 +9,20 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Action.h" -#include "clang/Driver/ArgList.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "clang/Driver/ToolChain.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/Program.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" #include <errno.h> #include <sys/stat.h> using namespace clang::driver; using namespace clang; +using namespace llvm::opt; Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain, InputArgList *_Args, DerivedArgList *_TranslatedArgs) @@ -69,160 +69,34 @@ const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC, return *Entry; } -void Compilation::PrintJob(raw_ostream &OS, const Job &J, - const char *Terminator, bool Quote) const { - if (const Command *C = dyn_cast<Command>(&J)) { - OS << " \"" << C->getExecutable() << '"'; - for (ArgStringList::const_iterator it = C->getArguments().begin(), - ie = C->getArguments().end(); it != ie; ++it) { - OS << ' '; - if (!Quote && !std::strpbrk(*it, " \"\\$")) { - OS << *it; - continue; - } - - // Quote the argument and escape shell special characters; this isn't - // really complete but is good enough. - OS << '"'; - for (const char *s = *it; *s; ++s) { - if (*s == '"' || *s == '\\' || *s == '$') - OS << '\\'; - OS << *s; - } - OS << '"'; - } - OS << Terminator; - } else { - const JobList *Jobs = cast<JobList>(&J); - for (JobList::const_iterator - it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it) - PrintJob(OS, **it, Terminator, Quote); - } -} - -static bool skipArg(const char *Flag, bool &SkipNextArg) { - StringRef FlagRef(Flag); - - // Assume we're going to see -Flag <Arg>. - SkipNextArg = true; - - // These flags are all of the form -Flag <Arg> and are treated as two - // arguments. Therefore, we need to skip the flag and the next argument. - bool Res = llvm::StringSwitch<bool>(Flag) - .Cases("-I", "-MF", "-MT", "-MQ", true) - .Cases("-o", "-coverage-file", "-dependency-file", true) - .Cases("-fdebug-compilation-dir", "-idirafter", true) - .Cases("-include", "-include-pch", "-internal-isystem", true) - .Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true) - .Cases("-iwithprefixbefore", "-isysroot", "-isystem", "-iquote", true) - .Cases("-resource-dir", "-serialize-diagnostic-file", true) - .Case("-dwarf-debug-flags", true) - .Default(false); - - // Match found. - if (Res) - return Res; - - // The remaining flags are treated as a single argument. - SkipNextArg = false; - - // These flags are all of the form -Flag and have no second argument. - Res = llvm::StringSwitch<bool>(Flag) - .Cases("-M", "-MM", "-MG", "-MP", "-MD", true) - .Case("-MMD", true) - .Default(false); - - // Match found. - if (Res) - return Res; - - // These flags are treated as a single argument (e.g., -F<Dir>). - if (FlagRef.startswith("-F") || FlagRef.startswith("-I")) - return true; - - return false; -} - -static bool quoteNextArg(const char *flag) { - return llvm::StringSwitch<bool>(flag) - .Case("-D", true) - .Default(false); -} - -void Compilation::PrintDiagnosticJob(raw_ostream &OS, const Job &J) const { - if (const Command *C = dyn_cast<Command>(&J)) { - OS << C->getExecutable(); - unsigned QuoteNextArg = 0; - for (ArgStringList::const_iterator it = C->getArguments().begin(), - ie = C->getArguments().end(); it != ie; ++it) { - - bool SkipNext; - if (skipArg(*it, SkipNext)) { - if (SkipNext) ++it; - continue; - } - - if (!QuoteNextArg) - QuoteNextArg = quoteNextArg(*it) ? 2 : 0; - - OS << ' '; - - if (QuoteNextArg == 1) - OS << '"'; - - if (!std::strpbrk(*it, " \"\\$")) { - OS << *it; - } else { - // Quote the argument and escape shell special characters; this isn't - // really complete but is good enough. - OS << '"'; - for (const char *s = *it; *s; ++s) { - if (*s == '"' || *s == '\\' || *s == '$') - OS << '\\'; - OS << *s; - } - OS << '"'; - } +bool Compilation::CleanupFile(const char *File, bool IssueErrors) const { + std::string P(File); - if (QuoteNextArg) { - if (QuoteNextArg == 1) - OS << '"'; - --QuoteNextArg; - } - } - OS << '\n'; - } else { - const JobList *Jobs = cast<JobList>(&J); - for (JobList::const_iterator - it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it) - PrintDiagnosticJob(OS, **it); - } -} + // FIXME: Why are we trying to remove files that we have not created? For + // example we should only try to remove a temporary assembly file if + // "clang -cc1" succeed in writing it. Was this a workaround for when + // clang was writing directly to a .s file and sometimes leaving it behind + // during a failure? -bool Compilation::CleanupFile(const char *File, bool IssueErrors) const { - llvm::sys::Path P(File); - std::string Error; + // FIXME: If this is necessary, we can still try to split + // llvm::sys::fs::remove into a removeFile and a removeDir and avoid the + // duplicated stat from is_regular_file. // Don't try to remove files which we don't have write access to (but may be // able to remove), or non-regular files. Underlying tools may have // intentionally not overwritten them. - if (!P.canWrite() || !P.isRegularFile()) + if (!llvm::sys::fs::can_write(File) || !llvm::sys::fs::is_regular_file(File)) return true; - if (P.eraseFromDisk(false, &Error)) { - // Failure is only failure if the file exists and is "regular". There is - // a race condition here due to the limited interface of - // llvm::sys::Path, we want to know if the removal gave ENOENT. + if (llvm::error_code EC = llvm::sys::fs::remove(File)) { + // Failure is only failure if the file exists and is "regular". We checked + // for it being regular before, and llvm::sys::fs::remove ignores ENOENT, + // so we don't need to check again. - // FIXME: Grumble, P.exists() is broken. PR3837. - struct stat buf; - if (::stat(P.c_str(), &buf) == 0 ? (buf.st_mode & S_IFMT) == S_IFREG : - (errno != ENOENT)) { - if (IssueErrors) - getDriver().Diag(clang::diag::err_drv_unable_to_remove_file) - << Error; - return false; - } + if (IssueErrors) + getDriver().Diag(clang::diag::err_drv_unable_to_remove_file) + << EC.message(); + return false; } return true; } @@ -254,13 +128,7 @@ bool Compilation::CleanupFileMap(const ArgStringMap &Files, int Compilation::ExecuteCommand(const Command &C, const Command *&FailingCommand) const { - llvm::sys::Path Prog(C.getExecutable()); - const char **Argv = new const char*[C.getArguments().size() + 2]; - Argv[0] = C.getExecutable(); - std::copy(C.getArguments().begin(), C.getArguments().end(), Argv+1); - Argv[C.getArguments().size() + 1] = 0; - - if ((getDriver().CCCEcho || getDriver().CCPrintOptions || + if ((getDriver().CCPrintOptions || getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) { raw_ostream *OS = &llvm::errs(); @@ -268,9 +136,8 @@ int Compilation::ExecuteCommand(const Command &C, // output stream. if (getDriver().CCPrintOptions && getDriver().CCPrintOptionsFilename) { std::string Error; - OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename, - Error, - llvm::raw_fd_ostream::F_Append); + OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename, Error, + llvm::sys::fs::F_Append); if (!Error.empty()) { getDriver().Diag(clang::diag::err_drv_cc_print_options_failure) << Error; @@ -283,7 +150,7 @@ int Compilation::ExecuteCommand(const Command &C, if (getDriver().CCPrintOptions) *OS << "[Logging clang options]"; - PrintJob(*OS, C, "\n", /*Quote=*/getDriver().CCPrintOptions); + C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions); if (OS != &llvm::errs()) delete OS; @@ -291,11 +158,7 @@ int Compilation::ExecuteCommand(const Command &C, std::string Error; bool ExecutionFailed; - int Res = - llvm::sys::Program::ExecuteAndWait(Prog, Argv, - /*env*/0, Redirects, - /*secondsToWait*/0, /*memoryLimit*/0, - &Error, &ExecutionFailed); + int Res = C.Execute(Redirects, &Error, &ExecutionFailed); if (!Error.empty()) { assert(Res && "Error string set with 0 result code!"); getDriver().Diag(clang::diag::err_drv_command_failure) << Error; @@ -304,7 +167,6 @@ int Compilation::ExecuteCommand(const Command &C, if (Res) FailingCommand = &C; - delete[] Argv; return ExecutionFailed ? 1 : Res; } @@ -370,9 +232,10 @@ void Compilation::initCompilationForDiagnostics() { TranslatedArgs->ClaimAllArgs(); // Redirect stdout/stderr to /dev/null. - Redirects = new const llvm::sys::Path*[3](); - Redirects[1] = new const llvm::sys::Path(); - Redirects[2] = new const llvm::sys::Path(); + Redirects = new const StringRef*[3](); + Redirects[0] = 0; + Redirects[1] = new const StringRef(); + Redirects[2] = new const StringRef(); } StringRef Compilation::getSysRoot() const { diff --git a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp index b541a55..49beb93 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp @@ -12,19 +12,22 @@ #include "ToolChains.h" #include "clang/Basic/Version.h" #include "clang/Driver/Action.h" -#include "clang/Driver/Arg.h" -#include "clang/Driver/ArgList.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Job.h" -#include "clang/Driver/OptTable.h" -#include "clang/Driver/Option.h" #include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSet.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/OptTable.h" +#include "llvm/Option/Option.h" +#include "llvm/Option/OptSpecifier.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" @@ -40,20 +43,21 @@ using namespace clang::driver; using namespace clang; +using namespace llvm::opt; Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple, StringRef DefaultImageName, DiagnosticsEngine &Diags) - : Opts(createDriverOptTable()), Diags(Diags), + : Opts(createDriverOptTable()), Diags(Diags), Mode(GCCMode), ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT), UseStdLib(true), DefaultTargetTriple(DefaultTargetTriple), DefaultImageName(DefaultImageName), DriverTitle("clang LLVM compiler"), CCPrintOptionsFilename(0), CCPrintHeadersFilename(0), - CCLogDiagnosticsFilename(0), CCCIsCXX(false), - CCCIsCPP(false),CCCEcho(false), CCCPrintBindings(false), - CCPrintOptions(false), CCPrintHeaders(false), CCLogDiagnostics(false), + CCLogDiagnosticsFilename(0), + CCCPrintBindings(false), + CCPrintHeaders(false), CCLogDiagnostics(false), CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true), CCCUsePCH(true), SuppressMissingInputWarning(false) { @@ -79,11 +83,43 @@ Driver::~Driver() { delete I->second; } +void Driver::ParseDriverMode(ArrayRef<const char *> Args) { + const std::string OptName = + getOpts().getOption(options::OPT_driver_mode).getPrefixedName(); + + for (size_t I = 0, E = Args.size(); I != E; ++I) { + const StringRef Arg = Args[I]; + if (!Arg.startswith(OptName)) + continue; + + const StringRef Value = Arg.drop_front(OptName.size()); + const unsigned M = llvm::StringSwitch<unsigned>(Value) + .Case("gcc", GCCMode) + .Case("g++", GXXMode) + .Case("cpp", CPPMode) + .Case("cl", CLMode) + .Default(~0U); + + if (M != ~0U) + Mode = static_cast<DriverMode>(M); + else + Diag(diag::err_drv_unsupported_option_argument) << OptName << Value; + } +} + InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) { llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); + + unsigned IncludedFlagsBitmask; + unsigned ExcludedFlagsBitmask; + llvm::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) = + getIncludeExcludeOptionFlagMasks(); + unsigned MissingArgIndex, MissingArgCount; InputArgList *Args = getOpts().ParseArgs(ArgList.begin(), ArgList.end(), - MissingArgIndex, MissingArgCount); + MissingArgIndex, MissingArgCount, + IncludedFlagsBitmask, + ExcludedFlagsBitmask); // Check for missing argument error. if (MissingArgCount) @@ -107,6 +143,11 @@ InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) { } } + for (arg_iterator it = Args->filtered_begin(options::OPT_UNKNOWN), + ie = Args->filtered_end(); it != ie; ++it) { + Diags.Report(diag::err_drv_unknown_argument) << (*it) ->getAsString(*Args); + } + return Args; } @@ -119,7 +160,7 @@ const { phases::ID FinalPhase; // -{E,M,MM} only run the preprocessor. - if (CCCIsCPP || + if (CCCIsCPP() || (PhaseArg = DAL.getLastArg(options::OPT_E)) || (PhaseArg = DAL.getLastArg(options::OPT_M, options::OPT_MM))) { FinalPhase = phases::Preprocess; @@ -150,6 +191,14 @@ const { return FinalPhase; } +static Arg* MakeInputArg(const DerivedArgList &Args, OptTable *Opts, + StringRef Value) { + Arg *A = new Arg(Opts->getOption(options::OPT_INPUT), Value, + Args.getBaseArgs().MakeIndex(Value), Value.data()); + A->claim(); + return A; +} + DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { DerivedArgList *DAL = new DerivedArgList(Args); @@ -215,6 +264,14 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { } } + // Pick up inputs via the -- option. + if (A->getOption().matches(options::OPT__DASH_DASH)) { + A->claim(); + for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) + DAL->append(MakeInputArg(*DAL, Opts, A->getValue(i))); + continue; + } + DAL->append(*it); } @@ -241,16 +298,20 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { StringRef CompilerPath = env; while (!CompilerPath.empty()) { std::pair<StringRef, StringRef> Split - = CompilerPath.split(llvm::sys::PathSeparator); + = CompilerPath.split(llvm::sys::EnvPathSeparator); PrefixDirs.push_back(Split.first); CompilerPath = Split.second; } } + // We look for the driver mode option early, because the mode can affect + // how other options are parsed. + ParseDriverMode(ArgList.slice(1)); + // FIXME: What are we going to do with -V and -b? // FIXME: This stuff needs to go into the Compilation, not the driver. - bool CCCPrintOptions, CCCPrintActions; + bool CCCPrintActions; InputArgList *Args = ParseArgStrings(ArgList.slice(1)); @@ -266,17 +327,20 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // should be outside in the client; the parts that aren't should have proper // options, either by introducing new ones or by overloading gcc ones like -V // or -b. - CCCPrintOptions = Args->hasArg(options::OPT_ccc_print_options); CCCPrintActions = Args->hasArg(options::OPT_ccc_print_phases); CCCPrintBindings = Args->hasArg(options::OPT_ccc_print_bindings); - CCCIsCXX = Args->hasArg(options::OPT_ccc_cxx) || CCCIsCXX; - CCCEcho = Args->hasArg(options::OPT_ccc_echo); if (const Arg *A = Args->getLastArg(options::OPT_ccc_gcc_name)) CCCGenericGCCName = A->getValue(); CCCUsePCH = Args->hasFlag(options::OPT_ccc_pch_is_pch, options::OPT_ccc_pch_is_pth); // FIXME: DefaultTargetTriple is used by the target-prefixed calls to as/ld // and getToolChain is const. + if (IsCLMode()) { + // clang-cl targets Win32. + llvm::Triple T(DefaultTargetTriple); + T.setOSName(llvm::Triple::getOSTypeName(llvm::Triple::Win32)); + DefaultTargetTriple = T.str(); + } if (const Arg *A = Args->getLastArg(options::OPT_target)) DefaultTargetTriple = A->getValue(); if (const Arg *A = Args->getLastArg(options::OPT_ccc_install_dir)) @@ -289,6 +353,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { } if (const Arg *A = Args->getLastArg(options::OPT__sysroot_EQ)) SysRoot = A->getValue(); + if (const Arg *A = Args->getLastArg(options::OPT__dyld_prefix_EQ)) + DyldPrefix = A->getValue(); if (Args->hasArg(options::OPT_nostdlib)) UseStdLib = false; @@ -304,18 +370,12 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // The compilation takes ownership of Args. Compilation *C = new Compilation(*this, TC, Args, TranslatedArgs); - // FIXME: This behavior shouldn't be here. - if (CCCPrintOptions) { - PrintOptions(C->getInputArgs()); - return C; - } - if (!HandleImmediateArgs(*C)) return C; // Construct the list of inputs. InputList Inputs; - BuildInputs(C->getDefaultToolChain(), C->getArgs(), Inputs); + BuildInputs(C->getDefaultToolChain(), *TranslatedArgs, Inputs); // Construct the list of abstract actions to perform for this compilation. On // Darwin target OSes this uses the driver-driver and universal actions. @@ -357,7 +417,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C, "crash backtrace, preprocessed source, and associated run script."; // Suppress driver output and emit preprocessor output to temp file. - CCCIsCPP = true; + Mode = CPPMode; CCGenDiagnostics = true; C.getArgs().AddFlagArg(0, Opts->getOption(options::OPT_frewrite_includes)); @@ -365,11 +425,11 @@ void Driver::generateCompilationDiagnostics(Compilation &C, std::string Cmd; llvm::raw_string_ostream OS(Cmd); if (FailingCommand) - C.PrintDiagnosticJob(OS, *FailingCommand); + FailingCommand->Print(OS, "\n", /*Quote*/ false, /*CrashReport*/ true); else // Crash triggered by FORCE_CLANG_DIAGNOSTICS_CRASH, which doesn't have an // associated FailingCommand, so just pass all jobs. - C.PrintDiagnosticJob(OS, C.getJobs()); + C.getJobs().Print(OS, "\n", /*Quote*/ false, /*CrashReport*/ true); OS.flush(); // Keep track of whether we produce any errors while trying to produce @@ -463,9 +523,8 @@ void Driver::generateCompilationDiagnostics(Compilation &C, std::string Err; std::string Script = StringRef(*it).rsplit('.').first; Script += ".sh"; - llvm::raw_fd_ostream ScriptOS(Script.c_str(), Err, - llvm::raw_fd_ostream::F_Excl | - llvm::raw_fd_ostream::F_Binary); + llvm::raw_fd_ostream ScriptOS( + Script.c_str(), Err, llvm::sys::fs::F_Excl | llvm::sys::fs::F_Binary); if (!Err.empty()) { Diag(clang::diag::note_drv_command_failed_diag_msg) << "Error generating run script: " + Script + " " + Err; @@ -503,7 +562,7 @@ int Driver::ExecuteCompilation(const Compilation &C, SmallVectorImpl< std::pair<int, const Command *> > &FailingCommands) const { // Just print if -### was present. if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) { - C.PrintJob(llvm::errs(), C.getJobs(), "\n", true); + C.getJobs().Print(llvm::errs(), "\n", true); return 0; } @@ -559,28 +618,18 @@ int Driver::ExecuteCompilation(const Compilation &C, return 0; } -void Driver::PrintOptions(const ArgList &Args) const { - unsigned i = 0; - for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); - it != ie; ++it, ++i) { - Arg *A = *it; - llvm::errs() << "Option " << i << " - " - << "Name: \"" << A->getOption().getPrefixedName() << "\", " - << "Values: {"; - for (unsigned j = 0; j < A->getNumValues(); ++j) { - if (j) - llvm::errs() << ", "; - llvm::errs() << '"' << A->getValue(j) << '"'; - } - llvm::errs() << "}\n"; - } -} - void Driver::PrintHelp(bool ShowHidden) const { + unsigned IncludedFlagsBitmask; + unsigned ExcludedFlagsBitmask; + llvm::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) = + getIncludeExcludeOptionFlagMasks(); + + ExcludedFlagsBitmask |= options::NoDriverOption; + if (!ShowHidden) + ExcludedFlagsBitmask |= HelpHidden; + getOpts().PrintHelp(llvm::outs(), Name.c_str(), DriverTitle.c_str(), - /*Include*/0, - /*Exclude*/options::NoDriverOption | - (ShowHidden ? 0 : options::HelpHidden)); + IncludedFlagsBitmask, ExcludedFlagsBitmask); } void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const { @@ -649,6 +698,10 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { } const ToolChain &TC = C.getDefaultToolChain(); + + if (C.getArgs().hasArg(options::OPT_v)) + TC.printVerboseInfo(llvm::errs()); + if (C.getArgs().hasArg(options::OPT_print_search_dirs)) { llvm::outs() << "programs: ="; for (ToolChain::path_list::const_iterator it = TC.getProgramPaths().begin(), @@ -707,6 +760,10 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { case llvm::Triple::ppc64: llvm::outs() << "ppc64;@m64" << "\n"; break; + + case llvm::Triple::ppc64le: + llvm::outs() << "ppc64le;@m64" << "\n"; + break; } return false; } @@ -729,6 +786,10 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { case llvm::Triple::ppc64: llvm::outs() << "ppc64" << "\n"; break; + + case llvm::Triple::ppc64le: + llvm::outs() << "ppc64le" << "\n"; + break; } return false; } @@ -790,7 +851,7 @@ static bool ContainsCompileOrAssembleAction(const Action *A) { } void Driver::BuildUniversalActions(const ToolChain &TC, - const DerivedArgList &Args, + DerivedArgList &Args, const InputList &BAInputs, ActionList &Actions) const { llvm::PrettyStackTraceString CrashInfo("Building universal build actions"); @@ -885,6 +946,33 @@ void Driver::BuildUniversalActions(const ToolChain &TC, } } +/// \brief Check that the file referenced by Value exists. If it doesn't, +/// issue a diagnostic and return false. +static bool DiagnoseInputExistance(const Driver &D, const DerivedArgList &Args, + StringRef Value) { + if (!D.getCheckInputsExist()) + return true; + + // stdin always exists. + if (Value == "-") + return true; + + SmallString<64> Path(Value); + if (Arg *WorkDir = Args.getLastArg(options::OPT_working_directory)) { + if (!llvm::sys::path::is_absolute(Path.str())) { + SmallString<64> Directory(WorkDir->getValue()); + llvm::sys::path::append(Directory, Value); + Path.assign(Directory); + } + } + + if (llvm::sys::fs::exists(Twine(Path))) + return true; + + D.Diag(clang::diag::err_drv_no_such_file) << Path.str(); + return false; +} + // Construct a the list of inputs and their types. void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args, InputList &Inputs) const { @@ -894,6 +982,31 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args, types::ID InputType = types::TY_Nothing; Arg *InputTypeArg = 0; + // The last /TC or /TP option sets the input type to C or C++ globally. + if (Arg *TCTP = Args.getLastArg(options::OPT__SLASH_TC, + options::OPT__SLASH_TP)) { + InputTypeArg = TCTP; + InputType = TCTP->getOption().matches(options::OPT__SLASH_TC) + ? types::TY_C : types::TY_CXX; + + arg_iterator it = Args.filtered_begin(options::OPT__SLASH_TC, + options::OPT__SLASH_TP); + const arg_iterator ie = Args.filtered_end(); + Arg *Previous = *it++; + bool ShowNote = false; + while (it != ie) { + Diag(clang::diag::warn_drv_overriding_flag_option) + << Previous->getSpelling() << (*it)->getSpelling(); + Previous = *it++; + ShowNote = true; + } + if (ShowNote) + Diag(clang::diag::note_drv_t_option_is_global); + + // No driver mode exposes -x and /TC or /TP; we don't support mixing them. + assert(!Args.hasArg(options::OPT_x) && "-x and /TC or /TP is not allowed"); + } + for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { Arg *A = *it; @@ -915,7 +1028,7 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args, // // Otherwise emit an error but still use a valid type to avoid // spurious errors (e.g., no inputs). - if (!Args.hasArgNoClaim(options::OPT_E) && !CCCIsCPP) + if (!Args.hasArgNoClaim(options::OPT_E) && !CCCIsCPP()) Diag(clang::diag::err_drv_unknown_stdin_type); Ty = types::TY_C; } else { @@ -927,7 +1040,7 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args, Ty = TC.LookupTypeForExtension(Ext + 1); if (Ty == types::TY_INVALID) { - if (CCCIsCPP) + if (CCCIsCPP()) Ty = types::TY_C; else Ty = types::TY_Object; @@ -935,7 +1048,7 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args, // If the driver is invoked as C++ compiler (like clang++ or c++) it // should autodetect some input files as C++ for g++ compatibility. - if (CCCIsCXX) { + if (CCCIsCXX()) { types::ID OldTy = Ty; Ty = types::lookupCXXTypeForCType(Ty); @@ -962,25 +1075,23 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args, Ty = InputType; } - // Check that the file exists, if enabled. - if (CheckInputsExist && memcmp(Value, "-", 2) != 0) { - SmallString<64> Path(Value); - if (Arg *WorkDir = Args.getLastArg(options::OPT_working_directory)) { - if (!llvm::sys::path::is_absolute(Path.str())) { - SmallString<64> Directory(WorkDir->getValue()); - llvm::sys::path::append(Directory, Value); - Path.assign(Directory); - } - } - - bool exists = false; - if (llvm::sys::fs::exists(Path.c_str(), exists) || !exists) - Diag(clang::diag::err_drv_no_such_file) << Path.str(); - else - Inputs.push_back(std::make_pair(Ty, A)); - } else + if (DiagnoseInputExistance(*this, Args, Value)) Inputs.push_back(std::make_pair(Ty, A)); + } else if (A->getOption().matches(options::OPT__SLASH_Tc)) { + StringRef Value = A->getValue(); + if (DiagnoseInputExistance(*this, Args, Value)) { + Arg *InputArg = MakeInputArg(Args, Opts, A->getValue()); + Inputs.push_back(std::make_pair(types::TY_C, InputArg)); + } + A->claim(); + } else if (A->getOption().matches(options::OPT__SLASH_Tp)) { + StringRef Value = A->getValue(); + if (DiagnoseInputExistance(*this, Args, Value)) { + Arg *InputArg = MakeInputArg(Args, Opts, A->getValue()); + Inputs.push_back(std::make_pair(types::TY_CXX, InputArg)); + } + A->claim(); } else if (A->getOption().hasFlag(options::LinkerInput)) { // Just treat as object type, we could make a special type for this if // necessary. @@ -1000,17 +1111,15 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args, } } } - if (CCCIsCPP && Inputs.empty()) { + if (CCCIsCPP() && Inputs.empty()) { // If called as standalone preprocessor, stdin is processed // if no other input is present. - unsigned Index = Args.getBaseArgs().MakeIndex("-"); - Arg *A = Opts->ParseOneArg(Args, Index); - A->claim(); + Arg *A = MakeInputArg(Args, Opts, "-"); Inputs.push_back(std::make_pair(types::TY_C, A)); } } -void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args, +void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args, const InputList &Inputs, ActionList &Actions) const { llvm::PrettyStackTraceString CrashInfo("Building compilation actions"); @@ -1022,11 +1131,50 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args, Arg *FinalPhaseArg; phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg); + if (FinalPhase == phases::Link && Args.hasArg(options::OPT_emit_llvm)) { + Diag(clang::diag::err_drv_emit_llvm_link); + } + // Reject -Z* at the top level, these options should never have been exposed // by gcc. if (Arg *A = Args.getLastArg(options::OPT_Z_Joined)) Diag(clang::diag::err_drv_use_of_Z_option) << A->getAsString(Args); + // Diagnose misuse of /Fo. + if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fo)) { + StringRef V = A->getValue(); + if (V.empty()) { + // It has to have a value. + Diag(clang::diag::err_drv_missing_argument) << A->getSpelling() << 1; + Args.eraseArg(options::OPT__SLASH_Fo); + } else if (Inputs.size() > 1 && !llvm::sys::path::is_separator(V.back())) { + // Check whether /Fo tries to name an output file for multiple inputs. + Diag(clang::diag::err_drv_out_file_argument_with_multiple_sources) + << A->getSpelling() << V; + Args.eraseArg(options::OPT__SLASH_Fo); + } + } + + // Diagnose misuse of /Fa. + if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fa)) { + StringRef V = A->getValue(); + if (Inputs.size() > 1 && !llvm::sys::path::is_separator(V.back())) { + // Check whether /Fa tries to name an asm file for multiple inputs. + Diag(clang::diag::err_drv_out_file_argument_with_multiple_sources) + << A->getSpelling() << V; + Args.eraseArg(options::OPT__SLASH_Fa); + } + } + + // Diagnose misuse of /Fe. + if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fe)) { + if (A->getValue()[0] == '\0') { + // It has to have a value. + Diag(clang::diag::err_drv_missing_argument) << A->getSpelling() << 1; + Args.eraseArg(options::OPT__SLASH_Fe); + } + } + // Construct the actions to perform. ActionList LinkerInputs; ActionList SplitInputs; @@ -1051,7 +1199,7 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args, // Special case when final phase determined by binary name, rather than // by a command-line argument with a corresponding Arg. - if (CCCIsCPP) + if (CCCIsCPP()) Diag(clang::diag::warn_drv_input_file_unused_by_cpp) << InputArg->getAsString(Args) << getPhaseName(InitialPhase); @@ -1075,7 +1223,7 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args, // Build the pipeline for this file. OwningPtr<Action> Current(new InputAction(*InputArg, InputType)); - for (llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases>::iterator + for (SmallVectorImpl<phases::ID>::iterator i = PL.begin(), e = PL.end(); i != e; ++i) { phases::ID Phase = *i; @@ -1113,8 +1261,13 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args, // If we are linking, claim any options which are obviously only used for // compilation. - if (FinalPhase == phases::Link && PL.size() == 1) + if (FinalPhase == phases::Link && PL.size() == 1) { Args.ClaimAllArgs(options::OPT_CompileOnly_Group); + Args.ClaimAllArgs(options::OPT_cl_compile_Group); + } + + // Claim ignored clang-cl options. + Args.ClaimAllArgs(options::OPT_cl_ignored_Group); } Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, @@ -1165,6 +1318,10 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, types::ID Output = Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC; return new CompileJobAction(Input, Output); + } else if (Args.hasArg(options::OPT_emit_llvm)) { + types::ID Output = + Args.hasArg(options::OPT_S) ? types::TY_LLVM_IR : types::TY_LLVM_BC; + return new CompileJobAction(Input, Output); } else { return new CompileJobAction(Input, types::TY_PP_Asm); } @@ -1177,15 +1334,9 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, } bool Driver::IsUsingLTO(const ArgList &Args) const { - // Check for -emit-llvm or -flto. - if (Args.hasArg(options::OPT_emit_llvm) || - Args.hasFlag(options::OPT_flto, options::OPT_fno_lto, false)) + if (Args.hasFlag(options::OPT_flto, options::OPT_fno_lto, false)) return true; - // Check for -O4. - if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) - return A->getOption().matches(options::OPT_O4); - return false; } @@ -1256,6 +1407,9 @@ void Driver::BuildJobs(Compilation &C) const { // Claim -### here. (void) C.getArgs().hasArg(options::OPT__HASH_HASH_HASH); + // Claim --driver-mode, it was handled earlier. + (void) C.getArgs().hasArg(options::OPT_driver_mode); + for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end(); it != ie; ++it) { Arg *A = *it; @@ -1302,6 +1456,8 @@ static const Tool *SelectToolForJob(Compilation &C, const ToolChain *TC, if (TC->useIntegratedAs() && !C.getArgs().hasArg(options::OPT_save_temps) && + !C.getArgs().hasArg(options::OPT__SLASH_FA) && + !C.getArgs().hasArg(options::OPT__SLASH_Fa) && isa<AssembleJobAction>(JA) && Inputs->size() == 1 && isa<CompileJobAction>(*Inputs->begin())) { const Tool *Compiler = @@ -1424,6 +1580,38 @@ void Driver::BuildJobsForAction(Compilation &C, } } +/// \brief Create output filename based on ArgValue, which could either be a +/// full filename, filename without extension, or a directory. If ArgValue +/// does not provide a filename, then use BaseName, and use the extension +/// suitable for FileType. +static const char *MakeCLOutputFilename(const ArgList &Args, StringRef ArgValue, + StringRef BaseName, types::ID FileType) { + SmallString<128> Filename = ArgValue; + + if (ArgValue.empty()) { + // If the argument is empty, output to BaseName in the current dir. + Filename = BaseName; + } else if (llvm::sys::path::is_separator(Filename.back())) { + // If the argument is a directory, output to BaseName in that dir. + llvm::sys::path::append(Filename, BaseName); + } + + if (!llvm::sys::path::has_extension(ArgValue)) { + // If the argument didn't provide an extension, then set it. + const char *Extension = types::getTypeTempSuffix(FileType, true); + + if (FileType == types::TY_Image && + Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd)) { + // The output file is a dll. + Extension = "dll"; + } + + llvm::sys::path::replace_extension(Filename, Extension); + } + + return Args.MakeArgString(Filename.c_str()); +} + const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, const char *BaseInput, @@ -1443,13 +1631,26 @@ const char *Driver::GetNamedOutputPath(Compilation &C, (isa<PreprocessJobAction>(JA) || JA.getType() == types::TY_ModuleFile)) return "-"; + // Is this the assembly listing for /FA? + if (JA.getType() == types::TY_PP_Asm && + (C.getArgs().hasArg(options::OPT__SLASH_FA) || + C.getArgs().hasArg(options::OPT__SLASH_Fa))) { + // Use /Fa and the input filename to determine the asm file name. + StringRef BaseName = llvm::sys::path::filename(BaseInput); + StringRef FaValue = C.getArgs().getLastArgValue(options::OPT__SLASH_Fa); + return C.addResultFile(MakeCLOutputFilename(C.getArgs(), FaValue, BaseName, + JA.getType()), &JA); + } + // Output to a temporary file? - if ((!AtTopLevel && !C.getArgs().hasArg(options::OPT_save_temps)) || + if ((!AtTopLevel && !C.getArgs().hasArg(options::OPT_save_temps) && + !C.getArgs().hasArg(options::OPT__SLASH_Fo)) || CCGenDiagnostics) { StringRef Name = llvm::sys::path::filename(BaseInput); std::pair<StringRef, StringRef> Split = Name.split('.'); std::string TmpName = - GetTemporaryPath(Split.first, types::getTypeTempSuffix(JA.getType())); + GetTemporaryPath(Split.first, + types::getTypeTempSuffix(JA.getType(), IsCLMode())); return C.addTempFile(C.getArgs().MakeArgString(TmpName.c_str())); } @@ -1464,8 +1665,25 @@ const char *Driver::GetNamedOutputPath(Compilation &C, // Determine what the derived output name should be. const char *NamedOutput; - if (JA.getType() == types::TY_Image) { - if (MultipleArchs && BoundArch) { + + if (JA.getType() == types::TY_Object && + C.getArgs().hasArg(options::OPT__SLASH_Fo)) { + // The /Fo flag decides the object filename. + StringRef Val = C.getArgs().getLastArg(options::OPT__SLASH_Fo)->getValue(); + NamedOutput = MakeCLOutputFilename(C.getArgs(), Val, BaseName, + types::TY_Object); + } else if (JA.getType() == types::TY_Image && + C.getArgs().hasArg(options::OPT__SLASH_Fe)) { + // The /Fe flag names the linked file. + StringRef Val = C.getArgs().getLastArg(options::OPT__SLASH_Fe)->getValue(); + NamedOutput = MakeCLOutputFilename(C.getArgs(), Val, BaseName, + types::TY_Image); + } else if (JA.getType() == types::TY_Image) { + if (IsCLMode()) { + // clang-cl uses BaseName for the executable name. + NamedOutput = MakeCLOutputFilename(C.getArgs(), "", BaseName, + types::TY_Image); + } else if (MultipleArchs && BoundArch) { SmallString<128> Output(DefaultImageName.c_str()); Output += "-"; Output.append(BoundArch); @@ -1473,7 +1691,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C, } else NamedOutput = DefaultImageName.c_str(); } else { - const char *Suffix = types::getTypeTempSuffix(JA.getType()); + const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode()); assert(Suffix && "All types used for output should have a suffix."); std::string::size_type End = std::string::npos; @@ -1504,7 +1722,8 @@ const char *Driver::GetNamedOutputPath(Compilation &C, StringRef Name = llvm::sys::path::filename(BaseInput); std::pair<StringRef, StringRef> Split = Name.split('.'); std::string TmpName = - GetTemporaryPath(Split.first, types::getTypeTempSuffix(JA.getType())); + GetTemporaryPath(Split.first, + types::getTypeTempSuffix(JA.getType(), IsCLMode())); return C.addTempFile(C.getArgs().MakeArgString(TmpName.c_str())); } } @@ -1532,17 +1751,15 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const { continue; if (Dir[0] == '=') Dir = SysRoot + Dir.substr(1); - llvm::sys::Path P(Dir); - P.appendComponent(Name); - bool Exists; - if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) + SmallString<128> P(Dir); + llvm::sys::path::append(P, Name); + if (llvm::sys::fs::exists(Twine(P))) return P.str(); } - llvm::sys::Path P(ResourceDir); - P.appendComponent(Name); - bool Exists; - if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) + SmallString<128> P(ResourceDir); + llvm::sys::path::append(P, Name); + if (llvm::sys::fs::exists(Twine(P))) return P.str(); const ToolChain::path_list &List = TC.getFilePaths(); @@ -1553,10 +1770,9 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const { continue; if (Dir[0] == '=') Dir = SysRoot + Dir.substr(1); - llvm::sys::Path P(Dir); - P.appendComponent(Name); - bool Exists; - if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) + SmallString<128> P(Dir); + llvm::sys::path::append(P, Name); + if (llvm::sys::fs::exists(Twine(P))) return P.str(); } @@ -1571,69 +1787,58 @@ std::string Driver::GetProgramPath(const char *Name, // attempting to use this prefix when looking for program paths. for (Driver::prefix_list::const_iterator it = PrefixDirs.begin(), ie = PrefixDirs.end(); it != ie; ++it) { - bool IsDirectory; - if (!llvm::sys::fs::is_directory(*it, IsDirectory) && IsDirectory) { - llvm::sys::Path P(*it); - P.appendComponent(TargetSpecificExecutable); - if (P.canExecute()) return P.str(); - P.eraseComponent(); - P.appendComponent(Name); - if (P.canExecute()) return P.str(); + if (llvm::sys::fs::is_directory(*it)) { + SmallString<128> P(*it); + llvm::sys::path::append(P, TargetSpecificExecutable); + if (llvm::sys::fs::can_execute(Twine(P))) + return P.str(); + llvm::sys::path::remove_filename(P); + llvm::sys::path::append(P, Name); + if (llvm::sys::fs::can_execute(Twine(P))) + return P.str(); } else { - llvm::sys::Path P(*it + Name); - if (P.canExecute()) return P.str(); + SmallString<128> P(*it + Name); + if (llvm::sys::fs::can_execute(Twine(P))) + return P.str(); } } const ToolChain::path_list &List = TC.getProgramPaths(); for (ToolChain::path_list::const_iterator it = List.begin(), ie = List.end(); it != ie; ++it) { - llvm::sys::Path P(*it); - P.appendComponent(TargetSpecificExecutable); - if (P.canExecute()) return P.str(); - P.eraseComponent(); - P.appendComponent(Name); - if (P.canExecute()) return P.str(); + SmallString<128> P(*it); + llvm::sys::path::append(P, TargetSpecificExecutable); + if (llvm::sys::fs::can_execute(Twine(P))) + return P.str(); + llvm::sys::path::remove_filename(P); + llvm::sys::path::append(P, Name); + if (llvm::sys::fs::can_execute(Twine(P))) + return P.str(); } // If all else failed, search the path. - llvm::sys::Path - P(llvm::sys::Program::FindProgramByName(TargetSpecificExecutable)); + std::string P(llvm::sys::FindProgramByName(TargetSpecificExecutable)); if (!P.empty()) - return P.str(); + return P; - P = llvm::sys::Path(llvm::sys::Program::FindProgramByName(Name)); + P = llvm::sys::FindProgramByName(Name); if (!P.empty()) - return P.str(); + return P; return Name; } std::string Driver::GetTemporaryPath(StringRef Prefix, const char *Suffix) const { - // FIXME: This is lame; sys::Path should provide this function (in particular, - // it should know how to find the temporary files dir). - std::string Error; - const char *TmpDir = ::getenv("TMPDIR"); - if (!TmpDir) - TmpDir = ::getenv("TEMP"); - if (!TmpDir) - TmpDir = ::getenv("TMP"); - if (!TmpDir) - TmpDir = "/tmp"; - llvm::sys::Path P(TmpDir); - P.appendComponent(Prefix); - if (P.makeUnique(false, &Error)) { - Diag(clang::diag::err_unable_to_make_temp) << Error; + SmallString<128> Path; + llvm::error_code EC = + llvm::sys::fs::createTemporaryFile(Prefix, Suffix, Path); + if (EC) { + Diag(clang::diag::err_unable_to_make_temp) << EC.message(); return ""; } - // FIXME: Grumble, makeUnique sometimes leaves the file around!? PR3837. - P.eraseFromDisk(false, 0); - - if (Suffix) - P.appendSuffix(Suffix); - return P.str(); + return Path.str(); } /// \brief Compute target triple from args. @@ -1772,6 +1977,10 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, TC = new toolchains::Hexagon_TC(*this, Target, Args); break; } + if (Target.getArch() == llvm::Triple::xcore) { + TC = new toolchains::XCore(*this, Target, Args); + break; + } TC = new toolchains::Generic_GCC(*this, Target, Args); break; } @@ -1831,3 +2040,18 @@ bool Driver::GetReleaseVersion(const char *Str, unsigned &Major, HadExtra = true; return true; } + +std::pair<unsigned, unsigned> Driver::getIncludeExcludeOptionFlagMasks() const { + unsigned IncludedFlagsBitmask = 0; + unsigned ExcludedFlagsBitmask = options::NoDriverOption; + + if (Mode == CLMode) { + // Include CL and Core options. + IncludedFlagsBitmask |= options::CLOption; + IncludedFlagsBitmask |= options::CoreOption; + } else { + ExcludedFlagsBitmask |= options::CLOption; + } + + return std::make_pair(IncludedFlagsBitmask, ExcludedFlagsBitmask); +} diff --git a/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp b/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp index 3925b8a..6ff1cba 100644 --- a/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp @@ -8,26 +8,25 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Options.h" -#include "clang/Driver/OptTable.h" -#include "clang/Driver/Option.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Option/OptTable.h" +#include "llvm/Option/Option.h" using namespace clang::driver; using namespace clang::driver::options; +using namespace llvm::opt; -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) +#define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE; #include "clang/Driver/Options.inc" -#undef OPTION #undef PREFIX static const OptTable::Info InfoTable[] = { -#define PREFIX(NAME, VALUE) -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ HELPTEXT, METAVAR) \ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \ - FLAGS, OPT_##GROUP, OPT_##ALIAS }, + FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS }, #include "clang/Driver/Options.inc" +#undef OPTION }; namespace { @@ -35,7 +34,7 @@ namespace { class DriverOptTable : public OptTable { public: DriverOptTable() - : OptTable(InfoTable, sizeof(InfoTable) / sizeof(InfoTable[0])) {} + : OptTable(InfoTable, llvm::array_lengthof(InfoTable)) {} }; } diff --git a/contrib/llvm/tools/clang/lib/Driver/InputInfo.h b/contrib/llvm/tools/clang/lib/Driver/InputInfo.h index a243d32..4eedd22 100644 --- a/contrib/llvm/tools/clang/lib/Driver/InputInfo.h +++ b/contrib/llvm/tools/clang/lib/Driver/InputInfo.h @@ -10,8 +10,8 @@ #ifndef CLANG_LIB_DRIVER_INPUTINFO_H_ #define CLANG_LIB_DRIVER_INPUTINFO_H_ -#include "clang/Driver/Arg.h" #include "clang/Driver/Types.h" +#include "llvm/Option/Arg.h" #include <cassert> #include <string> @@ -35,7 +35,7 @@ class InputInfo { union { const char *Filename; - const Arg *InputArg; + const llvm::opt::Arg *InputArg; } Data; Class Kind; types::ID Type; @@ -50,8 +50,9 @@ public: : Kind(Filename), Type(_Type), BaseInput(_BaseInput) { Data.Filename = _Filename; } - InputInfo(const Arg *_InputArg, types::ID _Type, const char *_BaseInput) - : Kind(InputArg), Type(_Type), BaseInput(_BaseInput) { + InputInfo(const llvm::opt::Arg *_InputArg, types::ID _Type, + const char *_BaseInput) + : Kind(InputArg), Type(_Type), BaseInput(_BaseInput) { Data.InputArg = _InputArg; } @@ -65,7 +66,7 @@ public: assert(isFilename() && "Invalid accessor."); return Data.Filename; } - const Arg &getInputArg() const { + const llvm::opt::Arg &getInputArg() const { assert(isInputArg() && "Invalid accessor."); return *Data.InputArg; } diff --git a/contrib/llvm/tools/clang/lib/Driver/Job.cpp b/contrib/llvm/tools/clang/lib/Driver/Job.cpp index 8c46705..ee68e6f 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Job.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Job.cpp @@ -9,18 +9,158 @@ #include "clang/Driver/Job.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/raw_ostream.h" #include <cassert> using namespace clang::driver; +using llvm::raw_ostream; +using llvm::StringRef; Job::~Job() {} -void Command::anchor() {} - Command::Command(const Action &_Source, const Tool &_Creator, - const char *_Executable, const ArgStringList &_Arguments) - : Job(CommandClass), Source(_Source), Creator(_Creator), - Executable(_Executable), Arguments(_Arguments) -{ + const char *_Executable, + const ArgStringList &_Arguments) + : Job(CommandClass), Source(_Source), Creator(_Creator), + Executable(_Executable), Arguments(_Arguments) {} + +static int skipArgs(const char *Flag) { + // These flags are all of the form -Flag <Arg> and are treated as two + // arguments. Therefore, we need to skip the flag and the next argument. + bool Res = llvm::StringSwitch<bool>(Flag) + .Cases("-I", "-MF", "-MT", "-MQ", true) + .Cases("-o", "-coverage-file", "-dependency-file", true) + .Cases("-fdebug-compilation-dir", "-idirafter", true) + .Cases("-include", "-include-pch", "-internal-isystem", true) + .Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true) + .Cases("-iwithprefixbefore", "-isysroot", "-isystem", "-iquote", true) + .Cases("-resource-dir", "-serialize-diagnostic-file", true) + .Case("-dwarf-debug-flags", true) + .Default(false); + + // Match found. + if (Res) + return 2; + + // The remaining flags are treated as a single argument. + + // These flags are all of the form -Flag and have no second argument. + Res = llvm::StringSwitch<bool>(Flag) + .Cases("-M", "-MM", "-MG", "-MP", "-MD", true) + .Case("-MMD", true) + .Default(false); + + // Match found. + if (Res) + return 1; + + // These flags are treated as a single argument (e.g., -F<Dir>). + StringRef FlagRef(Flag); + if (FlagRef.startswith("-F") || FlagRef.startswith("-I")) + return 1; + + return 0; +} + +static bool quoteNextArg(const char *flag) { + return llvm::StringSwitch<bool>(flag) + .Case("-D", true) + .Default(false); +} + +static void PrintArg(raw_ostream &OS, const char *Arg, bool Quote) { + const bool Escape = std::strpbrk(Arg, "\"\\$"); + + if (!Quote && !Escape) { + OS << Arg; + return; + } + + // Quote and escape. This isn't really complete, but good enough. + OS << '"'; + while (const char c = *Arg++) { + if (c == '"' || c == '\\' || c == '$') + OS << '\\'; + OS << c; + } + OS << '"'; +} + +void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, + bool CrashReport) const { + OS << " \"" << Executable << '"'; + + for (size_t i = 0, e = Arguments.size(); i < e; ++i) { + const char *const Arg = Arguments[i]; + + if (CrashReport) { + if (int Skip = skipArgs(Arg)) { + i += Skip - 1; + continue; + } + } + + OS << ' '; + PrintArg(OS, Arg, Quote); + + if (CrashReport && quoteNextArg(Arg) && i + 1 < e) { + OS << ' '; + PrintArg(OS, Arguments[++i], true); + } + } + OS << Terminator; +} + +int Command::Execute(const StringRef **Redirects, std::string *ErrMsg, + bool *ExecutionFailed) const { + SmallVector<const char*, 128> Argv; + Argv.push_back(Executable); + for (size_t i = 0, e = Arguments.size(); i != e; ++i) + Argv.push_back(Arguments[i]); + Argv.push_back(0); + + return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ 0, + Redirects, /*secondsToWait*/ 0, + /*memoryLimit*/ 0, ErrMsg, ExecutionFailed); +} + +FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_, + const char *Executable_, + const ArgStringList &Arguments_, + Command *Fallback_) + : Command(Source_, Creator_, Executable_, Arguments_), Fallback(Fallback_) { +} + +void FallbackCommand::Print(raw_ostream &OS, const char *Terminator, + bool Quote, bool CrashReport) const { + Command::Print(OS, "", Quote, CrashReport); + OS << " ||"; + Fallback->Print(OS, Terminator, Quote, CrashReport); +} + +static bool ShouldFallback(int ExitCode) { + // FIXME: We really just want to fall back for internal errors, such + // as when some symbol cannot be mangled, when we should be able to + // parse something but can't, etc. + return ExitCode != 0; +} + +int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg, + bool *ExecutionFailed) const { + int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed); + if (!ShouldFallback(PrimaryStatus)) + return PrimaryStatus; + + // Clear ExecutionFailed and ErrMsg before falling back. + if (ErrMsg) + ErrMsg->clear(); + if (ExecutionFailed) + *ExecutionFailed = false; + + int SecondaryStatus = Fallback->Execute(Redirects, ErrMsg, ExecutionFailed); + return SecondaryStatus; } JobList::JobList() : Job(JobListClass) {} @@ -30,11 +170,12 @@ JobList::~JobList() { delete *it; } -void JobList::clear() { - DeleteContainerPointers(Jobs); +void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote, + bool CrashReport) const { + for (const_iterator it = begin(), ie = end(); it != ie; ++it) + (*it)->Print(OS, Terminator, Quote, CrashReport); } -void Job::addCommand(Command *C) { - cast<JobList>(this)->addJob(C); +void JobList::clear() { + DeleteContainerPointers(Jobs); } - diff --git a/contrib/llvm/tools/clang/lib/Driver/OptTable.cpp b/contrib/llvm/tools/clang/lib/Driver/OptTable.cpp deleted file mode 100644 index 20214a6..0000000 --- a/contrib/llvm/tools/clang/lib/Driver/OptTable.cpp +++ /dev/null @@ -1,388 +0,0 @@ -//===--- OptTable.cpp - Option Table Implementation -----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "clang/Driver/OptTable.h" -#include "clang/Driver/Arg.h" -#include "clang/Driver/ArgList.h" -#include "clang/Driver/Option.h" -#include "clang/Driver/Options.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <map> -using namespace clang::driver; -using namespace clang::driver::options; -using namespace clang; - -// Ordering on Info. The ordering is *almost* lexicographic, with two -// exceptions. First, '\0' comes at the end of the alphabet instead of -// the beginning (thus options precede any other options which prefix -// them). Second, for options with the same name, the less permissive -// version should come first; a Flag option should precede a Joined -// option, for example. - -static int StrCmpOptionName(const char *A, const char *B) { - char a = *A, b = *B; - while (a == b) { - if (a == '\0') - return 0; - - a = *++A; - b = *++B; - } - - if (a == '\0') // A is a prefix of B. - return 1; - if (b == '\0') // B is a prefix of A. - return -1; - - // Otherwise lexicographic. - return (a < b) ? -1 : 1; -} - -namespace clang { -namespace driver { -static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) { - if (&A == &B) - return false; - - if (int N = StrCmpOptionName(A.Name, B.Name)) - return N == -1; - - for (const char * const *APre = A.Prefixes, - * const *BPre = B.Prefixes; - *APre != 0 && *BPre != 0; ++APre, ++BPre) { - if (int N = StrCmpOptionName(*APre, *BPre)) - return N == -1; - } - - // Names are the same, check that classes are in order; exactly one - // should be joined, and it should succeed the other. - assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) && - "Unexpected classes for options with same name."); - return B.Kind == Option::JoinedClass; -} - -// Support lower_bound between info and an option name. -static inline bool operator<(const OptTable::Info &I, const char *Name) { - return StrCmpOptionName(I.Name, Name) == -1; -} -static inline bool operator<(const char *Name, const OptTable::Info &I) { - return StrCmpOptionName(Name, I.Name) == -1; -} -} -} - -// - -OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {} - -// - -OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos) - : OptionInfos(_OptionInfos), - NumOptionInfos(_NumOptionInfos), - TheInputOptionID(0), - TheUnknownOptionID(0), - FirstSearchableIndex(0) -{ - // Explicitly zero initialize the error to work around a bug in array - // value-initialization on MinGW with gcc 4.3.5. - - // Find start of normal options. - for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { - unsigned Kind = getInfo(i + 1).Kind; - if (Kind == Option::InputClass) { - assert(!TheInputOptionID && "Cannot have multiple input options!"); - TheInputOptionID = getInfo(i + 1).ID; - } else if (Kind == Option::UnknownClass) { - assert(!TheUnknownOptionID && "Cannot have multiple unknown options!"); - TheUnknownOptionID = getInfo(i + 1).ID; - } else if (Kind != Option::GroupClass) { - FirstSearchableIndex = i; - break; - } - } - assert(FirstSearchableIndex != 0 && "No searchable options?"); - -#ifndef NDEBUG - // Check that everything after the first searchable option is a - // regular option class. - for (unsigned i = FirstSearchableIndex, e = getNumOptions(); i != e; ++i) { - Option::OptionClass Kind = (Option::OptionClass) getInfo(i + 1).Kind; - assert((Kind != Option::InputClass && Kind != Option::UnknownClass && - Kind != Option::GroupClass) && - "Special options should be defined first!"); - } - - // Check that options are in order. - for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) { - if (!(getInfo(i) < getInfo(i + 1))) { - getOption(i).dump(); - getOption(i + 1).dump(); - llvm_unreachable("Options are not in order!"); - } - } -#endif - - // Build prefixes. - for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) { - if (const char *const *P = getInfo(i).Prefixes) { - for (; *P != 0; ++P) { - PrefixesUnion.insert(*P); - } - } - } - - // Build prefix chars. - for (llvm::StringSet<>::const_iterator I = PrefixesUnion.begin(), - E = PrefixesUnion.end(); I != E; ++I) { - StringRef Prefix = I->getKey(); - for (StringRef::const_iterator C = Prefix.begin(), CE = Prefix.end(); - C != CE; ++C) - if (std::find(PrefixChars.begin(), PrefixChars.end(), *C) - == PrefixChars.end()) - PrefixChars.push_back(*C); - } -} - -OptTable::~OptTable() { -} - -const Option OptTable::getOption(OptSpecifier Opt) const { - unsigned id = Opt.getID(); - if (id == 0) - return Option(0, 0); - assert((unsigned) (id - 1) < getNumOptions() && "Invalid ID."); - return Option(&getInfo(id), this); -} - -static bool isInput(const llvm::StringSet<> &Prefixes, StringRef Arg) { - if (Arg == "-") - return true; - for (llvm::StringSet<>::const_iterator I = Prefixes.begin(), - E = Prefixes.end(); I != E; ++I) - if (Arg.startswith(I->getKey())) - return false; - return true; -} - -/// \returns Matched size. 0 means no match. -static unsigned matchOption(const OptTable::Info *I, StringRef Str) { - for (const char * const *Pre = I->Prefixes; *Pre != 0; ++Pre) { - StringRef Prefix(*Pre); - if (Str.startswith(Prefix) && Str.substr(Prefix.size()).startswith(I->Name)) - return Prefix.size() + StringRef(I->Name).size(); - } - return 0; -} - -Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index) const { - unsigned Prev = Index; - const char *Str = Args.getArgString(Index); - - // Anything that doesn't start with PrefixesUnion is an input, as is '-' - // itself. - if (isInput(PrefixesUnion, Str)) - return new Arg(getOption(TheInputOptionID), Str, Index++, Str); - - const Info *Start = OptionInfos + FirstSearchableIndex; - const Info *End = OptionInfos + getNumOptions(); - StringRef Name = StringRef(Str).ltrim(PrefixChars); - - // Search for the first next option which could be a prefix. - Start = std::lower_bound(Start, End, Name.data()); - - // Options are stored in sorted order, with '\0' at the end of the - // alphabet. Since the only options which can accept a string must - // prefix it, we iteratively search for the next option which could - // be a prefix. - // - // FIXME: This is searching much more than necessary, but I am - // blanking on the simplest way to make it fast. We can solve this - // problem when we move to TableGen. - for (; Start != End; ++Start) { - unsigned ArgSize = 0; - // Scan for first option which is a proper prefix. - for (; Start != End; ++Start) - if ((ArgSize = matchOption(Start, Str))) - break; - if (Start == End) - break; - - // See if this option matches. - if (Arg *A = Option(Start, this).accept(Args, Index, ArgSize)) - return A; - - // Otherwise, see if this argument was missing values. - if (Prev != Index) - return 0; - } - - return new Arg(getOption(TheUnknownOptionID), Str, Index++, Str); -} - -InputArgList *OptTable::ParseArgs(const char* const *ArgBegin, - const char* const *ArgEnd, - unsigned &MissingArgIndex, - unsigned &MissingArgCount) const { - InputArgList *Args = new InputArgList(ArgBegin, ArgEnd); - - // FIXME: Handle '@' args (or at least error on them). - - MissingArgIndex = MissingArgCount = 0; - unsigned Index = 0, End = ArgEnd - ArgBegin; - while (Index < End) { - // Ignore empty arguments (other things may still take them as arguments). - if (Args->getArgString(Index)[0] == '\0') { - ++Index; - continue; - } - - unsigned Prev = Index; - Arg *A = ParseOneArg(*Args, Index); - assert(Index > Prev && "Parser failed to consume argument."); - - // Check for missing argument error. - if (!A) { - assert(Index >= End && "Unexpected parser error."); - assert(Index - Prev - 1 && "No missing arguments!"); - MissingArgIndex = Prev; - MissingArgCount = Index - Prev - 1; - break; - } - - Args->append(A); - } - - return Args; -} - -static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) { - const Option O = Opts.getOption(Id); - std::string Name = O.getPrefixedName(); - - // Add metavar, if used. - switch (O.getKind()) { - case Option::GroupClass: case Option::InputClass: case Option::UnknownClass: - llvm_unreachable("Invalid option with help text."); - - case Option::MultiArgClass: - llvm_unreachable("Cannot print metavar for this kind of option."); - - case Option::FlagClass: - break; - - case Option::SeparateClass: case Option::JoinedOrSeparateClass: - Name += ' '; - // FALLTHROUGH - case Option::JoinedClass: case Option::CommaJoinedClass: - case Option::JoinedAndSeparateClass: - if (const char *MetaVarName = Opts.getOptionMetaVar(Id)) - Name += MetaVarName; - else - Name += "<value>"; - break; - } - - return Name; -} - -static void PrintHelpOptionList(raw_ostream &OS, StringRef Title, - std::vector<std::pair<std::string, - const char*> > &OptionHelp) { - OS << Title << ":\n"; - - // Find the maximum option length. - unsigned OptionFieldWidth = 0; - for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) { - // Skip titles. - if (!OptionHelp[i].second) - continue; - - // Limit the amount of padding we are willing to give up for alignment. - unsigned Length = OptionHelp[i].first.size(); - if (Length <= 23) - OptionFieldWidth = std::max(OptionFieldWidth, Length); - } - - const unsigned InitialPad = 2; - for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) { - const std::string &Option = OptionHelp[i].first; - int Pad = OptionFieldWidth - int(Option.size()); - OS.indent(InitialPad) << Option; - - // Break on long option names. - if (Pad < 0) { - OS << "\n"; - Pad = OptionFieldWidth + InitialPad; - } - OS.indent(Pad + 1) << OptionHelp[i].second << '\n'; - } -} - -static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) { - unsigned GroupID = Opts.getOptionGroupID(Id); - - // If not in a group, return the default help group. - if (!GroupID) - return "OPTIONS"; - - // Abuse the help text of the option groups to store the "help group" - // name. - // - // FIXME: Split out option groups. - if (const char *GroupHelp = Opts.getOptionHelpText(GroupID)) - return GroupHelp; - - // Otherwise keep looking. - return getOptionHelpGroup(Opts, GroupID); -} - -void OptTable::PrintHelp(raw_ostream &OS, const char *Name, - const char *Title, unsigned short FlagsToInclude, - unsigned short FlagsToExclude) const { - OS << "OVERVIEW: " << Title << "\n"; - OS << '\n'; - OS << "USAGE: " << Name << " [options] <inputs>\n"; - OS << '\n'; - - // Render help text into a map of group-name to a list of (option, help) - // pairs. - typedef std::map<std::string, - std::vector<std::pair<std::string, const char*> > > helpmap_ty; - helpmap_ty GroupedOptionHelp; - - for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { - unsigned Id = i + 1; - - // FIXME: Split out option groups. - if (getOptionKind(Id) == Option::GroupClass) - continue; - - if ((FlagsToInclude && !(getInfo(Id).Flags & FlagsToInclude)) || - getInfo(Id).Flags & FlagsToExclude) - continue; - - if (const char *Text = getOptionHelpText(Id)) { - const char *HelpGroup = getOptionHelpGroup(*this, Id); - const std::string &OptName = getOptionHelpName(*this, Id); - GroupedOptionHelp[HelpGroup].push_back(std::make_pair(OptName, Text)); - } - } - - for (helpmap_ty::iterator it = GroupedOptionHelp .begin(), - ie = GroupedOptionHelp.end(); it != ie; ++it) { - if (it != GroupedOptionHelp .begin()) - OS << "\n"; - PrintHelpOptionList(OS, it->first, it->second); - } - - OS.flush(); -} diff --git a/contrib/llvm/tools/clang/lib/Driver/Option.cpp b/contrib/llvm/tools/clang/lib/Driver/Option.cpp deleted file mode 100644 index dbc61ea..0000000 --- a/contrib/llvm/tools/clang/lib/Driver/Option.cpp +++ /dev/null @@ -1,200 +0,0 @@ -//===--- Option.cpp - Abstract Driver Options -----------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "clang/Driver/Option.h" -#include "clang/Driver/Arg.h" -#include "clang/Driver/ArgList.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <cassert> -using namespace clang::driver; - -Option::Option(const OptTable::Info *info, const OptTable *owner) - : Info(info), Owner(owner) { - - // Multi-level aliases are not supported, and alias options cannot - // have groups. This just simplifies option tracking, it is not an - // inherent limitation. - assert((!Info || !getAlias().isValid() || (!getAlias().getAlias().isValid() && - !getGroup().isValid())) && - "Multi-level aliases and aliases with groups are unsupported."); -} - -Option::~Option() { -} - -void Option::dump() const { - llvm::errs() << "<"; - switch (getKind()) { -#define P(N) case N: llvm::errs() << #N; break - P(GroupClass); - P(InputClass); - P(UnknownClass); - P(FlagClass); - P(JoinedClass); - P(SeparateClass); - P(CommaJoinedClass); - P(MultiArgClass); - P(JoinedOrSeparateClass); - P(JoinedAndSeparateClass); -#undef P - } - - llvm::errs() << " Prefixes:["; - for (const char * const *Pre = Info->Prefixes; *Pre != 0; ++Pre) { - llvm::errs() << '"' << *Pre << (*(Pre + 1) == 0 ? "\"" : "\", "); - } - llvm::errs() << ']'; - - llvm::errs() << " Name:\"" << getName() << '"'; - - const Option Group = getGroup(); - if (Group.isValid()) { - llvm::errs() << " Group:"; - Group.dump(); - } - - const Option Alias = getAlias(); - if (Alias.isValid()) { - llvm::errs() << " Alias:"; - Alias.dump(); - } - - if (getKind() == MultiArgClass) - llvm::errs() << " NumArgs:" << getNumArgs(); - - llvm::errs() << ">\n"; -} - -bool Option::matches(OptSpecifier Opt) const { - // Aliases are never considered in matching, look through them. - const Option Alias = getAlias(); - if (Alias.isValid()) - return Alias.matches(Opt); - - // Check exact match. - if (getID() == Opt.getID()) - return true; - - const Option Group = getGroup(); - if (Group.isValid()) - return Group.matches(Opt); - return false; -} - -Arg *Option::accept(const ArgList &Args, - unsigned &Index, - unsigned ArgSize) const { - const Option &UnaliasedOption = getUnaliasedOption(); - StringRef Spelling; - // If the option was an alias, get the spelling from the unaliased one. - if (getID() == UnaliasedOption.getID()) { - Spelling = StringRef(Args.getArgString(Index), ArgSize); - } else { - Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) + - Twine(UnaliasedOption.getName())); - } - - switch (getKind()) { - case FlagClass: - if (ArgSize != strlen(Args.getArgString(Index))) - return 0; - - return new Arg(UnaliasedOption, Spelling, Index++); - case JoinedClass: { - const char *Value = Args.getArgString(Index) + ArgSize; - return new Arg(UnaliasedOption, Spelling, Index++, Value); - } - case CommaJoinedClass: { - // Always matches. - const char *Str = Args.getArgString(Index) + ArgSize; - Arg *A = new Arg(UnaliasedOption, Spelling, Index++); - - // Parse out the comma separated values. - const char *Prev = Str; - for (;; ++Str) { - char c = *Str; - - if (!c || c == ',') { - if (Prev != Str) { - char *Value = new char[Str - Prev + 1]; - memcpy(Value, Prev, Str - Prev); - Value[Str - Prev] = '\0'; - A->getValues().push_back(Value); - } - - if (!c) - break; - - Prev = Str + 1; - } - } - A->setOwnsValues(true); - - return A; - } - case SeparateClass: - // Matches iff this is an exact match. - // FIXME: Avoid strlen. - if (ArgSize != strlen(Args.getArgString(Index))) - return 0; - - Index += 2; - if (Index > Args.getNumInputArgStrings()) - return 0; - - return new Arg(UnaliasedOption, Spelling, - Index - 2, Args.getArgString(Index - 1)); - case MultiArgClass: { - // Matches iff this is an exact match. - // FIXME: Avoid strlen. - if (ArgSize != strlen(Args.getArgString(Index))) - return 0; - - Index += 1 + getNumArgs(); - if (Index > Args.getNumInputArgStrings()) - return 0; - - Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(), - Args.getArgString(Index - getNumArgs())); - for (unsigned i = 1; i != getNumArgs(); ++i) - A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i)); - return A; - } - case JoinedOrSeparateClass: { - // If this is not an exact match, it is a joined arg. - // FIXME: Avoid strlen. - if (ArgSize != strlen(Args.getArgString(Index))) { - const char *Value = Args.getArgString(Index) + ArgSize; - return new Arg(*this, Spelling, Index++, Value); - } - - // Otherwise it must be separate. - Index += 2; - if (Index > Args.getNumInputArgStrings()) - return 0; - - return new Arg(UnaliasedOption, Spelling, - Index - 2, Args.getArgString(Index - 1)); - } - case JoinedAndSeparateClass: - // Always matches. - Index += 2; - if (Index > Args.getNumInputArgStrings()) - return 0; - - return new Arg(UnaliasedOption, Spelling, Index - 2, - Args.getArgString(Index - 2) + ArgSize, - Args.getArgString(Index - 1)); - default: - llvm_unreachable("Invalid option kind!"); - } -} diff --git a/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp b/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp new file mode 100644 index 0000000..43209f0 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp @@ -0,0 +1,389 @@ +//===--- SanitizerArgs.cpp - Arguments for sanitizer tools ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "clang/Driver/SanitizerArgs.h" + +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/ToolChain.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Transforms/Utils/SpecialCaseList.h" + +using namespace clang::driver; +using namespace llvm::opt; + +void SanitizerArgs::clear() { + Kind = 0; + BlacklistFile = ""; + MsanTrackOrigins = false; + AsanZeroBaseShadow = false; + UbsanTrapOnError = false; +} + +SanitizerArgs::SanitizerArgs() { + clear(); +} + +SanitizerArgs::SanitizerArgs(const ToolChain &TC, + const llvm::opt::ArgList &Args) { + clear(); + unsigned AllAdd = 0; // All kinds of sanitizers that were turned on + // at least once (possibly, disabled further). + unsigned AllRemove = 0; // During the loop below, the accumulated set of + // sanitizers disabled by the current sanitizer + // argument or any argument after it. + unsigned DiagnosedKinds = 0; // All Kinds we have diagnosed up to now. + // Used to deduplicate diagnostics. + const Driver &D = TC.getDriver(); + for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); + I != E; ++I) { + unsigned Add, Remove; + if (!parse(D, Args, *I, Add, Remove, true)) + continue; + (*I)->claim(); + + AllAdd |= expandGroups(Add); + AllRemove |= expandGroups(Remove); + + // Avoid diagnosing any sanitizer which is disabled later. + Add &= ~AllRemove; + // At this point we have not expanded groups, so any unsupported sanitizers + // in Add are those which have been explicitly enabled. Diagnose them. + Add = filterUnsupportedKinds(TC, Add, Args, *I, /*DiagnoseErrors=*/true, + DiagnosedKinds); + Add = expandGroups(Add); + // Group expansion may have enabled a sanitizer which is disabled later. + Add &= ~AllRemove; + // Silently discard any unsupported sanitizers implicitly enabled through + // group expansion. + Add = filterUnsupportedKinds(TC, Add, Args, *I, /*DiagnoseErrors=*/false, + DiagnosedKinds); + + Kind |= Add; + } + + UbsanTrapOnError = + Args.hasArg(options::OPT_fcatch_undefined_behavior) || + Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, + options::OPT_fno_sanitize_undefined_trap_on_error, false); + + if (Args.hasArg(options::OPT_fcatch_undefined_behavior) && + !Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, + options::OPT_fno_sanitize_undefined_trap_on_error, true)) { + D.Diag(diag::err_drv_argument_not_allowed_with) + << "-fcatch-undefined-behavior" + << "-fno-sanitize-undefined-trap-on-error"; + } + + // Warn about undefined sanitizer options that require runtime support. + if (UbsanTrapOnError && notAllowedWithTrap()) { + if (Args.hasArg(options::OPT_fcatch_undefined_behavior)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << lastArgumentForKind(D, Args, NotAllowedWithTrap) + << "-fcatch-undefined-behavior"; + else if (Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, + options::OPT_fno_sanitize_undefined_trap_on_error, + false)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << lastArgumentForKind(D, Args, NotAllowedWithTrap) + << "-fsanitize-undefined-trap-on-error"; + } + + // Only one runtime library can be used at once. + bool NeedsAsan = needsAsanRt(); + bool NeedsTsan = needsTsanRt(); + bool NeedsMsan = needsMsanRt(); + bool NeedsLsan = needsLeakDetection(); + if (NeedsAsan && NeedsTsan) + D.Diag(diag::err_drv_argument_not_allowed_with) + << lastArgumentForKind(D, Args, NeedsAsanRt) + << lastArgumentForKind(D, Args, NeedsTsanRt); + if (NeedsAsan && NeedsMsan) + D.Diag(diag::err_drv_argument_not_allowed_with) + << lastArgumentForKind(D, Args, NeedsAsanRt) + << lastArgumentForKind(D, Args, NeedsMsanRt); + if (NeedsTsan && NeedsMsan) + D.Diag(diag::err_drv_argument_not_allowed_with) + << lastArgumentForKind(D, Args, NeedsTsanRt) + << lastArgumentForKind(D, Args, NeedsMsanRt); + if (NeedsLsan && NeedsTsan) + D.Diag(diag::err_drv_argument_not_allowed_with) + << lastArgumentForKind(D, Args, NeedsLeakDetection) + << lastArgumentForKind(D, Args, NeedsTsanRt); + if (NeedsLsan && NeedsMsan) + D.Diag(diag::err_drv_argument_not_allowed_with) + << lastArgumentForKind(D, Args, NeedsLeakDetection) + << lastArgumentForKind(D, Args, NeedsMsanRt); + // FIXME: Currenly -fsanitize=leak is silently ignored in the presence of + // -fsanitize=address. Perhaps it should print an error, or perhaps + // -f(-no)sanitize=leak should change whether leak detection is enabled by + // default in ASan? + + // If -fsanitize contains extra features of ASan, it should also + // explicitly contain -fsanitize=address (probably, turned off later in the + // command line). + if ((Kind & AddressFull) != 0 && (AllAdd & Address) == 0) + D.Diag(diag::warn_drv_unused_sanitizer) + << lastArgumentForKind(D, Args, AddressFull) + << "-fsanitize=address"; + + // Parse -f(no-)sanitize-blacklist options. + if (Arg *BLArg = Args.getLastArg(options::OPT_fsanitize_blacklist, + options::OPT_fno_sanitize_blacklist)) { + if (BLArg->getOption().matches(options::OPT_fsanitize_blacklist)) { + std::string BLPath = BLArg->getValue(); + if (llvm::sys::fs::exists(BLPath)) { + // Validate the blacklist format. + std::string BLError; + llvm::OwningPtr<llvm::SpecialCaseList> SCL( + llvm::SpecialCaseList::create(BLPath, BLError)); + if (!SCL.get()) + D.Diag(diag::err_drv_malformed_sanitizer_blacklist) << BLError; + else + BlacklistFile = BLPath; + } else { + D.Diag(diag::err_drv_no_such_file) << BLPath; + } + } + } else { + // If no -fsanitize-blacklist option is specified, try to look up for + // blacklist in the resource directory. + std::string BLPath; + if (getDefaultBlacklistForKind(D, Kind, BLPath) && + llvm::sys::fs::exists(BLPath)) + BlacklistFile = BLPath; + } + + // Parse -f(no-)sanitize-memory-track-origins options. + if (NeedsMsan) + MsanTrackOrigins = + Args.hasFlag(options::OPT_fsanitize_memory_track_origins, + options::OPT_fno_sanitize_memory_track_origins, + /* Default */false); + + // Parse -f(no-)sanitize-address-zero-base-shadow options. + if (NeedsAsan) { + bool IsAndroid = (TC.getTriple().getEnvironment() == llvm::Triple::Android); + bool ZeroBaseShadowDefault = IsAndroid; + AsanZeroBaseShadow = + Args.hasFlag(options::OPT_fsanitize_address_zero_base_shadow, + options::OPT_fno_sanitize_address_zero_base_shadow, + ZeroBaseShadowDefault); + // Zero-base shadow is a requirement on Android. + if (IsAndroid && !AsanZeroBaseShadow) { + D.Diag(diag::err_drv_argument_not_allowed_with) + << "-fno-sanitize-address-zero-base-shadow" + << lastArgumentForKind(D, Args, Address); + } + } +} + +void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + if (!Kind) + return; + SmallString<256> SanitizeOpt("-fsanitize="); +#define SANITIZER(NAME, ID) \ + if (Kind & ID) \ + SanitizeOpt += NAME ","; +#include "clang/Basic/Sanitizers.def" + SanitizeOpt.pop_back(); + CmdArgs.push_back(Args.MakeArgString(SanitizeOpt)); + if (!BlacklistFile.empty()) { + SmallString<64> BlacklistOpt("-fsanitize-blacklist="); + BlacklistOpt += BlacklistFile; + CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); + } + + if (MsanTrackOrigins) + CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins")); + + if (AsanZeroBaseShadow) + CmdArgs.push_back( + Args.MakeArgString("-fsanitize-address-zero-base-shadow")); + + // Workaround for PR16386. + if (needsMsanRt()) + CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new")); +} + +unsigned SanitizerArgs::parse(const char *Value) { + unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value) +#define SANITIZER(NAME, ID) .Case(NAME, ID) +#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID##Group) +#include "clang/Basic/Sanitizers.def" + .Default(SanitizeKind()); + // Assume -fsanitize=address implies -fsanitize=init-order,use-after-return. + // FIXME: This should be either specified in Sanitizers.def, or go away when + // we get rid of "-fsanitize=init-order,use-after-return" flags at all. + if (ParsedKind & Address) + ParsedKind |= InitOrder | UseAfterReturn; + return ParsedKind; +} + +unsigned SanitizerArgs::expandGroups(unsigned Kinds) { +#define SANITIZER(NAME, ID) +#define SANITIZER_GROUP(NAME, ID, ALIAS) if (Kinds & ID##Group) Kinds |= ID; +#include "clang/Basic/Sanitizers.def" + return Kinds; +} + +void SanitizerArgs::filterUnsupportedMask(const ToolChain &TC, unsigned &Kinds, + unsigned Mask, + const llvm::opt::ArgList &Args, + const llvm::opt::Arg *A, + bool DiagnoseErrors, + unsigned &DiagnosedKinds) { + unsigned MaskedKinds = Kinds & Mask; + if (!MaskedKinds) + return; + Kinds &= ~Mask; + // Do we have new kinds to diagnose? + if (DiagnoseErrors && (DiagnosedKinds & MaskedKinds) != MaskedKinds) { + // Only diagnose the new kinds. + std::string Desc = + describeSanitizeArg(Args, A, MaskedKinds & ~DiagnosedKinds); + TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) + << Desc << TC.getTriple().str(); + DiagnosedKinds |= MaskedKinds; + } +} + +unsigned SanitizerArgs::filterUnsupportedKinds(const ToolChain &TC, + unsigned Kinds, + const llvm::opt::ArgList &Args, + const llvm::opt::Arg *A, + bool DiagnoseErrors, + unsigned &DiagnosedKinds) { + bool IsLinux = TC.getTriple().getOS() == llvm::Triple::Linux; + bool IsX86 = TC.getTriple().getArch() == llvm::Triple::x86; + bool IsX86_64 = TC.getTriple().getArch() == llvm::Triple::x86_64; + if (!(IsLinux && IsX86_64)) { + filterUnsupportedMask(TC, Kinds, Thread | Memory | DataFlow, Args, A, + DiagnoseErrors, DiagnosedKinds); + } + if (!(IsLinux && (IsX86 || IsX86_64))) { + filterUnsupportedMask(TC, Kinds, Function, Args, A, DiagnoseErrors, + DiagnosedKinds); + } + return Kinds; +} + +unsigned SanitizerArgs::parse(const Driver &D, const llvm::opt::Arg *A, + bool DiagnoseErrors) { + unsigned Kind = 0; + for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) { + if (unsigned K = parse(A->getValue(I))) + Kind |= K; + else if (DiagnoseErrors) + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << A->getValue(I); + } + return Kind; +} + +bool SanitizerArgs::parse(const Driver &D, const llvm::opt::ArgList &Args, + const llvm::opt::Arg *A, unsigned &Add, + unsigned &Remove, bool DiagnoseErrors) { + Add = 0; + Remove = 0; + const char *DeprecatedReplacement = 0; + if (A->getOption().matches(options::OPT_faddress_sanitizer)) { + Add = Address; + DeprecatedReplacement = "-fsanitize=address"; + } else if (A->getOption().matches(options::OPT_fno_address_sanitizer)) { + Remove = Address; + DeprecatedReplacement = "-fno-sanitize=address"; + } else if (A->getOption().matches(options::OPT_fthread_sanitizer)) { + Add = Thread; + DeprecatedReplacement = "-fsanitize=thread"; + } else if (A->getOption().matches(options::OPT_fno_thread_sanitizer)) { + Remove = Thread; + DeprecatedReplacement = "-fno-sanitize=thread"; + } else if (A->getOption().matches(options::OPT_fcatch_undefined_behavior)) { + Add = UndefinedTrap; + DeprecatedReplacement = + "-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error"; + } else if (A->getOption().matches(options::OPT_fbounds_checking) || + A->getOption().matches(options::OPT_fbounds_checking_EQ)) { + Add = LocalBounds; + DeprecatedReplacement = "-fsanitize=local-bounds"; + } else if (A->getOption().matches(options::OPT_fsanitize_EQ)) { + Add = parse(D, A, DiagnoseErrors); + } else if (A->getOption().matches(options::OPT_fno_sanitize_EQ)) { + Remove = parse(D, A, DiagnoseErrors); + } else { + // Flag is not relevant to sanitizers. + return false; + } + // If this is a deprecated synonym, produce a warning directing users + // towards the new spelling. + if (DeprecatedReplacement && DiagnoseErrors) + D.Diag(diag::warn_drv_deprecated_arg) + << A->getAsString(Args) << DeprecatedReplacement; + return true; +} + +std::string SanitizerArgs::lastArgumentForKind(const Driver &D, + const llvm::opt::ArgList &Args, + unsigned Kind) { + for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(), + E = Args.rend(); + I != E; ++I) { + unsigned Add, Remove; + if (parse(D, Args, *I, Add, Remove, false) && + (expandGroups(Add) & Kind)) + return describeSanitizeArg(Args, *I, Kind); + Kind &= ~Remove; + } + llvm_unreachable("arg list didn't provide expected value"); +} + +std::string SanitizerArgs::describeSanitizeArg(const llvm::opt::ArgList &Args, + const llvm::opt::Arg *A, + unsigned Mask) { + if (!A->getOption().matches(options::OPT_fsanitize_EQ)) + return A->getAsString(Args); + + std::string Sanitizers; + for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) { + if (expandGroups(parse(A->getValue(I))) & Mask) { + if (!Sanitizers.empty()) + Sanitizers += ","; + Sanitizers += A->getValue(I); + } + } + + assert(!Sanitizers.empty() && "arg didn't provide expected value"); + return "-fsanitize=" + Sanitizers; +} + +bool SanitizerArgs::getDefaultBlacklistForKind(const Driver &D, unsigned Kind, + std::string &BLPath) { + const char *BlacklistFile = 0; + if (Kind & NeedsAsanRt) + BlacklistFile = "asan_blacklist.txt"; + else if (Kind & NeedsMsanRt) + BlacklistFile = "msan_blacklist.txt"; + else if (Kind & NeedsTsanRt) + BlacklistFile = "tsan_blacklist.txt"; + else if (Kind & NeedsDfsanRt) + BlacklistFile = "dfsan_abilist.txt"; + + if (BlacklistFile) { + SmallString<64> Path(D.ResourceDir); + llvm::sys::path::append(Path, BlacklistFile); + BLPath = Path.str(); + return true; + } + return false; +} diff --git a/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.h b/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.h deleted file mode 100644 index 326d80d..0000000 --- a/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.h +++ /dev/null @@ -1,220 +0,0 @@ -//===--- SanitizerArgs.h - Arguments for sanitizer tools -------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef CLANG_LIB_DRIVER_SANITIZERARGS_H_ -#define CLANG_LIB_DRIVER_SANITIZERARGS_H_ - -#include "clang/Driver/Arg.h" -#include "clang/Driver/ArgList.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/DriverDiagnostic.h" -#include "clang/Driver/Options.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/Path.h" - -namespace clang { -namespace driver { - -class SanitizerArgs { - /// Assign ordinals to sanitizer flags. We'll use the ordinal values as - /// bit positions within \c Kind. - enum SanitizeOrdinal { -#define SANITIZER(NAME, ID) SO_##ID, -#include "clang/Basic/Sanitizers.def" - SO_Count - }; - - /// Bugs to catch at runtime. - enum SanitizeKind { -#define SANITIZER(NAME, ID) ID = 1 << SO_##ID, -#define SANITIZER_GROUP(NAME, ID, ALIAS) ID = ALIAS, -#include "clang/Basic/Sanitizers.def" - NeedsAsanRt = Address, - NeedsTsanRt = Thread, - NeedsMsanRt = Memory, - NeedsUbsanRt = Undefined | Integer, - NotAllowedWithTrap = Vptr, - HasZeroBaseShadow = Thread | Memory - }; - unsigned Kind; - std::string BlacklistFile; - bool MsanTrackOrigins; - bool AsanZeroBaseShadow; - bool UbsanTrapOnError; - - public: - SanitizerArgs() : Kind(0), BlacklistFile(""), MsanTrackOrigins(false), - AsanZeroBaseShadow(false), UbsanTrapOnError(false) {} - /// Parses the sanitizer arguments from an argument list. - SanitizerArgs(const ToolChain &TC, const ArgList &Args); - - bool needsAsanRt() const { return Kind & NeedsAsanRt; } - bool needsTsanRt() const { return Kind & NeedsTsanRt; } - bool needsMsanRt() const { return Kind & NeedsMsanRt; } - bool needsUbsanRt() const { - if (UbsanTrapOnError) - return false; - return Kind & NeedsUbsanRt; - } - - bool sanitizesVptr() const { return Kind & Vptr; } - bool notAllowedWithTrap() const { return Kind & NotAllowedWithTrap; } - bool hasZeroBaseShadow() const { - return (Kind & HasZeroBaseShadow) || AsanZeroBaseShadow; - } - - void addArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - if (!Kind) - return; - SmallString<256> SanitizeOpt("-fsanitize="); -#define SANITIZER(NAME, ID) \ - if (Kind & ID) \ - SanitizeOpt += NAME ","; -#include "clang/Basic/Sanitizers.def" - SanitizeOpt.pop_back(); - CmdArgs.push_back(Args.MakeArgString(SanitizeOpt)); - if (!BlacklistFile.empty()) { - SmallString<64> BlacklistOpt("-fsanitize-blacklist="); - BlacklistOpt += BlacklistFile; - CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); - } - - if (MsanTrackOrigins) - CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins")); - - if (AsanZeroBaseShadow) - CmdArgs.push_back(Args.MakeArgString( - "-fsanitize-address-zero-base-shadow")); - } - - private: - /// Parse a single value from a -fsanitize= or -fno-sanitize= value list. - /// Returns OR of members of the \c SanitizeKind enumeration, or \c 0 - /// if \p Value is not known. - static unsigned parse(const char *Value) { - unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value) -#define SANITIZER(NAME, ID) .Case(NAME, ID) -#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID) -#include "clang/Basic/Sanitizers.def" - .Default(SanitizeKind()); - // Assume -fsanitize=address implies -fsanitize=init-order. - // FIXME: This should be either specified in Sanitizers.def, or go away when - // we get rid of "-fsanitize=init-order" flag at all. - if (ParsedKind & Address) - ParsedKind |= InitOrder; - return ParsedKind; - } - - /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any - /// invalid components. - static unsigned parse(const Driver &D, const Arg *A, bool DiagnoseErrors) { - unsigned Kind = 0; - for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) { - if (unsigned K = parse(A->getValue(I))) - Kind |= K; - else if (DiagnoseErrors) - D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << A->getValue(I); - } - return Kind; - } - - /// Parse a single flag of the form -f[no]sanitize=, or - /// -f*-sanitizer. Sets the masks defining required change of Kind value. - /// Returns true if the flag was parsed successfully. - static bool parse(const Driver &D, const ArgList &Args, const Arg *A, - unsigned &Add, unsigned &Remove, bool DiagnoseErrors) { - Add = 0; - Remove = 0; - const char *DeprecatedReplacement = 0; - if (A->getOption().matches(options::OPT_faddress_sanitizer)) { - Add = Address; - DeprecatedReplacement = "-fsanitize=address"; - } else if (A->getOption().matches(options::OPT_fno_address_sanitizer)) { - Remove = Address; - DeprecatedReplacement = "-fno-sanitize=address"; - } else if (A->getOption().matches(options::OPT_fthread_sanitizer)) { - Add = Thread; - DeprecatedReplacement = "-fsanitize=thread"; - } else if (A->getOption().matches(options::OPT_fno_thread_sanitizer)) { - Remove = Thread; - DeprecatedReplacement = "-fno-sanitize=thread"; - } else if (A->getOption().matches(options::OPT_fcatch_undefined_behavior)) { - Add = UndefinedTrap; - DeprecatedReplacement = - "-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error"; - } else if (A->getOption().matches(options::OPT_fbounds_checking) || - A->getOption().matches(options::OPT_fbounds_checking_EQ)) { - Add = Bounds; - DeprecatedReplacement = "-fsanitize=bounds"; - } else if (A->getOption().matches(options::OPT_fsanitize_EQ)) { - Add = parse(D, A, DiagnoseErrors); - } else if (A->getOption().matches(options::OPT_fno_sanitize_EQ)) { - Remove = parse(D, A, DiagnoseErrors); - } else { - // Flag is not relevant to sanitizers. - return false; - } - // If this is a deprecated synonym, produce a warning directing users - // towards the new spelling. - if (DeprecatedReplacement && DiagnoseErrors) - D.Diag(diag::warn_drv_deprecated_arg) - << A->getAsString(Args) << DeprecatedReplacement; - return true; - } - - /// Produce an argument string from ArgList \p Args, which shows how it - /// provides a sanitizer kind in \p Mask. For example, the argument list - /// "-fsanitize=thread,vptr -faddress-sanitizer" with mask \c NeedsUbsanRt - /// would produce "-fsanitize=vptr". - static std::string lastArgumentForKind(const Driver &D, const ArgList &Args, - unsigned Kind) { - for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); - I != E; ++I) { - unsigned Add, Remove; - if (parse(D, Args, *I, Add, Remove, false) && - (Add & Kind)) - return describeSanitizeArg(Args, *I, Kind); - Kind &= ~Remove; - } - llvm_unreachable("arg list didn't provide expected value"); - } - - /// Produce an argument string from argument \p A, which shows how it provides - /// a value in \p Mask. For instance, the argument - /// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce - /// "-fsanitize=alignment". - static std::string describeSanitizeArg(const ArgList &Args, const Arg *A, - unsigned Mask) { - if (!A->getOption().matches(options::OPT_fsanitize_EQ)) - return A->getAsString(Args); - - for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) - if (parse(A->getValue(I)) & Mask) - return std::string("-fsanitize=") + A->getValue(I); - - llvm_unreachable("arg didn't provide expected value"); - } - - static bool getDefaultBlacklistForKind(const Driver &D, unsigned Kind, - std::string &BLPath) { - // For now, specify the default blacklist location for ASan only. - if (Kind & NeedsAsanRt) { - SmallString<64> Path(D.ResourceDir); - llvm::sys::path::append(Path, "asan_blacklist.txt"); - BLPath = Path.str(); - return true; - } - return false; - } -}; - -} // namespace driver -} // namespace clang - -#endif // CLANG_LIB_DRIVER_SANITIZERARGS_H_ diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp index 71f5393..efd3945 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp @@ -8,20 +8,22 @@ //===----------------------------------------------------------------------===// #include "Tools.h" -#include "clang/Driver/ToolChain.h" #include "clang/Basic/ObjCRuntime.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/Option.h" #include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "clang/Driver/ToolChain.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" using namespace clang::driver; using namespace clang; +using namespace llvm::opt; ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, const ArgList &A) @@ -41,6 +43,12 @@ bool ToolChain::useIntegratedAs() const { IsIntegratedAssemblerDefault()); } +const SanitizerArgs& ToolChain::getSanitizerArgs() const { + if (!SanitizerArguments.get()) + SanitizerArguments.reset(new SanitizerArgs(*this, Args)); + return *SanitizerArguments.get(); +} + std::string ToolChain::getDefaultUniversalArchName() const { // In universal driver terms, the arch name accepted by -arch isn't exactly // the same as the ones that appear in the triple. Roughly speaking, this is @@ -51,6 +59,8 @@ std::string ToolChain::getDefaultUniversalArchName() const { return "ppc"; case llvm::Triple::ppc64: return "ppc64"; + case llvm::Triple::ppc64le: + return "ppc64le"; default: return Triple.getArchName(); } @@ -173,11 +183,17 @@ static const char *getARMTargetCPU(const ArgList &Args, MArch = Triple.getArchName(); } - return llvm::StringSwitch<const char *>(MArch) + if (Triple.getOS() == llvm::Triple::NetBSD) { + if (MArch == "armv6") + return "arm1176jzf-s"; + } + + const char *result = llvm::StringSwitch<const char *>(MArch) .Cases("armv2", "armv2a","arm2") .Case("armv3", "arm6") .Case("armv3m", "arm7m") - .Cases("armv4", "armv4t", "arm7tdmi") + .Case("armv4", "strongarm") + .Case("armv4t", "arm7tdmi") .Cases("armv5", "armv5t", "arm10tdmi") .Cases("armv5e", "armv5te", "arm1026ejs") .Case("armv5tej", "arm926ej-s") @@ -193,11 +209,21 @@ static const char *getARMTargetCPU(const ArgList &Args, .Cases("armv7r", "armv7-r", "cortex-r4") .Cases("armv7m", "armv7-m", "cortex-m3") .Cases("armv7em", "armv7e-m", "cortex-m4") + .Cases("armv8", "armv8a", "armv8-a", "cortex-a53") .Case("ep9312", "ep9312") .Case("iwmmxt", "iwmmxt") .Case("xscale", "xscale") - // If all else failed, return the most base CPU LLVM supports. - .Default("arm7tdmi"); + // If all else failed, return the most base CPU with thumb interworking + // supported by LLVM. + .Default(0); + + if (result) + return result; + + return + Triple.getEnvironment() == llvm::Triple::GNUEABIHF + ? "arm1176jzf-s" + : "arm7tdmi"; } /// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular @@ -207,6 +233,7 @@ static const char *getARMTargetCPU(const ArgList &Args, // FIXME: tblgen this, or kill it! static const char *getLLVMArchSuffixForARM(StringRef CPU) { return llvm::StringSwitch<const char *>(CPU) + .Case("strongarm", "v4") .Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "v4t") .Cases("arm720t", "arm9", "arm9tdmi", "v4t") .Cases("arm920", "arm920t", "arm922t", "v4t") @@ -219,22 +246,37 @@ static const char *getLLVMArchSuffixForARM(StringRef CPU) { .Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6") .Cases("arm1156t2-s", "arm1156t2f-s", "v6t2") .Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7") - .Cases("cortex-a9", "cortex-a15", "v7") - .Case("cortex-r5", "v7r") + .Cases("cortex-a9", "cortex-a12", "cortex-a15", "v7") + .Cases("cortex-r4", "cortex-r5", "v7r") .Case("cortex-m0", "v6m") .Case("cortex-m3", "v7m") .Case("cortex-m4", "v7em") .Case("cortex-a9-mp", "v7f") .Case("swift", "v7s") + .Cases("cortex-a53", "cortex-a57", "v8") .Default(""); } -std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, +std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, types::ID InputType) const { switch (getTriple().getArch()) { default: return getTripleString(); + case llvm::Triple::x86_64: { + llvm::Triple Triple = getTriple(); + if (!Triple.isOSDarwin()) + return getTripleString(); + + if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) { + // x86_64h goes in the triple. Other -march options just use the + // vanilla triple we already have. + StringRef MArch = A->getValue(); + if (MArch == "x86_64h") + Triple.setArchName(MArch); + } + return Triple.getTriple(); + } case llvm::Triple::arm: case llvm::Triple::thumb: { // FIXME: Factor into subclasses. diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp index dbb69ac..8a47e76 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp @@ -8,27 +8,28 @@ //===----------------------------------------------------------------------===// #include "ToolChains.h" -#include "SanitizerArgs.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" -#include "clang/Driver/Arg.h" -#include "clang/Driver/ArgList.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" -#include "clang/Driver/OptTable.h" -#include "clang/Driver/Option.h" #include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/OptTable.h" +#include "llvm/Option/Option.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" +#include "llvm/Support/Program.h" // FIXME: This needs to be listed last until we fix the broken include guards // in these files and the LLVM config.h files. @@ -39,6 +40,7 @@ using namespace clang::driver; using namespace clang::driver::toolchains; using namespace clang; +using namespace llvm::opt; /// Darwin - Darwin tool chain for i386 and x86_64. @@ -122,7 +124,9 @@ static const char *GetArmArchForMCpu(StringRef Value) { .Case("xscale", "xscale") .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "arm1176jzf-s", "armv6") .Case("cortex-m0", "armv6m") - .Cases("cortex-a8", "cortex-r4", "cortex-a9", "cortex-a15", "armv7") + .Cases("cortex-a5", "cortex-a7", "cortex-a8", "armv7") + .Cases("cortex-a9", "cortex-a12", "cortex-a15", "armv7") + .Cases("cortex-r4", "cortex-r5", "armv7r") .Case("cortex-a9-mp", "armv7f") .Case("cortex-m3", "armv7m") .Case("cortex-m4", "armv7em") @@ -162,10 +166,18 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, if (!isTargetInitialized()) return Triple.getTriple(); - SmallString<16> Str; - Str += isTargetIPhoneOS() ? "ios" : "macosx"; - Str += getTargetVersion().getAsString(); - Triple.setOSName(Str); + if (Triple.getArchName() == "thumbv6m" || + Triple.getArchName() == "thumbv7m" || + Triple.getArchName() == "thumbv7em") { + // OS is ios or macosx unless it's the v6m or v7m. + Triple.setOS(llvm::Triple::Darwin); + Triple.setEnvironment(llvm::Triple::EABI); + } else { + SmallString<16> Str; + Str += isTargetIPhoneOS() ? "ios" : "macosx"; + Str += getTargetVersion().getAsString(); + Triple.setOSName(Str); + } return Triple.getTriple(); } @@ -217,39 +229,33 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CmdArgs.push_back("-force_load"); - llvm::sys::Path P(getDriver().ClangExecutable); - P.eraseComponent(); // 'clang' - P.eraseComponent(); // 'bin' - P.appendComponent("lib"); - P.appendComponent("arc"); - P.appendComponent("libarclite_"); - std::string s = P.str(); + SmallString<128> P(getDriver().ClangExecutable); + llvm::sys::path::remove_filename(P); // 'clang' + llvm::sys::path::remove_filename(P); // 'bin' + llvm::sys::path::append(P, "lib", "arc", "libarclite_"); // Mash in the platform. if (isTargetIOSSimulator()) - s += "iphonesimulator"; + P += "iphonesimulator"; else if (isTargetIPhoneOS()) - s += "iphoneos"; + P += "iphoneos"; else - s += "macosx"; - s += ".a"; + P += "macosx"; + P += ".a"; - CmdArgs.push_back(Args.MakeArgString(s)); + CmdArgs.push_back(Args.MakeArgString(P)); } void DarwinClang::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, const char *DarwinStaticLib, bool AlwaysLink) const { - llvm::sys::Path P(getDriver().ResourceDir); - P.appendComponent("lib"); - P.appendComponent("darwin"); - P.appendComponent(DarwinStaticLib); + SmallString<128> P(getDriver().ResourceDir); + llvm::sys::path::append(P, "lib", "darwin", DarwinStaticLib); // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build (unless // we explicitly force linking with this library). - bool Exists; - if (AlwaysLink || (!llvm::sys::fs::exists(P.str(), Exists) && Exists)) + if (AlwaysLink || llvm::sys::fs::exists(P.str())) CmdArgs.push_back(Args.MakeArgString(P.str())); } @@ -294,10 +300,11 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, } } - SanitizerArgs Sanitize(*this, Args); + const SanitizerArgs &Sanitize = getSanitizerArgs(); // Add Ubsan runtime library, if required. if (Sanitize.needsUbsanRt()) { + // FIXME: Move this check to SanitizerArgs::filterUnsupportedKinds. if (isTargetIPhoneOS()) { getDriver().Diag(diag::err_drv_clang_unsupported_per_platform) << "-fsanitize=undefined"; @@ -312,19 +319,27 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, // Add ASAN runtime library, if required. Dynamic libraries and bundles // should not be linked with the runtime library. if (Sanitize.needsAsanRt()) { + // FIXME: Move this check to SanitizerArgs::filterUnsupportedKinds. if (isTargetIPhoneOS() && !isTargetIOSSimulator()) { getDriver().Diag(diag::err_drv_clang_unsupported_per_platform) << "-fsanitize=address"; } else { - if (Args.hasArg(options::OPT_dynamiclib) || - Args.hasArg(options::OPT_bundle)) { - // Assume the binary will provide the ASan runtime. - } else { - AddLinkRuntimeLib(Args, CmdArgs, - "libclang_rt.asan_osx_dynamic.dylib", true); + if (!Args.hasArg(options::OPT_dynamiclib) && + !Args.hasArg(options::OPT_bundle)) { // The ASAN runtime library requires C++. AddCXXStdlibLibArgs(Args, CmdArgs); } + if (isTargetMacOS()) { + AddLinkRuntimeLib(Args, CmdArgs, + "libclang_rt.asan_osx_dynamic.dylib", + true); + } else { + if (isTargetIOSSimulator()) { + AddLinkRuntimeLib(Args, CmdArgs, + "libclang_rt.asan_iossim_dynamic.dylib", + true); + } + } } } @@ -376,8 +391,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { // isysroot. if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { // Warn if the path does not exist. - bool Exists; - if (llvm::sys::fs::exists(A->getValue(), Exists) || !Exists) + if (!llvm::sys::fs::exists(A->getValue())) getDriver().Diag(clang::diag::warn_missing_sysroot) << A->getValue(); } else { if (char *env = ::getenv("SDKROOT")) { @@ -538,17 +552,14 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, // explicitly if we can't see an obvious -lstdc++ candidate. // Check in the sysroot first. - bool Exists; if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { - llvm::sys::Path P(A->getValue()); - P.appendComponent("usr"); - P.appendComponent("lib"); - P.appendComponent("libstdc++.dylib"); - - if (llvm::sys::fs::exists(P.str(), Exists) || !Exists) { - P.eraseComponent(); - P.appendComponent("libstdc++.6.dylib"); - if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) { + SmallString<128> P(A->getValue()); + llvm::sys::path::append(P, "usr", "lib", "libstdc++.dylib"); + + if (!llvm::sys::fs::exists(P.str())) { + llvm::sys::path::remove_filename(P); + llvm::sys::path::append(P, "libstdc++.6.dylib"); + if (llvm::sys::fs::exists(P.str())) { CmdArgs.push_back(Args.MakeArgString(P.str())); return; } @@ -558,8 +569,8 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, // Otherwise, look in the root. // FIXME: This should be removed someday when we don't have to care about // 10.6 and earlier, where /usr/lib/libstdc++.dylib does not exist. - if ((llvm::sys::fs::exists("/usr/lib/libstdc++.dylib", Exists) || !Exists)&& - (!llvm::sys::fs::exists("/usr/lib/libstdc++.6.dylib", Exists) && Exists)){ + if (!llvm::sys::fs::exists("/usr/lib/libstdc++.dylib") && + llvm::sys::fs::exists("/usr/lib/libstdc++.6.dylib")) { CmdArgs.push_back("/usr/lib/libstdc++.6.dylib"); return; } @@ -578,22 +589,20 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args, // instead of the gcc-provided one (which is also incidentally // only present in the gcc lib dir, which makes it hard to find). - llvm::sys::Path P(getDriver().ResourceDir); - P.appendComponent("lib"); - P.appendComponent("darwin"); + SmallString<128> P(getDriver().ResourceDir); + llvm::sys::path::append(P, "lib", "darwin"); // Use the newer cc_kext for iOS ARM after 6.0. if (!isTargetIPhoneOS() || isTargetIOSSimulator() || !isIPhoneOSVersionLT(6, 0)) { - P.appendComponent("libclang_rt.cc_kext.a"); + llvm::sys::path::append(P, "libclang_rt.cc_kext.a"); } else { - P.appendComponent("libclang_rt.cc_kext_ios5.a"); + llvm::sys::path::append(P, "libclang_rt.cc_kext_ios5.a"); } // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build. - bool Exists; - if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) + if (llvm::sys::fs::exists(P.str())) CmdArgs.push_back(Args.MakeArgString(P.str())); } @@ -762,7 +771,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, else if (Name == "ppc970") DAL->AddJoinedArg(0, MCpu, "970"); - else if (Name == "ppc64") + else if (Name == "ppc64" || Name == "ppc64le") DAL->AddFlagArg(0, Opts.getOption(options::OPT_m64)); else if (Name == "i386") @@ -784,6 +793,10 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, else if (Name == "x86_64") DAL->AddFlagArg(0, Opts.getOption(options::OPT_m64)); + else if (Name == "x86_64h") { + DAL->AddFlagArg(0, Opts.getOption(options::OPT_m64)); + DAL->AddJoinedArg(0, MArch, "x86_64h"); + } else if (Name == "arm") DAL->AddJoinedArg(0, MArch, "armv4t"); @@ -839,6 +852,12 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, } } + // Default to use libc++ on OS X 10.9+ and iOS 7+. + if (((isTargetMacOS() && !isMacosxVersionLT(10, 9)) || + (isTargetIPhoneOS() && !isIPhoneOSVersionLT(7, 0))) && + !Args.getLastArg(options::OPT_stdlib_EQ)) + DAL->AddJoinedArg(0, Opts.getOption(options::OPT_stdlib_EQ), "libc++"); + // Validate the C++ standard library choice. CXXStdlibType Type = GetCXXStdlibType(*DAL); if (Type == ToolChain::CST_Libcxx) { @@ -917,17 +936,19 @@ Darwin_Generic_GCC::ComputeEffectiveClangTriple(const ArgList &Args, /// This is the primary means of forming GCCVersion objects. /*static*/ Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) { - const GCCVersion BadVersion = { VersionText.str(), -1, -1, -1, "" }; + const GCCVersion BadVersion = { VersionText.str(), -1, -1, -1, "", "", "" }; std::pair<StringRef, StringRef> First = VersionText.split('.'); std::pair<StringRef, StringRef> Second = First.second.split('.'); - GCCVersion GoodVersion = { VersionText.str(), -1, -1, -1, "" }; + GCCVersion GoodVersion = { VersionText.str(), -1, -1, -1, "", "", "" }; if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0) return BadVersion; + GoodVersion.MajorStr = First.first.str(); if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0) return BadVersion; + GoodVersion.MinorStr = Second.first.str(); // First look for a number prefix and parse that if present. Otherwise just // stash the entire patch string in the suffix, and leave the number @@ -945,7 +966,7 @@ Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) { if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) || GoodVersion.Patch < 0) return BadVersion; - GoodVersion.PatchSuffix = PatchText.substr(EndNumber).str(); + GoodVersion.PatchSuffix = PatchText.substr(EndNumber); } } @@ -953,31 +974,33 @@ Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) { } /// \brief Less-than for GCCVersion, implementing a Strict Weak Ordering. -bool Generic_GCC::GCCVersion::operator<(const GCCVersion &RHS) const { - if (Major != RHS.Major) - return Major < RHS.Major; - if (Minor != RHS.Minor) - return Minor < RHS.Minor; - if (Patch != RHS.Patch) { +bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor, + int RHSPatch, + StringRef RHSPatchSuffix) const { + if (Major != RHSMajor) + return Major < RHSMajor; + if (Minor != RHSMinor) + return Minor < RHSMinor; + if (Patch != RHSPatch) { // Note that versions without a specified patch sort higher than those with // a patch. - if (RHS.Patch == -1) + if (RHSPatch == -1) return true; if (Patch == -1) return false; // Otherwise just sort on the patch itself. - return Patch < RHS.Patch; + return Patch < RHSPatch; } - if (PatchSuffix != RHS.PatchSuffix) { + if (PatchSuffix != RHSPatchSuffix) { // Sort empty suffixes higher. - if (RHS.PatchSuffix.empty()) + if (RHSPatchSuffix.empty()) return true; if (PatchSuffix.empty()) return false; // Provide a lexicographic sort to make this a total ordering. - return PatchSuffix < RHS.PatchSuffix; + return PatchSuffix < RHSPatchSuffix; } // The versions are equal. @@ -1002,20 +1025,19 @@ static StringRef getGCCToolchainDir(const ArgList &Args) { /// triple. void Generic_GCC::GCCInstallationDetector::init( - const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args) { - llvm::Triple MultiarchTriple - = TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant() + const llvm::Triple &TargetTriple, const ArgList &Args) { + llvm::Triple BiarchVariantTriple = + TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant() : TargetTriple.get32BitArchVariant(); llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); // The library directories which may contain GCC installations. - SmallVector<StringRef, 4> CandidateLibDirs, CandidateMultiarchLibDirs; + SmallVector<StringRef, 4> CandidateLibDirs, CandidateBiarchLibDirs; // The compatible GCC triples for this particular architecture. SmallVector<StringRef, 10> CandidateTripleAliases; - SmallVector<StringRef, 10> CandidateMultiarchTripleAliases; - CollectLibDirsAndTriples(TargetTriple, MultiarchTriple, CandidateLibDirs, - CandidateTripleAliases, - CandidateMultiarchLibDirs, - CandidateMultiarchTripleAliases); + SmallVector<StringRef, 10> CandidateBiarchTripleAliases; + CollectLibDirsAndTriples(TargetTriple, BiarchVariantTriple, CandidateLibDirs, + CandidateTripleAliases, CandidateBiarchLibDirs, + CandidateBiarchTripleAliases); // Compute the set of prefixes for our search. SmallVector<std::string, 8> Prefixes(D.PrefixDirs.begin(), @@ -1028,9 +1050,18 @@ Generic_GCC::GCCInstallationDetector::init( Prefixes.push_back(GCCToolchainDir); } else { - Prefixes.push_back(D.SysRoot); - Prefixes.push_back(D.SysRoot + "/usr"); + // If we have a SysRoot, try that first. + if (!D.SysRoot.empty()) { + Prefixes.push_back(D.SysRoot); + Prefixes.push_back(D.SysRoot + "/usr"); + } + + // Then look for gcc installed alongside clang. Prefixes.push_back(D.InstalledDir + "/.."); + + // And finally in /usr. + if (D.SysRoot.empty()) + Prefixes.push_back("/usr"); } // Loop over the various components which exist and select the best GCC @@ -1047,217 +1078,216 @@ Generic_GCC::GCCInstallationDetector::init( ScanLibDirForGCCTriple(TargetArch, Args, LibDir, CandidateTripleAliases[k]); } - for (unsigned j = 0, je = CandidateMultiarchLibDirs.size(); j < je; ++j) { - const std::string LibDir - = Prefixes[i] + CandidateMultiarchLibDirs[j].str(); + for (unsigned j = 0, je = CandidateBiarchLibDirs.size(); j < je; ++j) { + const std::string LibDir = Prefixes[i] + CandidateBiarchLibDirs[j].str(); if (!llvm::sys::fs::exists(LibDir)) continue; - for (unsigned k = 0, ke = CandidateMultiarchTripleAliases.size(); k < ke; + for (unsigned k = 0, ke = CandidateBiarchTripleAliases.size(); k < ke; ++k) ScanLibDirForGCCTriple(TargetArch, Args, LibDir, - CandidateMultiarchTripleAliases[k], - /*NeedsMultiarchSuffix=*/true); + CandidateBiarchTripleAliases[k], + /*NeedsBiarchSuffix=*/ true); } } } +void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { + for (std::set<std::string>::const_iterator + I = CandidateGCCInstallPaths.begin(), + E = CandidateGCCInstallPaths.end(); + I != E; ++I) + OS << "Found candidate GCC installation: " << *I << "\n"; + + OS << "Selected GCC installation: " << GCCInstallPath << "\n"; +} + /*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples( - const llvm::Triple &TargetTriple, - const llvm::Triple &MultiarchTriple, + const llvm::Triple &TargetTriple, const llvm::Triple &BiarchTriple, SmallVectorImpl<StringRef> &LibDirs, SmallVectorImpl<StringRef> &TripleAliases, - SmallVectorImpl<StringRef> &MultiarchLibDirs, - SmallVectorImpl<StringRef> &MultiarchTripleAliases) { + SmallVectorImpl<StringRef> &BiarchLibDirs, + SmallVectorImpl<StringRef> &BiarchTripleAliases) { // Declare a bunch of static data sets that we'll select between below. These // are specifically designed to always refer to string literals to avoid any // lifetime or initialization issues. static const char *const AArch64LibDirs[] = { "/lib" }; - static const char *const AArch64Triples[] = { - "aarch64-none-linux-gnu", - "aarch64-linux-gnu" - }; + static const char *const AArch64Triples[] = { "aarch64-none-linux-gnu", + "aarch64-linux-gnu" }; static const char *const ARMLibDirs[] = { "/lib" }; - static const char *const ARMTriples[] = { - "arm-linux-gnueabi", - "arm-linux-androideabi" - }; - static const char *const ARMHFTriples[] = { - "arm-linux-gnueabihf", - "armv7hl-redhat-linux-gnueabi" - }; + static const char *const ARMTriples[] = { "arm-linux-gnueabi", + "arm-linux-androideabi" }; + static const char *const ARMHFTriples[] = { "arm-linux-gnueabihf", + "armv7hl-redhat-linux-gnueabi" }; static const char *const X86_64LibDirs[] = { "/lib64", "/lib" }; static const char *const X86_64Triples[] = { - "x86_64-linux-gnu", - "x86_64-unknown-linux-gnu", - "x86_64-pc-linux-gnu", - "x86_64-redhat-linux6E", - "x86_64-redhat-linux", - "x86_64-suse-linux", - "x86_64-manbo-linux-gnu", - "x86_64-linux-gnu", - "x86_64-slackware-linux" + "x86_64-linux-gnu", "x86_64-unknown-linux-gnu", "x86_64-pc-linux-gnu", + "x86_64-redhat-linux6E", "x86_64-redhat-linux", "x86_64-suse-linux", + "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", "x86_64-slackware-linux" }; static const char *const X86LibDirs[] = { "/lib32", "/lib" }; static const char *const X86Triples[] = { - "i686-linux-gnu", - "i686-pc-linux-gnu", - "i486-linux-gnu", - "i386-linux-gnu", - "i386-redhat-linux6E", - "i686-redhat-linux", - "i586-redhat-linux", - "i386-redhat-linux", - "i586-suse-linux", - "i486-slackware-linux", + "i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu", "i386-linux-gnu", + "i386-redhat-linux6E", "i686-redhat-linux", "i586-redhat-linux", + "i386-redhat-linux", "i586-suse-linux", "i486-slackware-linux", "i686-montavista-linux" }; static const char *const MIPSLibDirs[] = { "/lib" }; - static const char *const MIPSTriples[] = { "mips-linux-gnu" }; + static const char *const MIPSTriples[] = { "mips-linux-gnu", + "mips-mti-linux-gnu" }; static const char *const MIPSELLibDirs[] = { "/lib" }; - static const char *const MIPSELTriples[] = { - "mipsel-linux-gnu", - "mipsel-linux-android", - "mips-linux-gnu" - }; + static const char *const MIPSELTriples[] = { "mipsel-linux-gnu", + "mipsel-linux-android" }; static const char *const MIPS64LibDirs[] = { "/lib64", "/lib" }; - static const char *const MIPS64Triples[] = { "mips64-linux-gnu" }; + static const char *const MIPS64Triples[] = { "mips64-linux-gnu", + "mips-mti-linux-gnu" }; static const char *const MIPS64ELLibDirs[] = { "/lib64", "/lib" }; - static const char *const MIPS64ELTriples[] = { "mips64el-linux-gnu" }; + static const char *const MIPS64ELTriples[] = { "mips64el-linux-gnu", + "mips-mti-linux-gnu" }; static const char *const PPCLibDirs[] = { "/lib32", "/lib" }; static const char *const PPCTriples[] = { - "powerpc-linux-gnu", - "powerpc-unknown-linux-gnu", - "powerpc-linux-gnuspe", - "powerpc-suse-linux", - "powerpc-montavista-linuxspe" + "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe", + "powerpc-suse-linux", "powerpc-montavista-linuxspe" }; static const char *const PPC64LibDirs[] = { "/lib64", "/lib" }; - static const char *const PPC64Triples[] = { - "powerpc64-linux-gnu", - "powerpc64-unknown-linux-gnu", - "powerpc64-suse-linux", - "ppc64-redhat-linux" - }; + static const char *const PPC64Triples[] = { "powerpc64-linux-gnu", + "powerpc64-unknown-linux-gnu", + "powerpc64-suse-linux", + "ppc64-redhat-linux" }; + static const char *const PPC64LELibDirs[] = { "/lib64", "/lib" }; + static const char *const PPC64LETriples[] = { "powerpc64le-linux-gnu", + "powerpc64le-unknown-linux-gnu", + "powerpc64le-suse-linux", + "ppc64le-redhat-linux" }; static const char *const SystemZLibDirs[] = { "/lib64", "/lib" }; static const char *const SystemZTriples[] = { - "s390x-linux-gnu", - "s390x-unknown-linux-gnu", - "s390x-ibm-linux-gnu", - "s390x-suse-linux", - "s390x-redhat-linux" + "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu", + "s390x-suse-linux", "s390x-redhat-linux" }; switch (TargetTriple.getArch()) { case llvm::Triple::aarch64: - LibDirs.append(AArch64LibDirs, AArch64LibDirs - + llvm::array_lengthof(AArch64LibDirs)); - TripleAliases.append( - AArch64Triples, AArch64Triples + llvm::array_lengthof(AArch64Triples)); - MultiarchLibDirs.append( - AArch64LibDirs, AArch64LibDirs + llvm::array_lengthof(AArch64LibDirs)); - MultiarchTripleAliases.append( - AArch64Triples, AArch64Triples + llvm::array_lengthof(AArch64Triples)); + LibDirs.append(AArch64LibDirs, + AArch64LibDirs + llvm::array_lengthof(AArch64LibDirs)); + TripleAliases.append(AArch64Triples, + AArch64Triples + llvm::array_lengthof(AArch64Triples)); + BiarchLibDirs.append(AArch64LibDirs, + AArch64LibDirs + llvm::array_lengthof(AArch64LibDirs)); + BiarchTripleAliases.append( + AArch64Triples, AArch64Triples + llvm::array_lengthof(AArch64Triples)); break; case llvm::Triple::arm: case llvm::Triple::thumb: LibDirs.append(ARMLibDirs, ARMLibDirs + llvm::array_lengthof(ARMLibDirs)); if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { - TripleAliases.append( - ARMHFTriples, ARMHFTriples + llvm::array_lengthof(ARMHFTriples)); + TripleAliases.append(ARMHFTriples, + ARMHFTriples + llvm::array_lengthof(ARMHFTriples)); } else { - TripleAliases.append( - ARMTriples, ARMTriples + llvm::array_lengthof(ARMTriples)); + TripleAliases.append(ARMTriples, + ARMTriples + llvm::array_lengthof(ARMTriples)); } break; case llvm::Triple::x86_64: - LibDirs.append( - X86_64LibDirs, X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs)); - TripleAliases.append( - X86_64Triples, X86_64Triples + llvm::array_lengthof(X86_64Triples)); - MultiarchLibDirs.append( - X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs)); - MultiarchTripleAliases.append( - X86Triples, X86Triples + llvm::array_lengthof(X86Triples)); + LibDirs.append(X86_64LibDirs, + X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs)); + TripleAliases.append(X86_64Triples, + X86_64Triples + llvm::array_lengthof(X86_64Triples)); + BiarchLibDirs.append(X86LibDirs, + X86LibDirs + llvm::array_lengthof(X86LibDirs)); + BiarchTripleAliases.append(X86Triples, + X86Triples + llvm::array_lengthof(X86Triples)); break; case llvm::Triple::x86: LibDirs.append(X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs)); - TripleAliases.append( - X86Triples, X86Triples + llvm::array_lengthof(X86Triples)); - MultiarchLibDirs.append( - X86_64LibDirs, X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs)); - MultiarchTripleAliases.append( - X86_64Triples, X86_64Triples + llvm::array_lengthof(X86_64Triples)); + TripleAliases.append(X86Triples, + X86Triples + llvm::array_lengthof(X86Triples)); + BiarchLibDirs.append(X86_64LibDirs, + X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs)); + BiarchTripleAliases.append( + X86_64Triples, X86_64Triples + llvm::array_lengthof(X86_64Triples)); break; case llvm::Triple::mips: - LibDirs.append( - MIPSLibDirs, MIPSLibDirs + llvm::array_lengthof(MIPSLibDirs)); - TripleAliases.append( - MIPSTriples, MIPSTriples + llvm::array_lengthof(MIPSTriples)); - MultiarchLibDirs.append( - MIPS64LibDirs, MIPS64LibDirs + llvm::array_lengthof(MIPS64LibDirs)); - MultiarchTripleAliases.append( - MIPS64Triples, MIPS64Triples + llvm::array_lengthof(MIPS64Triples)); + LibDirs.append(MIPSLibDirs, + MIPSLibDirs + llvm::array_lengthof(MIPSLibDirs)); + TripleAliases.append(MIPSTriples, + MIPSTriples + llvm::array_lengthof(MIPSTriples)); + BiarchLibDirs.append(MIPS64LibDirs, + MIPS64LibDirs + llvm::array_lengthof(MIPS64LibDirs)); + BiarchTripleAliases.append( + MIPS64Triples, MIPS64Triples + llvm::array_lengthof(MIPS64Triples)); break; case llvm::Triple::mipsel: - LibDirs.append( - MIPSELLibDirs, MIPSELLibDirs + llvm::array_lengthof(MIPSELLibDirs)); - TripleAliases.append( - MIPSELTriples, MIPSELTriples + llvm::array_lengthof(MIPSELTriples)); - MultiarchLibDirs.append( - MIPS64ELLibDirs, MIPS64ELLibDirs + llvm::array_lengthof(MIPS64ELLibDirs)); - MultiarchTripleAliases.append( - MIPS64ELTriples, MIPS64ELTriples + llvm::array_lengthof(MIPS64ELTriples)); + LibDirs.append(MIPSELLibDirs, + MIPSELLibDirs + llvm::array_lengthof(MIPSELLibDirs)); + TripleAliases.append(MIPSELTriples, + MIPSELTriples + llvm::array_lengthof(MIPSELTriples)); + TripleAliases.append(MIPSTriples, + MIPSTriples + llvm::array_lengthof(MIPSTriples)); + BiarchLibDirs.append( + MIPS64ELLibDirs, + MIPS64ELLibDirs + llvm::array_lengthof(MIPS64ELLibDirs)); + BiarchTripleAliases.append( + MIPS64ELTriples, + MIPS64ELTriples + llvm::array_lengthof(MIPS64ELTriples)); break; case llvm::Triple::mips64: - LibDirs.append( - MIPS64LibDirs, MIPS64LibDirs + llvm::array_lengthof(MIPS64LibDirs)); - TripleAliases.append( - MIPS64Triples, MIPS64Triples + llvm::array_lengthof(MIPS64Triples)); - MultiarchLibDirs.append( - MIPSLibDirs, MIPSLibDirs + llvm::array_lengthof(MIPSLibDirs)); - MultiarchTripleAliases.append( - MIPSTriples, MIPSTriples + llvm::array_lengthof(MIPSTriples)); + LibDirs.append(MIPS64LibDirs, + MIPS64LibDirs + llvm::array_lengthof(MIPS64LibDirs)); + TripleAliases.append(MIPS64Triples, + MIPS64Triples + llvm::array_lengthof(MIPS64Triples)); + BiarchLibDirs.append(MIPSLibDirs, + MIPSLibDirs + llvm::array_lengthof(MIPSLibDirs)); + BiarchTripleAliases.append(MIPSTriples, + MIPSTriples + llvm::array_lengthof(MIPSTriples)); break; case llvm::Triple::mips64el: - LibDirs.append( - MIPS64ELLibDirs, MIPS64ELLibDirs + llvm::array_lengthof(MIPS64ELLibDirs)); + LibDirs.append(MIPS64ELLibDirs, + MIPS64ELLibDirs + llvm::array_lengthof(MIPS64ELLibDirs)); TripleAliases.append( - MIPS64ELTriples, MIPS64ELTriples + llvm::array_lengthof(MIPS64ELTriples)); - MultiarchLibDirs.append( - MIPSELLibDirs, MIPSELLibDirs + llvm::array_lengthof(MIPSELLibDirs)); - MultiarchTripleAliases.append( - MIPSELTriples, MIPSELTriples + llvm::array_lengthof(MIPSELTriples)); + MIPS64ELTriples, + MIPS64ELTriples + llvm::array_lengthof(MIPS64ELTriples)); + BiarchLibDirs.append(MIPSELLibDirs, + MIPSELLibDirs + llvm::array_lengthof(MIPSELLibDirs)); + BiarchTripleAliases.append( + MIPSELTriples, MIPSELTriples + llvm::array_lengthof(MIPSELTriples)); + BiarchTripleAliases.append( + MIPSTriples, MIPSTriples + llvm::array_lengthof(MIPSTriples)); break; case llvm::Triple::ppc: LibDirs.append(PPCLibDirs, PPCLibDirs + llvm::array_lengthof(PPCLibDirs)); - TripleAliases.append( - PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples)); - MultiarchLibDirs.append( - PPC64LibDirs, PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs)); - MultiarchTripleAliases.append( - PPC64Triples, PPC64Triples + llvm::array_lengthof(PPC64Triples)); + TripleAliases.append(PPCTriples, + PPCTriples + llvm::array_lengthof(PPCTriples)); + BiarchLibDirs.append(PPC64LibDirs, + PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs)); + BiarchTripleAliases.append( + PPC64Triples, PPC64Triples + llvm::array_lengthof(PPC64Triples)); break; case llvm::Triple::ppc64: - LibDirs.append( - PPC64LibDirs, PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs)); - TripleAliases.append( - PPC64Triples, PPC64Triples + llvm::array_lengthof(PPC64Triples)); - MultiarchLibDirs.append( - PPCLibDirs, PPCLibDirs + llvm::array_lengthof(PPCLibDirs)); - MultiarchTripleAliases.append( - PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples)); + LibDirs.append(PPC64LibDirs, + PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs)); + TripleAliases.append(PPC64Triples, + PPC64Triples + llvm::array_lengthof(PPC64Triples)); + BiarchLibDirs.append(PPCLibDirs, + PPCLibDirs + llvm::array_lengthof(PPCLibDirs)); + BiarchTripleAliases.append(PPCTriples, + PPCTriples + llvm::array_lengthof(PPCTriples)); + break; + case llvm::Triple::ppc64le: + LibDirs.append(PPC64LELibDirs, + PPC64LELibDirs + llvm::array_lengthof(PPC64LELibDirs)); + TripleAliases.append(PPC64LETriples, + PPC64LETriples + llvm::array_lengthof(PPC64LETriples)); break; case llvm::Triple::systemz: - LibDirs.append( - SystemZLibDirs, SystemZLibDirs + llvm::array_lengthof(SystemZLibDirs)); - TripleAliases.append( - SystemZTriples, SystemZTriples + llvm::array_lengthof(SystemZTriples)); + LibDirs.append(SystemZLibDirs, + SystemZLibDirs + llvm::array_lengthof(SystemZLibDirs)); + TripleAliases.append(SystemZTriples, + SystemZTriples + llvm::array_lengthof(SystemZTriples)); break; default: @@ -1271,8 +1301,8 @@ Generic_GCC::GCCInstallationDetector::init( TripleAliases.push_back(TargetTriple.str()); // Also include the multiarch variant if it's different. - if (TargetTriple.str() != MultiarchTriple.str()) - MultiarchTripleAliases.push_back(MultiarchTriple.str()); + if (TargetTriple.str() != BiarchTriple.str()) + BiarchTripleAliases.push_back(BiarchTriple.str()); } static bool isSoftFloatABI(const ArgList &Args) { @@ -1299,87 +1329,168 @@ static bool isMips16(const ArgList &Args) { return A && A->getOption().matches(options::OPT_mips16); } +static bool isMips32r2(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_march_EQ, + options::OPT_mcpu_EQ); + + return A && A->getValue() == StringRef("mips32r2"); +} + +static bool isMips64r2(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_march_EQ, + options::OPT_mcpu_EQ); + + return A && A->getValue() == StringRef("mips64r2"); +} + static bool isMicroMips(const ArgList &Args) { Arg *A = Args.getLastArg(options::OPT_mmicromips, options::OPT_mno_micromips); return A && A->getOption().matches(options::OPT_mmicromips); } +static bool isMipsFP64(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_mfp64, options::OPT_mfp32); + return A && A->getOption().matches(options::OPT_mfp64); +} + +static bool isMipsNan2008(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_mnan_EQ); + return A && A->getValue() == StringRef("2008"); +} + // FIXME: There is the same routine in the Tools.cpp. static bool hasMipsN32ABIArg(const ArgList &Args) { Arg *A = Args.getLastArg(options::OPT_mabi_EQ); return A && (A->getValue() == StringRef("n32")); } -static void appendMipsTargetSuffix(std::string &Path, +static bool hasCrtBeginObj(Twine Path) { + return llvm::sys::fs::exists(Path + "/crtbegin.o"); +} + +static bool findTargetBiarchSuffix(std::string &Suffix, StringRef Path, llvm::Triple::ArchType TargetArch, const ArgList &Args) { - if (isMips16(Args)) - Path += "/mips16"; - else if (isMicroMips(Args)) - Path += "/micromips"; - - if (isSoftFloatABI(Args)) - Path += "/soft-float"; + // FIXME: This routine was only intended to model bi-arch toolchains which + // use -m32 and -m64 to swap between variants of a target. It shouldn't be + // doing ABI-based builtin location for MIPS. + if (hasMipsN32ABIArg(Args)) + Suffix = "/n32"; + else if (TargetArch == llvm::Triple::x86_64 || + TargetArch == llvm::Triple::ppc64 || + TargetArch == llvm::Triple::systemz || + TargetArch == llvm::Triple::mips64 || + TargetArch == llvm::Triple::mips64el) + Suffix = "/64"; + else + Suffix = "/32"; - if (TargetArch == llvm::Triple::mipsel || - TargetArch == llvm::Triple::mips64el) - Path += "/el"; + return hasCrtBeginObj(Path + Suffix); } -static StringRef getMipsTargetABISuffix(llvm::Triple::ArchType TargetArch, - const ArgList &Args) { - if (TargetArch == llvm::Triple::mips64 || - TargetArch == llvm::Triple::mips64el) - return hasMipsN32ABIArg(Args) ? "/n32" : "/64"; - - return "/32"; -} +void Generic_GCC::GCCInstallationDetector::findMIPSABIDirSuffix( + std::string &Suffix, llvm::Triple::ArchType TargetArch, StringRef Path, + const llvm::opt::ArgList &Args) { + if (!isMipsArch(TargetArch)) + return; -static bool findTargetMultiarchSuffix(std::string &Suffix, - StringRef Path, - llvm::Triple::ArchType TargetArch, - const ArgList &Args) { - if (isMipsArch(TargetArch)) { - StringRef ABISuffix = getMipsTargetABISuffix(TargetArch, Args); + // Some MIPS toolchains put libraries and object files compiled + // using different options in to the sub-directoris which names + // reflects the flags used for compilation. For example sysroot + // directory might looks like the following examples: + // + // /usr + // /lib <= crt*.o files compiled with '-mips32' + // /mips16 + // /usr + // /lib <= crt*.o files compiled with '-mips16' + // /el + // /usr + // /lib <= crt*.o files compiled with '-mips16 -EL' + // + // or + // + // /usr + // /lib <= crt*.o files compiled with '-mips32r2' + // /mips16 + // /usr + // /lib <= crt*.o files compiled with '-mips32r2 -mips16' + // /mips32 + // /usr + // /lib <= crt*.o files compiled with '-mips32' + // + // Unfortunately different toolchains use different and partially + // overlapped naming schemes. So we have to make a trick for detection + // of using toolchain. We lookup a path which unique for each toolchains. + + bool IsMentorToolChain = hasCrtBeginObj(Path + "/mips16/soft-float"); + bool IsFSFToolChain = hasCrtBeginObj(Path + "/mips32/mips16/sof"); + + if (IsMentorToolChain && IsFSFToolChain) + D.Diag(diag::err_drv_unknown_toolchain); + + if (IsMentorToolChain) { + if (isMips16(Args)) + Suffix += "/mips16"; + else if (isMicroMips(Args)) + Suffix += "/micromips"; + + if (isSoftFloatABI(Args)) + Suffix += "/soft-float"; + + if (TargetArch == llvm::Triple::mipsel || + TargetArch == llvm::Triple::mips64el) + Suffix += "/el"; + } else if (IsFSFToolChain) { + if (TargetArch == llvm::Triple::mips || + TargetArch == llvm::Triple::mipsel) { + if (isMicroMips(Args)) + Suffix += "/micromips"; + else if (isMips32r2(Args)) + Suffix += ""; + else + Suffix += "/mips32"; - // First build and check a complex path to crtbegin.o - // depends on command line options (-mips16, -msoft-float, ...) - // like mips-linux-gnu/4.7/mips16/soft-float/el/crtbegin.o - appendMipsTargetSuffix(Suffix, TargetArch, Args); + if (isMips16(Args)) + Suffix += "/mips16"; + } else { + if (isMips64r2(Args)) + Suffix += hasMipsN32ABIArg(Args) ? "/mips64r2" : "/mips64r2/64"; + else + Suffix += hasMipsN32ABIArg(Args) ? "/mips64" : "/mips64/64"; + } - if (TargetArch == llvm::Triple::mips64 || + if (TargetArch == llvm::Triple::mipsel || TargetArch == llvm::Triple::mips64el) - Suffix += ABISuffix; + Suffix += "/el"; - if (llvm::sys::fs::exists(Path + Suffix + "/crtbegin.o")) - return true; + if (isSoftFloatABI(Args)) + Suffix += "/sof"; + else { + if (isMipsFP64(Args)) + Suffix += "/fp64"; - // Then fall back and probe a simple case like - // mips-linux-gnu/4.7/32/crtbegin.o - Suffix = ABISuffix; - return llvm::sys::fs::exists(Path + Suffix + "/crtbegin.o"); + if (isMipsNan2008(Args)) + Suffix += "/nan2008"; + } } - if (TargetArch == llvm::Triple::x86_64 || - TargetArch == llvm::Triple::ppc64 || - TargetArch == llvm::Triple::systemz) - Suffix = "/64"; - else - Suffix = "/32"; - - return llvm::sys::fs::exists(Path + Suffix + "/crtbegin.o"); + if (!hasCrtBeginObj(Path + Suffix)) + Suffix.clear(); } void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( llvm::Triple::ArchType TargetArch, const ArgList &Args, - const std::string &LibDir, - StringRef CandidateTriple, bool NeedsMultiarchSuffix) { + const std::string &LibDir, StringRef CandidateTriple, + bool NeedsBiarchSuffix) { // There are various different suffixes involving the triple we // check for. We also record what is necessary to walk from each back // up to the lib directory. const std::string LibSuffixes[] = { "/gcc/" + CandidateTriple.str(), + // Debian puts cross-compilers in gcc-cross + "/gcc-cross/" + CandidateTriple.str(), "/" + CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), // The Freescale PPC SDK has the gcc libraries in @@ -1393,14 +1504,15 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( "/i386-linux-gnu/gcc/" + CandidateTriple.str() }; const std::string InstallSuffixes[] = { - "/../../..", - "/../../../..", - "/../..", - "/../../../.." + "/../../..", // gcc/ + "/../../..", // gcc-cross/ + "/../../../..", // <triple>/gcc/ + "/../..", // <triple>/ + "/../../../.." // i386-linux-gnu/gcc/<triple>/ }; // Only look at the final, weird Ubuntu suffix for i386-linux-gnu. - const unsigned NumLibSuffixes = (llvm::array_lengthof(LibSuffixes) - - (TargetArch != llvm::Triple::x86)); + const unsigned NumLibSuffixes = + (llvm::array_lengthof(LibSuffixes) - (TargetArch != llvm::Triple::x86)); for (unsigned i = 0; i < NumLibSuffixes; ++i) { StringRef LibSuffix = LibSuffixes[i]; llvm::error_code EC; @@ -1408,28 +1520,34 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( !EC && LI != LE; LI = LI.increment(EC)) { StringRef VersionText = llvm::sys::path::filename(LI->path()); GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); - static const GCCVersion MinVersion = { "4.1.1", 4, 1, 1, "" }; - if (CandidateVersion < MinVersion) + if (CandidateVersion.Major != -1) // Filter obviously bad entries. + if (!CandidateGCCInstallPaths.insert(LI->path()).second) + continue; // Saw this path before; no need to look at it again. + if (CandidateVersion.isOlderThan(4, 1, 1)) continue; if (CandidateVersion <= Version) continue; + std::string MIPSABIDirSuffix; + findMIPSABIDirSuffix(MIPSABIDirSuffix, TargetArch, LI->path(), Args); + // Some versions of SUSE and Fedora on ppc64 put 32-bit libs // in what would normally be GCCInstallPath and put the 64-bit // libs in a subdirectory named 64. The simple logic we follow is that // *if* there is a subdirectory of the right name with crtbegin.o in it, - // we use that. If not, and if not a multiarch triple, we look for + // we use that. If not, and if not a biarch triple alias, we look for // crtbegin.o without the subdirectory. - std::string MultiarchSuffix; - if (findTargetMultiarchSuffix(MultiarchSuffix, - LI->path(), TargetArch, Args)) { - GCCMultiarchSuffix = MultiarchSuffix; + std::string BiarchSuffix; + if (findTargetBiarchSuffix(BiarchSuffix, + LI->path() + MIPSABIDirSuffix, + TargetArch, Args)) { + GCCBiarchSuffix = BiarchSuffix; + } else if (NeedsBiarchSuffix || + !hasCrtBeginObj(LI->path() + MIPSABIDirSuffix)) { + continue; } else { - if (NeedsMultiarchSuffix || - !llvm::sys::fs::exists(LI->path() + "/crtbegin.o")) - continue; - GCCMultiarchSuffix.clear(); + GCCBiarchSuffix.clear(); } Version = CandidateVersion; @@ -1439,6 +1557,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( // Linux. GCCInstallPath = LibDir + LibSuffixes[i] + "/" + VersionText.str(); GCCParentLibPath = GCCInstallPath + InstallSuffixes[i]; + GCCMIPSABIDirSuffix = MIPSABIDirSuffix; IsValid = true; } } @@ -1446,7 +1565,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) - : ToolChain(D, Triple, Args), GCCInstallation() { + : ToolChain(D, Triple, Args), GCCInstallation(getDriver()) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); @@ -1482,6 +1601,11 @@ Tool *Generic_GCC::buildLinker() const { return new tools::gcc::Link(*this); } +void Generic_GCC::printVerboseInfo(raw_ostream &OS) const { + // Print the information about how we detected the GCC installation. + GCCInstallation.print(OS); +} + bool Generic_GCC::IsUnwindTablesDefault() const { return getArch() == llvm::Triple::x86_64; } @@ -1626,7 +1750,6 @@ void Hexagon_TC::AddClangSystemIncludeArgs(const ArgList &DriverArgs, DriverArgs.hasArg(options::OPT_nostdlibinc)) return; - llvm::sys::Path InstallDir(D.InstalledDir); std::string Ver(GetGCCLibAndIncVersion()); std::string GnuDir = Hexagon_TC::GetGnuDir(D.InstalledDir); std::string HexagonDir(GnuDir + "/lib/gcc/hexagon/" + Ver); @@ -1644,10 +1767,10 @@ void Hexagon_TC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, const Driver &D = getDriver(); std::string Ver(GetGCCLibAndIncVersion()); - llvm::sys::Path IncludeDir(Hexagon_TC::GetGnuDir(D.InstalledDir)); + SmallString<128> IncludeDir(Hexagon_TC::GetGnuDir(D.InstalledDir)); - IncludeDir.appendComponent("hexagon/include/c++/"); - IncludeDir.appendComponent(Ver); + llvm::sys::path::append(IncludeDir, "hexagon/include/c++/"); + llvm::sys::path::append(IncludeDir, Ver); addSystemInclude(DriverArgs, CC1Args, IncludeDir.str()); } @@ -1666,40 +1789,47 @@ Hexagon_TC::GetCXXStdlibType(const ArgList &Args) const { return ToolChain::CST_Libstdcxx; } -static Arg *GetLastHexagonArchArg(const ArgList &Args) -{ - Arg *A = NULL; - - for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); - it != ie; ++it) { - if ((*it)->getOption().matches(options::OPT_march_EQ) || - (*it)->getOption().matches(options::OPT_mcpu_EQ)) { - A = *it; - A->claim(); - } else if ((*it)->getOption().matches(options::OPT_m_Joined)) { - StringRef Value = (*it)->getValue(0); - if (Value.startswith("v")) { - A = *it; - A->claim(); - } - } +static int getHexagonVersion(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_march_EQ, options::OPT_mcpu_EQ); + // Select the default CPU (v4) if none was given. + if (!A) + return 4; + + // FIXME: produce errors if we cannot parse the version. + StringRef WhichHexagon = A->getValue(); + if (WhichHexagon.startswith("hexagonv")) { + int Val; + if (!WhichHexagon.substr(sizeof("hexagonv") - 1).getAsInteger(10, Val)) + return Val; + } + if (WhichHexagon.startswith("v")) { + int Val; + if (!WhichHexagon.substr(1).getAsInteger(10, Val)) + return Val; } - return A; + + // FIXME: should probably be an error. + return 4; } StringRef Hexagon_TC::GetTargetCPU(const ArgList &Args) { - // Select the default CPU (v4) if none was given or detection failed. - Arg *A = GetLastHexagonArchArg (Args); - if (A) { - StringRef WhichHexagon = A->getValue(); - if (WhichHexagon.startswith("hexagon")) - return WhichHexagon.substr(sizeof("hexagon") - 1); - if (WhichHexagon != "") - return WhichHexagon; + int V = getHexagonVersion(Args); + // FIXME: We don't support versions < 4. We should error on them. + switch (V) { + default: + llvm_unreachable("Unexpected version"); + case 5: + return "v5"; + case 4: + return "v4"; + case 3: + return "v3"; + case 2: + return "v2"; + case 1: + return "v1"; } - - return "v4"; } // End Hexagon @@ -1828,57 +1958,62 @@ FreeBSD::FreeBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Arg getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); } -Tool *FreeBSD::buildAssembler() const { - return new tools::freebsd::Assemble(*this); -} - -Tool *FreeBSD::buildLinker() const { - return new tools::freebsd::Link(*this); -} - -bool FreeBSD::UseSjLjExceptions() const { - // FreeBSD uses SjLj exceptions on ARM oabi. - switch (getTriple().getEnvironment()) { - case llvm::Triple::GNUEABI: - case llvm::Triple::EABI: - return false; - - default: - return (getTriple().getArch() == llvm::Triple::arm || - getTriple().getArch() == llvm::Triple::thumb); - } -} - ToolChain::CXXStdlibType FreeBSD::GetCXXStdlibType(const ArgList &Args) const { if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { StringRef Value = A->getValue(); - if (Value == "libc++") - return ToolChain::CST_Libcxx; if (Value == "libstdc++") return ToolChain::CST_Libstdcxx; + if (Value == "libc++") + return ToolChain::CST_Libcxx; + getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); } - - return getTriple().getOSMajorVersion() >= 10 ? ToolChain::CST_Libcxx : - ToolChain::CST_Libstdcxx; + if (getTriple().getOSMajorVersion() >= 10) + return ToolChain::CST_Libcxx; + return ToolChain::CST_Libstdcxx; } void FreeBSD::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { + ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) return; - if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/include/c++/v1"); - else + break; + case ToolChain::CST_Libstdcxx: addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/include/c++/4.2"); - return; + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/c++/4.2/backward"); + break; + } +} + +Tool *FreeBSD::buildAssembler() const { + return new tools::freebsd::Assemble(*this); +} + +Tool *FreeBSD::buildLinker() const { + return new tools::freebsd::Link(*this); +} +bool FreeBSD::UseSjLjExceptions() const { + // FreeBSD uses SjLj exceptions on ARM oabi. + switch (getTriple().getEnvironment()) { + case llvm::Triple::GNUEABI: + case llvm::Triple::EABI: + return false; + + default: + return (getTriple().getArch() == llvm::Triple::arm || + getTriple().getArch() == llvm::Triple::thumb); + } } /// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly. @@ -1920,6 +2055,12 @@ NetBSD::GetCXXStdlibType(const ArgList &Args) const { << A->getAsString(Args); } + unsigned Major, Minor, Micro; + getTriple().getOSVersion(Major, Minor, Micro); + if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 23) || Major == 0) { + if (getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64) + return ToolChain::CST_Libcxx; + } return ToolChain::CST_Libstdcxx; } @@ -2019,15 +2160,8 @@ enum Distro { RHEL4, RHEL5, RHEL6, - Fedora13, - Fedora14, - Fedora15, - Fedora16, - FedoraRawhide, - OpenSuse11_3, - OpenSuse11_4, - OpenSuse12_1, - OpenSuse12_2, + Fedora, + OpenSUSE, UbuntuHardy, UbuntuIntrepid, UbuntuJaunty, @@ -2039,16 +2173,17 @@ enum Distro { UbuntuPrecise, UbuntuQuantal, UbuntuRaring, + UbuntuSaucy, + UbuntuTrusty, UnknownDistro }; static bool IsRedhat(enum Distro Distro) { - return (Distro >= Fedora13 && Distro <= FedoraRawhide) || - (Distro >= RHEL4 && Distro <= RHEL6); + return Distro == Fedora || (Distro >= RHEL4 && Distro <= RHEL6); } -static bool IsOpenSuse(enum Distro Distro) { - return Distro >= OpenSuse11_3 && Distro <= OpenSuse12_2; +static bool IsOpenSUSE(enum Distro Distro) { + return Distro == OpenSUSE; } static bool IsDebian(enum Distro Distro) { @@ -2056,7 +2191,7 @@ static bool IsDebian(enum Distro Distro) { } static bool IsUbuntu(enum Distro Distro) { - return Distro >= UbuntuHardy && Distro <= UbuntuRaring; + return Distro >= UbuntuHardy && Distro <= UbuntuTrusty; } static Distro DetectDistro(llvm::Triple::ArchType Arch) { @@ -2080,23 +2215,16 @@ static Distro DetectDistro(llvm::Triple::ArchType Arch) { .Case("precise", UbuntuPrecise) .Case("quantal", UbuntuQuantal) .Case("raring", UbuntuRaring) + .Case("saucy", UbuntuSaucy) + .Case("trusty", UbuntuTrusty) .Default(UnknownDistro); return Version; } if (!llvm::MemoryBuffer::getFile("/etc/redhat-release", File)) { StringRef Data = File.get()->getBuffer(); - if (Data.startswith("Fedora release 16")) - return Fedora16; - else if (Data.startswith("Fedora release 15")) - return Fedora15; - else if (Data.startswith("Fedora release 14")) - return Fedora14; - else if (Data.startswith("Fedora release 13")) - return Fedora13; - else if (Data.startswith("Fedora release") && - Data.find("Rawhide") != StringRef::npos) - return FedoraRawhide; + if (Data.startswith("Fedora release")) + return Fedora; else if (Data.startswith("Red Hat Enterprise Linux") && Data.find("release 6") != StringRef::npos) return RHEL6; @@ -2124,19 +2252,13 @@ static Distro DetectDistro(llvm::Triple::ArchType Arch) { return UnknownDistro; } - if (!llvm::MemoryBuffer::getFile("/etc/SuSE-release", File)) - return llvm::StringSwitch<Distro>(File.get()->getBuffer()) - .StartsWith("openSUSE 11.3", OpenSuse11_3) - .StartsWith("openSUSE 11.4", OpenSuse11_4) - .StartsWith("openSUSE 12.1", OpenSuse12_1) - .StartsWith("openSUSE 12.2", OpenSuse12_2) - .Default(UnknownDistro); + if (llvm::sys::fs::exists("/etc/SuSE-release")) + return OpenSUSE; - bool Exists; - if (!llvm::sys::fs::exists("/etc/exherbo-release", Exists) && Exists) + if (llvm::sys::fs::exists("/etc/exherbo-release")) return Exherbo; - if (!llvm::sys::fs::exists("/etc/arch-release", Exists) && Exists) + if (llvm::sys::fs::exists("/etc/arch-release")) return ArchLinux; return UnknownDistro; @@ -2181,6 +2303,7 @@ static std::string getMultiarchTriple(const llvm::Triple TargetTriple, case llvm::Triple::aarch64: if (llvm::sys::fs::exists(SysRoot + "/lib/aarch64-linux-gnu")) return "aarch64-linux-gnu"; + return TargetTriple.str(); case llvm::Triple::mips: if (llvm::sys::fs::exists(SysRoot + "/lib/mips-linux-gnu")) return "mips-linux-gnu"; @@ -2198,6 +2321,9 @@ static std::string getMultiarchTriple(const llvm::Triple TargetTriple, case llvm::Triple::ppc64: if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc64-linux-gnu")) return "powerpc64-linux-gnu"; + case llvm::Triple::ppc64le: + if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc64le-linux-gnu")) + return "powerpc64le-linux-gnu"; return TargetTriple.str(); } } @@ -2206,34 +2332,28 @@ static void addPathIfExists(Twine Path, ToolChain::path_list &Paths) { if (llvm::sys::fs::exists(Path)) Paths.push_back(Path.str()); } -static bool isMipsR2Arch(llvm::Triple::ArchType Arch, - const ArgList &Args) { - if (Arch != llvm::Triple::mips && - Arch != llvm::Triple::mipsel) - return false; - - Arg *A = Args.getLastArg(options::OPT_march_EQ, - options::OPT_mcpu_EQ, - options::OPT_mips_CPUs_Group); - - if (!A) - return false; - - if (A->getOption().matches(options::OPT_mips_CPUs_Group)) - return A->getOption().matches(options::OPT_mips32r2); - - return A->getValue() == StringRef("mips32r2"); -} - static StringRef getMultilibDir(const llvm::Triple &Triple, const ArgList &Args) { - if (!isMipsArch(Triple.getArch())) - return Triple.isArch32Bit() ? "lib32" : "lib64"; + if (isMipsArch(Triple.getArch())) { + // lib32 directory has a special meaning on MIPS targets. + // It contains N32 ABI binaries. Use this folder if produce + // code for N32 ABI only. + if (hasMipsN32ABIArg(Args)) + return "lib32"; + return Triple.isArch32Bit() ? "lib" : "lib64"; + } - // lib32 directory has a special meaning on MIPS targets. - // It contains N32 ABI binaries. Use this folder if produce - // code for N32 ABI only. - if (hasMipsN32ABIArg(Args)) + // It happens that only x86 and PPC use the 'lib32' variant of multilib, and + // using that variant while targeting other architectures causes problems + // because the libraries are laid out in shared system roots that can't cope + // with a 'lib32' multilib search path being considered. So we only enable + // them when we know we may need it. + // + // FIXME: This is a bit of a hack. We should really unify this code for + // reasoning about multilib spellings with the lib dir spellings in the + // GCCInstallationDetector, but that is a more significant refactoring. + if (Triple.getArch() == llvm::Triple::x86 || + Triple.getArch() == llvm::Triple::ppc) return "lib32"; return Triple.isArch32Bit() ? "lib" : "lib64"; @@ -2241,12 +2361,18 @@ static StringRef getMultilibDir(const llvm::Triple &Triple, Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(D, Triple, Args); + GCCInstallation.init(Triple, Args); llvm::Triple::ArchType Arch = Triple.getArch(); - std::string SysRoot = computeSysRoot(Args); - - // OpenSuse stores the linker with the compiler, add that to the search - // path. + std::string SysRoot = computeSysRoot(); + + // Cross-compiling binutils and GCC installations (vanilla and openSUSE at + // least) put various tools in a triple-prefixed directory off of the parent + // of the GCC installation. We use the GCC triple here to ensure that we end + // up with tools that support the same amount of cross compiling as the + // detected GCC installation. For example, if we find a GCC installation + // targeting x86_64, but it is a bi-arch GCC installation, it can also be + // used to target i386. + // FIXME: This seems unlikely to be Linux-specific. ToolChain::path_list &PPaths = getProgramPaths(); PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + GCCInstallation.getTriple().str() + "/bin").str()); @@ -2255,7 +2381,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) Distro Distro = DetectDistro(Arch); - if (IsOpenSuse(Distro) || IsUbuntu(Distro)) { + if (IsOpenSUSE(Distro) || IsUbuntu(Distro)) { ExtraOpts.push_back("-z"); ExtraOpts.push_back("relro"); } @@ -2275,11 +2401,11 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // ABI requires a mapping between the GOT and the symbol table. // Android loader does not support .gnu.hash. if (!IsMips && !IsAndroid) { - if (IsRedhat(Distro) || IsOpenSuse(Distro) || + if (IsRedhat(Distro) || IsOpenSUSE(Distro) || (IsUbuntu(Distro) && Distro >= UbuntuMaverick)) ExtraOpts.push_back("--hash-style=gnu"); - if (IsDebian(Distro) || IsOpenSuse(Distro) || Distro == UbuntuLucid || + if (IsDebian(Distro) || IsOpenSUSE(Distro) || Distro == UbuntuLucid || Distro == UbuntuJaunty || Distro == UbuntuKarmic) ExtraOpts.push_back("--hash-style=both"); } @@ -2288,12 +2414,12 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) ExtraOpts.push_back("--no-add-needed"); if (Distro == DebianSqueeze || Distro == DebianWheezy || - Distro == DebianJessie || IsOpenSuse(Distro) || + Distro == DebianJessie || IsOpenSUSE(Distro) || (IsRedhat(Distro) && Distro != RHEL4 && Distro != RHEL5) || (IsUbuntu(Distro) && Distro >= UbuntuKarmic)) ExtraOpts.push_back("--build-id"); - if (IsOpenSuse(Distro)) + if (IsOpenSUSE(Distro)) ExtraOpts.push_back("--enable-new-dtags"); // The selection of paths to try here is designed to match the patterns which @@ -2311,15 +2437,43 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); const std::string &LibPath = GCCInstallation.getParentLibPath(); - if (IsAndroid && isMipsR2Arch(Triple.getArch(), Args)) - addPathIfExists(GCCInstallation.getInstallPath() + - GCCInstallation.getMultiarchSuffix() + - "/mips-r2", - Paths); - else + // Sourcery CodeBench MIPS toolchain holds some libraries under + // a biarch-like suffix of the GCC installation. + // + // FIXME: It would be cleaner to model this as a variant of bi-arch. IE, + // instead of a '64' biarch suffix it would be 'el' or something. + if (IsAndroid && IsMips && isMips32r2(Args)) { + assert(GCCInstallation.getBiarchSuffix().empty() && + "Unexpected bi-arch suffix"); + addPathIfExists(GCCInstallation.getInstallPath() + "/mips-r2", Paths); + } else { addPathIfExists((GCCInstallation.getInstallPath() + - GCCInstallation.getMultiarchSuffix()), + GCCInstallation.getMIPSABIDirSuffix() + + GCCInstallation.getBiarchSuffix()), Paths); + } + + // GCC cross compiling toolchains will install target libraries which ship + // as part of the toolchain under <prefix>/<triple>/<libdir> rather than as + // any part of the GCC installation in + // <prefix>/<libdir>/gcc/<triple>/<version>. This decision is somewhat + // debatable, but is the reality today. We need to search this tree even + // when we have a sysroot somewhere else. It is the responsibility of + // whomever is doing the cross build targetting a sysroot using a GCC + // installation that is *not* within the system root to ensure two things: + // + // 1) Any DSOs that are linked in from this tree or from the install path + // above must be preasant on the system root and found via an + // appropriate rpath. + // 2) There must not be libraries installed into + // <prefix>/<triple>/<libdir> unless they should be preferred over + // those within the system root. + // + // Note that this matches the GCC behavior. See the below comment for where + // Clang diverges from GCC's behavior. + addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + Multilib + + GCCInstallation.getMIPSABIDirSuffix(), + Paths); // If the GCC installation we found is inside of the sysroot, we want to // prefer libraries installed in the parent prefix of the GCC installation. @@ -2327,55 +2481,48 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // outside of the system root as that can pick up unintended libraries. // This usually happens when there is an external cross compiler on the // host system, and a more minimal sysroot available that is the target of - // the cross. + // the cross. Note that GCC does include some of these directories in some + // configurations but this seems somewhere between questionable and simply + // a bug. if (StringRef(LibPath).startswith(SysRoot)) { - addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + Multilib, - Paths); addPathIfExists(LibPath + "/" + MultiarchTriple, Paths); addPathIfExists(LibPath + "/../" + Multilib, Paths); } - // On Android, libraries in the parent prefix of the GCC installation are - // preferred to the ones under sysroot. - if (IsAndroid) { - addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib", Paths); - } - // Sourcery CodeBench MIPS toolchain holds some libraries under - // the parent prefix of the GCC installation. - if (IsMips) { - std::string Suffix; - appendMipsTargetSuffix(Suffix, Arch, Args); - addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + - Multilib + Suffix, - Paths); - } } addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths); addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths); addPathIfExists(SysRoot + "/usr/lib/" + MultiarchTriple, Paths); addPathIfExists(SysRoot + "/usr/lib/../" + Multilib, Paths); - // Try walking via the GCC triple path in case of multiarch GCC + // Try walking via the GCC triple path in case of biarch or multiarch GCC // installations with strange symlinks. - if (GCCInstallation.isValid()) + if (GCCInstallation.isValid()) { addPathIfExists(SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() + "/../../" + Multilib, Paths); - // Add the non-multilib suffixed paths (if potentially different). - if (GCCInstallation.isValid()) { + // Add the non-multilib suffixed paths (if potentially different). const std::string &LibPath = GCCInstallation.getParentLibPath(); const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); - if (!GCCInstallation.getMultiarchSuffix().empty()) - addPathIfExists(GCCInstallation.getInstallPath(), Paths); + if (!GCCInstallation.getBiarchSuffix().empty()) + addPathIfExists(GCCInstallation.getInstallPath() + + GCCInstallation.getMIPSABIDirSuffix(), Paths); - if (StringRef(LibPath).startswith(SysRoot)) { - addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib", Paths); + // See comments above on the multilib variant for details of why this is + // included even from outside the sysroot. + addPathIfExists(LibPath + "/../" + GCCTriple.str() + + "/lib" + GCCInstallation.getMIPSABIDirSuffix(), Paths); + + // See comments above on the multilib variant for details of why this is + // only included from within the sysroot. + if (StringRef(LibPath).startswith(SysRoot)) addPathIfExists(LibPath, Paths); - } } addPathIfExists(SysRoot + "/lib", Paths); addPathIfExists(SysRoot + "/usr/lib", Paths); +} - IsPIEDefault = SanitizerArgs(*this, Args).hasZeroBaseShadow(); +bool FreeBSD::HasNativeLLVMSupport() const { + return true; } bool Linux::HasNativeLLVMSupport() const { @@ -2393,8 +2540,8 @@ Tool *Linux::buildAssembler() const { void Linux::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args) const { const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion(); - bool UseInitArrayDefault - = V >= Generic_GCC::GCCVersion::Parse("4.7.0") || + bool UseInitArrayDefault = + !V.isOlderThan(4, 7, 0) || getTriple().getArch() == llvm::Triple::aarch64 || getTriple().getEnvironment() == llvm::Triple::Android; if (DriverArgs.hasFlag(options::OPT_fuse_init_array, @@ -2403,25 +2550,39 @@ void Linux::addClangTargetOptions(const ArgList &DriverArgs, CC1Args.push_back("-fuse-init-array"); } -std::string Linux::computeSysRoot(const ArgList &Args) const { +std::string Linux::computeSysRoot() const { if (!getDriver().SysRoot.empty()) return getDriver().SysRoot; if (!GCCInstallation.isValid() || !isMipsArch(getTriple().getArch())) return std::string(); - std::string Path = - (GCCInstallation.getInstallPath() + - "/../../../../" + GCCInstallation.getTriple().str() + "/libc").str(); - appendMipsTargetSuffix(Path, getTriple().getArch(), Args); + // Standalone MIPS toolchains use different names for sysroot folder + // and put it into different places. Here we try to check some known + // variants. + + const StringRef InstallDir = GCCInstallation.getInstallPath(); + const StringRef TripleStr = GCCInstallation.getTriple().str(); + const StringRef MIPSABIDirSuffix = GCCInstallation.getMIPSABIDirSuffix(); + + std::string Path = (InstallDir + "/../../../../" + TripleStr + "/libc" + + MIPSABIDirSuffix).str(); + + if (llvm::sys::fs::exists(Path)) + return Path; + + Path = (InstallDir + "/../../../../sysroot" + MIPSABIDirSuffix).str(); + + if (llvm::sys::fs::exists(Path)) + return Path; - return llvm::sys::fs::exists(Path) ? Path : ""; + return std::string(); } void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { const Driver &D = getDriver(); - std::string SysRoot = computeSysRoot(DriverArgs); + std::string SysRoot = computeSysRoot(); if (DriverArgs.hasArg(options::OPT_nostdinc)) return; @@ -2430,8 +2591,8 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include"); if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { - llvm::sys::Path P(D.ResourceDir); - P.appendComponent("include"); + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "include"); addSystemInclude(DriverArgs, CC1Args, P.str()); } @@ -2457,15 +2618,17 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // Sourcery CodeBench and modern FSF Mips toolchains put extern C // system includes under three additional directories. if (GCCInstallation.isValid() && isMipsArch(getTriple().getArch())) { - addExternCSystemIncludeIfExists(DriverArgs, CC1Args, - GCCInstallation.getInstallPath() + - "/include"); + addExternCSystemIncludeIfExists( + DriverArgs, CC1Args, GCCInstallation.getInstallPath() + "/include"); - addExternCSystemIncludeIfExists(DriverArgs, CC1Args, - GCCInstallation.getInstallPath() + - "/../../../../" + - GCCInstallation.getTriple().str() + - "/libc/usr/include"); + addExternCSystemIncludeIfExists( + DriverArgs, CC1Args, + GCCInstallation.getInstallPath() + "/../../../../" + + GCCInstallation.getTriple().str() + "/libc/usr/include"); + + addExternCSystemIncludeIfExists( + DriverArgs, CC1Args, + GCCInstallation.getInstallPath() + "/../../../../sysroot/usr/include"); } // Implement generic Debian multiarch support. @@ -2475,8 +2638,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // FIXME: These are older forms of multiarch. It's not clear that they're // in use in any released version of Debian, so we should consider // removing them. - "/usr/include/i686-linux-gnu/64", - "/usr/include/i486-linux-gnu/64" + "/usr/include/i686-linux-gnu/64", "/usr/include/i486-linux-gnu/64" }; const StringRef X86MultiarchIncludeDirs[] = { "/usr/include/i386-linux-gnu", @@ -2484,8 +2646,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // FIXME: These are older forms of multiarch. It's not clear that they're // in use in any released version of Debian, so we should consider // removing them. - "/usr/include/x86_64-linux-gnu/32", - "/usr/include/i686-linux-gnu", + "/usr/include/x86_64-linux-gnu/32", "/usr/include/i686-linux-gnu", "/usr/include/i486-linux-gnu" }; const StringRef AArch64MultiarchIncludeDirs[] = { @@ -2566,15 +2727,17 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, /// libstdc++ installation. /*static*/ bool Linux::addLibStdCXXIncludePaths(Twine Base, Twine Suffix, Twine TargetArchDir, - Twine MultiLibSuffix, + Twine BiarchSuffix, + Twine MIPSABIDirSuffix, const ArgList &DriverArgs, ArgStringList &CC1Args) { - if (!addLibStdCXXIncludePaths(Base+Suffix, TargetArchDir + MultiLibSuffix, + if (!addLibStdCXXIncludePaths(Base + Suffix, + TargetArchDir + MIPSABIDirSuffix + BiarchSuffix, DriverArgs, CC1Args)) return false; addSystemInclude(DriverArgs, CC1Args, Base + "/" + TargetArchDir + Suffix - + MultiLibSuffix); + + MIPSABIDirSuffix + BiarchSuffix); return true; } @@ -2602,37 +2765,39 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, // equivalent to '/usr/include/c++/X.Y' in almost all cases. StringRef LibDir = GCCInstallation.getParentLibPath(); StringRef InstallDir = GCCInstallation.getInstallPath(); - StringRef Version = GCCInstallation.getVersion().Text; StringRef TripleStr = GCCInstallation.getTriple().str(); + StringRef MIPSABIDirSuffix = GCCInstallation.getMIPSABIDirSuffix(); + StringRef BiarchSuffix = GCCInstallation.getBiarchSuffix(); + const GCCVersion &Version = GCCInstallation.getVersion(); - if (addLibStdCXXIncludePaths(LibDir.str() + "/../include", - "/c++/" + Version.str(), - TripleStr, - GCCInstallation.getMultiarchSuffix(), - DriverArgs, CC1Args)) + if (addLibStdCXXIncludePaths(LibDir.str() + "/../include", + "/c++/" + Version.Text, TripleStr, BiarchSuffix, + MIPSABIDirSuffix, DriverArgs, CC1Args)) return; const std::string IncludePathCandidates[] = { // Gentoo is weird and places its headers inside the GCC install, so if the - // first attempt to find the headers fails, try this pattern. - InstallDir.str() + "/include/g++-v4", + // first attempt to find the headers fails, try these patterns. + InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." + + Version.MinorStr, + InstallDir.str() + "/include/g++-v" + Version.MajorStr, // Android standalone toolchain has C++ headers in yet another place. - LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.str(), + LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, // Freescale SDK C++ headers are directly in <sysroot>/usr/include/c++, // without a subdirectory corresponding to the gcc version. LibDir.str() + "/../include/c++", }; for (unsigned i = 0; i < llvm::array_lengthof(IncludePathCandidates); ++i) { - if (addLibStdCXXIncludePaths(IncludePathCandidates[i], (TripleStr + - GCCInstallation.getMultiarchSuffix()), - DriverArgs, CC1Args)) + if (addLibStdCXXIncludePaths(IncludePathCandidates[i], + TripleStr + MIPSABIDirSuffix + BiarchSuffix, + DriverArgs, CC1Args)) break; } } bool Linux::isPIEDefault() const { - return IsPIEDefault; + return getSanitizerArgs().hasZeroBaseShadow(); } /// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly. @@ -2660,3 +2825,77 @@ Tool *DragonFly::buildAssembler() const { Tool *DragonFly::buildLinker() const { return new tools::dragonfly::Link(*this); } + + +/// XCore tool chain +XCore::XCore(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) : ToolChain(D, Triple, Args) { + // ProgramPaths are found via 'PATH' environment variable. +} + +Tool *XCore::buildAssembler() const { + return new tools::XCore::Assemble(*this); +} + +Tool *XCore::buildLinker() const { + return new tools::XCore::Link(*this); +} + +bool XCore::isPICDefault() const { + return false; +} + +bool XCore::isPIEDefault() const { + return false; +} + +bool XCore::isPICDefaultForced() const { + return false; +} + +bool XCore::SupportsProfiling() const { + return false; +} + +bool XCore::hasBlocksRuntime() const { + return false; +} + + +void XCore::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc) || + DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + if (const char *cl_include_dir = getenv("XCC_C_INCLUDE_PATH")) { + SmallVector<StringRef, 4> Dirs; + const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator,'\0'}; + StringRef(cl_include_dir).split(Dirs, StringRef(EnvPathSeparatorStr)); + ArrayRef<StringRef> DirVec(Dirs); + addSystemIncludes(DriverArgs, CC1Args, DirVec); + } +} + +void XCore::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + CC1Args.push_back("-nostdsysteminc"); +} + +void XCore::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc) || + DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + if (const char *cl_include_dir = getenv("XCC_CPLUS_INCLUDE_PATH")) { + SmallVector<StringRef, 4> Dirs; + const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator,'\0'}; + StringRef(cl_include_dir).split(Dirs, StringRef(EnvPathSeparatorStr)); + ArrayRef<StringRef> DirVec(Dirs); + addSystemIncludes(DriverArgs, CC1Args, DirVec); + } +} + +void XCore::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // We don't output any lib args. This is handled by xcc. +} diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains.h index 50145e7..ba794a7 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains.h @@ -16,6 +16,8 @@ #include "clang/Driver/ToolChain.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/Compiler.h" +#include <vector> +#include <set> namespace clang { namespace driver { @@ -48,11 +50,18 @@ protected: /// \brief The parsed major, minor, and patch numbers. int Major, Minor, Patch; + /// \brief The text of the parsed major, and major+minor versions. + std::string MajorStr, MinorStr; + /// \brief Any textual suffix on the patch number. std::string PatchSuffix; static GCCVersion Parse(StringRef VersionText); - bool operator<(const GCCVersion &RHS) const; + bool isOlderThan(int RHSMajor, int RHSMinor, int RHSPatch, + StringRef RHSPatchSuffix = StringRef()) const; + bool operator<(const GCCVersion &RHS) const { + return isOlderThan(RHS.Major, RHS.Minor, RHS.Patch, RHS.PatchSuffix); + } bool operator>(const GCCVersion &RHS) const { return RHS < *this; } bool operator<=(const GCCVersion &RHS) const { return !(*this > RHS); } bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); } @@ -66,21 +75,25 @@ protected: /// information about it. It starts from the host information provided to the /// Driver, and has logic for fuzzing that where appropriate. class GCCInstallationDetector { - bool IsValid; + const Driver &D; llvm::Triple GCCTriple; // FIXME: These might be better as path objects. std::string GCCInstallPath; - std::string GCCMultiarchSuffix; + std::string GCCBiarchSuffix; std::string GCCParentLibPath; + std::string GCCMIPSABIDirSuffix; GCCVersion Version; + // We retain the list of install paths that were considered and rejected in + // order to print out detailed information in verbose mode. + std::set<std::string> CandidateGCCInstallPaths; + public: - GCCInstallationDetector() : IsValid(false) {} - void init(const Driver &D, const llvm::Triple &TargetTriple, - const ArgList &Args); + GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {} + void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args); /// \brief Check whether we detected a valid GCC install. bool isValid() const { return IsValid; } @@ -91,37 +104,62 @@ protected: /// \brief Get the detected GCC installation path. StringRef getInstallPath() const { return GCCInstallPath; } - /// \brief Get the detected GCC installation path suffix for multiarch GCCs. - StringRef getMultiarchSuffix() const { return GCCMultiarchSuffix; } + /// \brief Get the detected GCC installation path suffix for the bi-arch + /// target variant. + StringRef getBiarchSuffix() const { return GCCBiarchSuffix; } /// \brief Get the detected GCC parent lib path. StringRef getParentLibPath() const { return GCCParentLibPath; } + /// \brief Get the detected GCC MIPS ABI directory suffix. + /// + /// This is used as a suffix both to the install directory of GCC and as + /// a suffix to its parent lib path in order to select a MIPS ABI-specific + /// subdirectory. + /// + /// This will always be empty for any non-MIPS target. + /// + // FIXME: This probably shouldn't exist at all, and should be factored + // into the multiarch and/or biarch support. Please don't add more uses of + // this interface, it is meant as a legacy crutch for the MIPS driver + // logic. + StringRef getMIPSABIDirSuffix() const { return GCCMIPSABIDirSuffix; } + /// \brief Get the detected GCC version string. const GCCVersion &getVersion() const { return Version; } + /// \brief Print information about the detected GCC installation. + void print(raw_ostream &OS) const; + private: - static void CollectLibDirsAndTriples( - const llvm::Triple &TargetTriple, - const llvm::Triple &MultiarchTriple, - SmallVectorImpl<StringRef> &LibDirs, - SmallVectorImpl<StringRef> &TripleAliases, - SmallVectorImpl<StringRef> &MultiarchLibDirs, - SmallVectorImpl<StringRef> &MultiarchTripleAliases); + static void + CollectLibDirsAndTriples(const llvm::Triple &TargetTriple, + const llvm::Triple &BiarchTriple, + SmallVectorImpl<StringRef> &LibDirs, + SmallVectorImpl<StringRef> &TripleAliases, + SmallVectorImpl<StringRef> &BiarchLibDirs, + SmallVectorImpl<StringRef> &BiarchTripleAliases); void ScanLibDirForGCCTriple(llvm::Triple::ArchType TargetArch, - const ArgList &Args, + const llvm::opt::ArgList &Args, const std::string &LibDir, StringRef CandidateTriple, - bool NeedsMultiarchSuffix = false); + bool NeedsBiarchSuffix = false); + + void findMIPSABIDirSuffix(std::string &Suffix, + llvm::Triple::ArchType TargetArch, StringRef Path, + const llvm::opt::ArgList &Args); }; GCCInstallationDetector GCCInstallation; public: - Generic_GCC(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); + Generic_GCC(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); ~Generic_GCC(); + virtual void printVerboseInfo(raw_ostream &OS) const; + virtual bool IsUnwindTablesDefault() const; virtual bool isPICDefault() const; virtual bool isPIEDefault() const; @@ -191,13 +229,14 @@ private: std::string iOSVersionMin; private: - void AddDeploymentTarget(DerivedArgList &Args) const; + void AddDeploymentTarget(llvm::opt::DerivedArgList &Args) const; public: - Darwin(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); + Darwin(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); ~Darwin(); - std::string ComputeEffectiveClangTriple(const ArgList &Args, + std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, types::ID InputType) const; /// @name Darwin Specific Toolchain API @@ -247,7 +286,7 @@ public: /// getDarwinArchName - Get the "Darwin" arch name for a particular compiler /// invocation. For example, Darwin treats different ARM variations as /// distinct architectures. - StringRef getDarwinArchName(const ArgList &Args) const; + StringRef getDarwinArchName(const llvm::opt::ArgList &Args) const; bool isIPhoneOSVersionLT(unsigned V0, unsigned V1=0, unsigned V2=0) const { assert(isTargetIPhoneOS() && "Unexpected call for OS X target!"); @@ -260,14 +299,15 @@ public: } /// AddLinkARCArgs - Add the linker arguments to link the ARC runtime library. - virtual void AddLinkARCArgs(const ArgList &Args, - ArgStringList &CmdArgs) const = 0; - + virtual void AddLinkARCArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const = 0; + /// AddLinkRuntimeLibArgs - Add the linker arguments to link the compiler /// runtime library. - virtual void AddLinkRuntimeLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const = 0; - + virtual void + AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const = 0; + /// } /// @name ToolChain Implementation /// { @@ -279,8 +319,9 @@ public: virtual ObjCRuntime getDefaultObjCRuntime(bool isNonFragile) const; virtual bool hasBlocksRuntime() const; - virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args, - const char *BoundArch) const; + virtual llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, + const char *BoundArch) const; virtual bool IsBlocksDefault() const { // Always allow blocks on Darwin; users interested in versioning are @@ -288,19 +329,8 @@ public: return true; } virtual bool IsIntegratedAssemblerDefault() const { -#ifdef DISABLE_DEFAULT_INTEGRATED_ASSEMBLER - return false; -#else // Default integrated assembler to on for Darwin. return true; -#endif - } - virtual bool IsStrictAliasingDefault() const { -#ifdef DISABLE_DEFAULT_STRICT_ALIASING - return false; -#else - return ToolChain::IsStrictAliasingDefault(); -#endif } virtual bool IsMathErrnoDefault() const { @@ -353,35 +383,38 @@ public: /// DarwinClang - The Darwin toolchain used by Clang. class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin { public: - DarwinClang(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); + DarwinClang(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); /// @name Darwin ToolChain Implementation /// { - virtual void AddLinkRuntimeLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const; - void AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, + virtual void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddLinkRuntimeLib(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, const char *DarwinStaticLib, bool AlwaysLink = false) const; - virtual void AddCXXStdlibLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const; + virtual void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; - virtual void AddCCKextLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const; + virtual void AddCCKextLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; - virtual void AddLinkARCArgs(const ArgList &Args, - ArgStringList &CmdArgs) const; + virtual void AddLinkARCArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; /// } }; /// Darwin_Generic_GCC - Generic Darwin tool chain using gcc. class LLVM_LIBRARY_VISIBILITY Darwin_Generic_GCC : public Generic_GCC { public: - Darwin_Generic_GCC(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) - : Generic_GCC(D, Triple, Args) {} + Darwin_Generic_GCC(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : Generic_GCC(D, Triple, Args) {} - std::string ComputeEffectiveClangTriple(const ArgList &Args, + std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, types::ID InputType) const; virtual bool isPICDefault() const { return false; } @@ -390,8 +423,9 @@ public: class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC { virtual void anchor(); public: - Generic_ELF(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) - : Generic_GCC(D, Triple, Args) {} + Generic_ELF(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : Generic_GCC(D, Triple, Args) {} virtual bool IsIntegratedAssemblerDefault() const { // Default integrated assembler to on for x86. @@ -403,7 +437,8 @@ public: class LLVM_LIBRARY_VISIBILITY AuroraUX : public Generic_GCC { public: - AuroraUX(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); + AuroraUX(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); protected: virtual Tool *buildAssembler() const; @@ -412,7 +447,8 @@ protected: class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_GCC { public: - Solaris(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); + Solaris(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); virtual bool IsIntegratedAssemblerDefault() const { return true; } protected: @@ -424,10 +460,16 @@ protected: class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_ELF { public: - OpenBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); + OpenBSD(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); virtual bool IsMathErrnoDefault() const { return false; } virtual bool IsObjCNonFragileABIDefault() const { return true; } + virtual bool isPIEDefault() const { return true; } + + virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const { + return 1; + } protected: virtual Tool *buildAssembler() const; @@ -436,16 +478,18 @@ protected: class LLVM_LIBRARY_VISIBILITY Bitrig : public Generic_ELF { public: - Bitrig(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); + Bitrig(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); virtual bool IsMathErrnoDefault() const { return false; } virtual bool IsObjCNonFragileABIDefault() const { return true; } virtual bool IsObjCLegacyDispatchDefault() const { return false; } - virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const; - virtual void AddCXXStdlibLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const; + virtual void + AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + virtual void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const { return 1; } @@ -457,15 +501,23 @@ protected: class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF { public: - FreeBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); - - virtual CXXStdlibType GetCXXStdlibType(const ArgList &Args) const; + FreeBSD(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + virtual bool HasNativeLLVMSupport() const; virtual bool IsMathErrnoDefault() const { return false; } virtual bool IsObjCNonFragileABIDefault() const { return true; } - virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const; + virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const; + virtual void + AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + virtual bool IsIntegratedAssemblerDefault() const { + if (getTriple().getArch() == llvm::Triple::ppc || + getTriple().getArch() == llvm::Triple::ppc64) + return true; + return Generic_ELF::IsIntegratedAssemblerDefault(); + } virtual bool UseSjLjExceptions() const; protected: @@ -475,15 +527,25 @@ protected: class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF { public: - NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); + NetBSD(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); virtual bool IsMathErrnoDefault() const { return false; } virtual bool IsObjCNonFragileABIDefault() const { return true; } - virtual CXXStdlibType GetCXXStdlibType(const ArgList &Args) const; + virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const; - virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const; + virtual void + AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + virtual bool IsUnwindTablesDefault() const { + return true; + } + virtual bool IsIntegratedAssemblerDefault() const { + if (getTriple().getArch() == llvm::Triple::ppc) + return true; + return Generic_ELF::IsIntegratedAssemblerDefault(); + } protected: virtual Tool *buildAssembler() const; @@ -492,7 +554,8 @@ protected: class LLVM_LIBRARY_VISIBILITY Minix : public Generic_ELF { public: - Minix(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); + Minix(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); protected: virtual Tool *buildAssembler() const; @@ -501,7 +564,8 @@ protected: class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_ELF { public: - DragonFly(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); + DragonFly(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); virtual bool IsMathErrnoDefault() const { return false; } @@ -512,21 +576,23 @@ protected: class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF { public: - Linux(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); + Linux(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); virtual bool HasNativeLLVMSupport() const; - virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const; - virtual void addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const; - virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const; + virtual void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + virtual void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + virtual void + AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; virtual bool isPIEDefault() const; std::string Linker; std::vector<std::string> ExtraOpts; - bool IsPIEDefault; protected: virtual Tool *buildAssembler() const; @@ -535,14 +601,15 @@ protected: private: static bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, Twine TargetArchDir, - Twine MultiLibSuffix, - const ArgList &DriverArgs, - ArgStringList &CC1Args); + Twine BiarchSuffix, + Twine MIPSABIDirSuffix, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args); static bool addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir, - const ArgList &DriverArgs, - ArgStringList &CC1Args); + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args); - std::string computeSysRoot(const ArgList &Args) const; + std::string computeSysRoot() const; }; class LLVM_LIBRARY_VISIBILITY Hexagon_TC : public Linux { @@ -553,28 +620,30 @@ protected: public: Hexagon_TC(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args); + const llvm::opt::ArgList &Args); ~Hexagon_TC(); - virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const; - virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const; - virtual CXXStdlibType GetCXXStdlibType(const ArgList &Args) const; + virtual void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + virtual void + AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const; StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; } static std::string GetGnuDir(const std::string &InstalledDir); - static StringRef GetTargetCPU(const ArgList &Args); + static StringRef GetTargetCPU(const llvm::opt::ArgList &Args); }; /// TCEToolChain - A tool chain using the llvm bitcode tools to perform /// all subcommands. See http://tce.cs.tut.fi for our peculiar target. class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain { public: - TCEToolChain(const Driver &D, const llvm::Triple& Triple, - const ArgList &Args); + TCEToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); ~TCEToolChain(); bool IsMathErrnoDefault() const; @@ -585,7 +654,8 @@ public: class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain { public: - Windows(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); + Windows(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); virtual bool IsIntegratedAssemblerDefault() const; virtual bool IsUnwindTablesDefault() const; @@ -593,15 +663,42 @@ public: virtual bool isPIEDefault() const; virtual bool isPICDefaultForced() const; - virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const; - virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const; + virtual void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + virtual void + AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + protected: virtual Tool *buildLinker() const; virtual Tool *buildAssembler() const; }; + +class LLVM_LIBRARY_VISIBILITY XCore : public ToolChain { +public: + XCore(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; +public: + virtual bool isPICDefault() const; + virtual bool isPIEDefault() const; + virtual bool isPICDefaultForced() const; + virtual bool SupportsProfiling() const; + virtual bool hasBlocksRuntime() const; + virtual void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + virtual void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + virtual void AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + virtual void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; +}; + } // end namespace toolchains } // end namespace driver } // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp index 26b69f3..3529fc7 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp @@ -7,43 +7,48 @@ // //===----------------------------------------------------------------------===// -#include <sys/stat.h> #include "Tools.h" #include "InputInfo.h" -#include "SanitizerArgs.h" #include "ToolChains.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" #include "clang/Driver/Action.h" -#include "clang/Driver/Arg.h" -#include "clang/Driver/ArgList.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Job.h" -#include "clang/Driver/Option.h" #include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" #include "clang/Driver/ToolChain.h" #include "clang/Driver/Util.h" +#include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/Host.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" #include "llvm/Support/Process.h" #include "llvm/Support/raw_ostream.h" +#include <sys/stat.h> using namespace clang::driver; using namespace clang::driver::tools; using namespace clang; +using namespace llvm::opt; /// CheckPreprocessingOptions - Perform some validation of preprocessing /// arguments that is shared with gcc. static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) { if (Arg *A = Args.getLastArg(options::OPT_C, options::OPT_CC)) - if (!Args.hasArg(options::OPT_E) && !D.CCCIsCPP) + if (!Args.hasArg(options::OPT_E) && !D.CCCIsCPP()) D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) << "-E"; } @@ -107,7 +112,7 @@ static void addDirectoryList(const ArgList &Args, return; StringRef::size_type Delim; - while ((Delim = Dirs.find(llvm::sys::PathSeparator)) != StringRef::npos) { + while ((Delim = Dirs.find(llvm::sys::EnvPathSeparator)) != StringRef::npos) { if (Delim == 0) { // Leading colon. if (CombinedArg) { CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + ".")); @@ -223,7 +228,9 @@ static void addProfileRT(const ToolChain &TC, const ArgList &Args, } static bool forwardToGCC(const Option &O) { - return !O.hasFlag(options::NoForward) && + // Don't forward inputs from the original command line. They are added from + // InputInfoList. + return O.getKind() != Option::InputClass && !O.hasFlag(options::DriverOption) && !O.hasFlag(options::LinkerInput); } @@ -339,32 +346,28 @@ void Clang::AddPreprocessingOptions(Compilation &C, bool FoundPTH = false; bool FoundPCH = false; - llvm::sys::Path P(A->getValue()); - bool Exists; + SmallString<128> P(A->getValue()); + // We want the files to have a name like foo.h.pch. Add a dummy extension + // so that replace_extension does the right thing. + P += ".dummy"; if (UsePCH) { - P.appendSuffix("pch"); - if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) + llvm::sys::path::replace_extension(P, "pch"); + if (llvm::sys::fs::exists(P.str())) FoundPCH = true; - else - P.eraseSuffix(); } if (!FoundPCH) { - P.appendSuffix("pth"); - if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) + llvm::sys::path::replace_extension(P, "pth"); + if (llvm::sys::fs::exists(P.str())) FoundPTH = true; - else - P.eraseSuffix(); } if (!FoundPCH && !FoundPTH) { - P.appendSuffix("gch"); - if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) { + llvm::sys::path::replace_extension(P, "gch"); + if (llvm::sys::fs::exists(P.str())) { FoundPCH = UsePCH; FoundPTH = !UsePCH; } - else - P.eraseSuffix(); } if (FoundPCH || FoundPTH) { @@ -446,6 +449,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, // FIXME: tblgen this, or kill it! static const char *getLLVMArchSuffixForARM(StringRef CPU) { return llvm::StringSwitch<const char *>(CPU) + .Case("strongarm", "v4") .Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "v4t") .Cases("arm720t", "arm9", "arm9tdmi", "v4t") .Cases("arm920", "arm920t", "arm922t", "v4t") @@ -458,13 +462,14 @@ static const char *getLLVMArchSuffixForARM(StringRef CPU) { .Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6") .Cases("arm1156t2-s", "arm1156t2f-s", "v6t2") .Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7") - .Cases("cortex-a9", "cortex-a15", "v7") - .Case("cortex-r5", "v7r") + .Cases("cortex-a9", "cortex-a12", "cortex-a15", "v7") + .Cases("cortex-r4", "cortex-r5", "v7r") .Case("cortex-m0", "v6m") .Case("cortex-m3", "v7m") .Case("cortex-m4", "v7em") .Case("cortex-a9-mp", "v7f") .Case("swift", "v7s") + .Cases("cortex-a53", "cortex-a57", "v8") .Default(""); } @@ -494,6 +499,11 @@ static std::string getARMTargetCPU(const ArgList &Args, MArch = Triple.getArchName(); } + if (Triple.getOS() == llvm::Triple::NetBSD) { + if (MArch == "armv6") + return "arm1176jzf-s"; + } + // Handle -march=native. std::string NativeMArch; if (MArch == "native") { @@ -510,7 +520,8 @@ static std::string getARMTargetCPU(const ArgList &Args, .Cases("armv2", "armv2a","arm2") .Case("armv3", "arm6") .Case("armv3m", "arm7m") - .Cases("armv4", "armv4t", "arm7tdmi") + .Case("armv4", "strongarm") + .Case("armv4t", "arm7tdmi") .Cases("armv5", "armv5t", "arm10tdmi") .Cases("armv5e", "armv5te", "arm1022e") .Case("armv5tej", "arm926ej-s") @@ -525,13 +536,35 @@ static std::string getARMTargetCPU(const ArgList &Args, .Cases("armv7s", "armv7-s", "swift") .Cases("armv7r", "armv7-r", "cortex-r4") .Cases("armv7m", "armv7-m", "cortex-m3") + .Cases("armv8", "armv8a", "armv8-a", "cortex-a53") .Case("ep9312", "ep9312") .Case("iwmmxt", "iwmmxt") .Case("xscale", "xscale") - // If all else failed, return the most base CPU LLVM supports. + // If all else failed, return the most base CPU with thumb interworking + // supported by LLVM. .Default("arm7tdmi"); } +/// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are targeting. +// +// FIXME: tblgen this. +static std::string getAArch64TargetCPU(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)) { + StringRef MCPU = A->getValue(); + // Handle -mcpu=native. + if (MCPU == "native") + return llvm::sys::getHostCPUName(); + else + return MCPU; + } + + return "generic"; +} + // FIXME: Move to target hook. static bool isSignedCharDefault(const llvm::Triple &Triple) { switch (Triple.getArch()) { @@ -546,73 +579,117 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) { return true; return false; + case llvm::Triple::ppc64le: case llvm::Triple::systemz: + case llvm::Triple::xcore: return false; } } +static bool isNoCommonDefault(const llvm::Triple &Triple) { + switch (Triple.getArch()) { + default: + return false; + + case llvm::Triple::xcore: + return true; + } +} + +// Handle -mfpu=. +// +// FIXME: Centralize feature selection, defaulting shouldn't be also in the +// frontend target. +static void getAArch64FPUFeatures(const Driver &D, const Arg *A, + const ArgList &Args, + std::vector<const char *> &Features) { + StringRef FPU = A->getValue(); + if (FPU == "fp-armv8") { + Features.push_back("+fp-armv8"); + } else if (FPU == "neon-fp-armv8") { + Features.push_back("+fp-armv8"); + Features.push_back("+neon"); + } else if (FPU == "crypto-neon-fp-armv8") { + Features.push_back("+fp-armv8"); + Features.push_back("+neon"); + Features.push_back("+crypto"); + } else if (FPU == "neon") { + Features.push_back("+neon"); + } else if (FPU == "none") { + Features.push_back("-fp-armv8"); + Features.push_back("-crypto"); + Features.push_back("-neon"); + } else + D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); +} + +// Handle -mhwdiv=. +static void getARMHWDivFeatures(const Driver &D, const Arg *A, + const ArgList &Args, + std::vector<const char *> &Features) { + StringRef HWDiv = A->getValue(); + if (HWDiv == "arm") { + Features.push_back("+hwdiv-arm"); + Features.push_back("-hwdiv"); + } else if (HWDiv == "thumb") { + Features.push_back("-hwdiv-arm"); + Features.push_back("+hwdiv"); + } else if (HWDiv == "arm,thumb" || HWDiv == "thumb,arm") { + Features.push_back("+hwdiv-arm"); + Features.push_back("+hwdiv"); + } else if (HWDiv == "none") { + Features.push_back("-hwdiv-arm"); + Features.push_back("-hwdiv"); + } else + D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); +} + // Handle -mfpu=. // // FIXME: Centralize feature selection, defaulting shouldn't be also in the // frontend target. -static void addFPUArgs(const Driver &D, const Arg *A, const ArgList &Args, - ArgStringList &CmdArgs) { +static void getARMFPUFeatures(const Driver &D, const Arg *A, + const ArgList &Args, + std::vector<const char *> &Features) { StringRef FPU = A->getValue(); // Set the target features based on the FPU. if (FPU == "fpa" || FPU == "fpe2" || FPU == "fpe3" || FPU == "maverick") { // Disable any default FPU support. - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("-vfp2"); - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("-vfp3"); - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("-neon"); + Features.push_back("-vfp2"); + Features.push_back("-vfp3"); + Features.push_back("-neon"); } else if (FPU == "vfp3-d16" || FPU == "vfpv3-d16") { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("+vfp3"); - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("+d16"); - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("-neon"); + Features.push_back("+vfp3"); + Features.push_back("+d16"); + Features.push_back("-neon"); } else if (FPU == "vfp") { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("+vfp2"); - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("-neon"); + Features.push_back("+vfp2"); + Features.push_back("-neon"); } else if (FPU == "vfp3" || FPU == "vfpv3") { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("+vfp3"); - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("-neon"); + Features.push_back("+vfp3"); + Features.push_back("-neon"); + } else if (FPU == "fp-armv8") { + Features.push_back("+fp-armv8"); + Features.push_back("-neon"); + Features.push_back("-crypto"); + } else if (FPU == "neon-fp-armv8") { + Features.push_back("+fp-armv8"); + Features.push_back("+neon"); + Features.push_back("-crypto"); + } else if (FPU == "crypto-neon-fp-armv8") { + Features.push_back("+fp-armv8"); + Features.push_back("+neon"); + Features.push_back("+crypto"); } else if (FPU == "neon") { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("+neon"); - } else - D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); -} - -// Handle -mfpmath=. -static void addFPMathArgs(const Driver &D, const Arg *A, const ArgList &Args, - ArgStringList &CmdArgs, StringRef CPU) { - StringRef FPMath = A->getValue(); - - // Set the target features based on the FPMath. - if (FPMath == "neon") { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("+neonfp"); - - if (CPU != "cortex-a5" && CPU != "cortex-a7" && - CPU != "cortex-a8" && CPU != "cortex-a9" && - CPU != "cortex-a9-mp" && CPU != "cortex-a15") - D.Diag(diag::err_drv_invalid_feature) << "-mfpmath=neon" << CPU; - - } else if (FPMath == "vfp" || FPMath == "vfp2" || FPMath == "vfp3" || - FPMath == "vfp4") { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("-neonfp"); - - // FIXME: Add warnings when disabling a feature not present for a given CPU. + Features.push_back("+neon"); + } else if (FPU == "none") { + Features.push_back("-vfp2"); + Features.push_back("-vfp3"); + Features.push_back("-vfp4"); + Features.push_back("-fp-armv8"); + Features.push_back("-crypto"); + Features.push_back("-neon"); } else D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } @@ -697,6 +774,41 @@ static StringRef getARMFloatABI(const Driver &D, return FloatABI; } +static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args, + std::vector<const char *> &Features) { + StringRef FloatABI = getARMFloatABI(D, Args, Triple); + // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these + // yet (it uses the -mfloat-abi and -msoft-float options), and it is + // stripped out by the ARM target. + // Use software floating point operations? + if (FloatABI == "soft") + Features.push_back("+soft-float"); + + // Use software floating point argument passing? + if (FloatABI != "hard") + Features.push_back("+soft-float-abi"); + + // Honor -mfpu=. + if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) + getARMFPUFeatures(D, A, Args, Features); + if (const Arg *A = Args.getLastArg(options::OPT_mhwdiv_EQ)) + getARMHWDivFeatures(D, A, Args, Features); + + // Setting -msoft-float effectively disables NEON because of the GCC + // implementation, although the same isn't true of VFP or VFP3. + if (FloatABI == "soft") + Features.push_back("-neon"); + + // En/disable crc + if (Arg *A = Args.getLastArg(options::OPT_mcrc, + options::OPT_mnocrc)) { + if (A->getOption().matches(options::OPT_mcrc)) + Features.push_back("+crc"); + else + Features.push_back("-crc"); + } +} void Clang::AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs, @@ -716,7 +828,8 @@ void Clang::AddARMTargetArgs(const ArgList &Args, } else if (Triple.isOSDarwin()) { // The backend is hardwired to assume AAPCS for M-class processors, ensure // the frontend matches that. - if (StringRef(CPUName).startswith("cortex-m")) { + if (Triple.getEnvironment() == llvm::Triple::EABI || + StringRef(CPUName).startswith("cortex-m")) { ABIName = "aapcs"; } else { ABIName = "apcs-gnu"; @@ -739,10 +852,6 @@ void Clang::AddARMTargetArgs(const ArgList &Args, CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName); - // Set the CPU based on -march= and -mcpu=. - CmdArgs.push_back("-target-cpu"); - CmdArgs.push_back(Args.MakeArgString(CPUName)); - // Determine floating point ABI from the options & target defaults. StringRef FloatABI = getARMFloatABI(D, Args, Triple); if (FloatABI == "soft") { @@ -763,42 +872,9 @@ void Clang::AddARMTargetArgs(const ArgList &Args, CmdArgs.push_back("hard"); } - // Set appropriate target features for floating point mode. - // - // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these - // yet (it uses the -mfloat-abi and -msoft-float options above), and it is - // stripped out by the ARM target. - - // Use software floating point operations? - if (FloatABI == "soft") { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("+soft-float"); - } - - // Use software floating point argument passing? - if (FloatABI != "hard") { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("+soft-float-abi"); - } - - // Honor -mfpu=. - if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) - addFPUArgs(D, A, Args, CmdArgs); - - // Honor -mfpmath=. - if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) - addFPMathArgs(D, A, Args, CmdArgs, getARMTargetCPU(Args, Triple)); - - // Setting -msoft-float effectively disables NEON because of the GCC - // implementation, although the same isn't true of VFP or VFP3. - if (FloatABI == "soft") { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("-neon"); - } - // Kernel code has more strict alignment requirements. if (KernelOrKext) { - if (Triple.getOS() != llvm::Triple::IOS || Triple.isOSVersionLT(6)) { + if (!Triple.isiOS() || Triple.isOSVersionLT(6)) { CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-long-calls"); } @@ -808,7 +884,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args, // The kext linker doesn't know how to deal with movw/movt. CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-arm-darwin-use-movt=0"); + CmdArgs.push_back("-arm-use-movt=0"); } // Setting -mno-global-merge disables the codegen global merge pass. Setting @@ -823,39 +899,28 @@ void Clang::AddARMTargetArgs(const ArgList &Args, options::OPT_mno_implicit_float, true)) CmdArgs.push_back("-no-implicit-float"); -} -// Translate MIPS CPU name alias option to CPU name. -static StringRef getMipsCPUFromAlias(const Arg &A) { - if (A.getOption().matches(options::OPT_mips32)) - return "mips32"; - if (A.getOption().matches(options::OPT_mips32r2)) - return "mips32r2"; - if (A.getOption().matches(options::OPT_mips64)) - return "mips64"; - if (A.getOption().matches(options::OPT_mips64r2)) - return "mips64r2"; - llvm_unreachable("Unexpected option"); - return ""; + // llvm does not support reserving registers in general. There is support + // for reserving r9 on ARM though (defined as a platform-specific register + // in ARM EABI). + if (Args.hasArg(options::OPT_ffixed_r9)) { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-arm-reserve-r9"); + } } // Get CPU and ABI names. They are not independent // so we have to calculate them together. static void getMipsCPUAndABI(const ArgList &Args, - const ToolChain &TC, + const llvm::Triple &Triple, StringRef &CPUName, StringRef &ABIName) { const char *DefMips32CPU = "mips32"; const char *DefMips64CPU = "mips64"; if (Arg *A = Args.getLastArg(options::OPT_march_EQ, - options::OPT_mcpu_EQ, - options::OPT_mips_CPUs_Group)) { - if (A->getOption().matches(options::OPT_mips_CPUs_Group)) - CPUName = getMipsCPUFromAlias(*A); - else - CPUName = A->getValue(); - } + options::OPT_mcpu_EQ)) + CPUName = A->getValue(); if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { ABIName = A->getValue(); @@ -869,7 +934,7 @@ static void getMipsCPUAndABI(const ArgList &Args, // Setup default CPU and ABI names. if (CPUName.empty() && ABIName.empty()) { - switch (TC.getTriple().getArch()) { + switch (Triple.getArch()) { default: llvm_unreachable("Unexpected triple arch name"); case llvm::Triple::mips: @@ -941,28 +1006,56 @@ static StringRef getMipsFloatABI(const Driver &D, const ArgList &Args) { } static void AddTargetFeature(const ArgList &Args, - ArgStringList &CmdArgs, - OptSpecifier OnOpt, - OptSpecifier OffOpt, + std::vector<const char *> &Features, + OptSpecifier OnOpt, OptSpecifier OffOpt, StringRef FeatureName) { if (Arg *A = Args.getLastArg(OnOpt, OffOpt)) { - CmdArgs.push_back("-target-feature"); if (A->getOption().matches(OnOpt)) - CmdArgs.push_back(Args.MakeArgString("+" + FeatureName)); + Features.push_back(Args.MakeArgString("+" + FeatureName)); else - CmdArgs.push_back(Args.MakeArgString("-" + FeatureName)); + Features.push_back(Args.MakeArgString("-" + FeatureName)); } } +static void getMIPSTargetFeatures(const Driver &D, const ArgList &Args, + std::vector<const char *> &Features) { + StringRef FloatABI = getMipsFloatABI(D, Args); + bool IsMips16 = Args.getLastArg(options::OPT_mips16) != NULL; + if (FloatABI == "soft" || (FloatABI == "hard" && IsMips16)) { + // FIXME: Note, this is a hack. We need to pass the selected float + // mode to the MipsTargetInfoBase to define appropriate macros there. + // Now it is the only method. + Features.push_back("+soft-float"); + } + + if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) { + if (StringRef(A->getValue()) == "2008") + Features.push_back("+nan2008"); + } + + AddTargetFeature(Args, Features, options::OPT_msingle_float, + options::OPT_mdouble_float, "single-float"); + AddTargetFeature(Args, Features, options::OPT_mips16, options::OPT_mno_mips16, + "mips16"); + AddTargetFeature(Args, Features, options::OPT_mmicromips, + options::OPT_mno_micromips, "micromips"); + AddTargetFeature(Args, Features, options::OPT_mdsp, options::OPT_mno_dsp, + "dsp"); + AddTargetFeature(Args, Features, options::OPT_mdspr2, options::OPT_mno_dspr2, + "dspr2"); + AddTargetFeature(Args, Features, options::OPT_mmsa, options::OPT_mno_msa, + "msa"); + AddTargetFeature(Args, Features, options::OPT_mfp64, options::OPT_mfp32, + "fp64"); +} + void Clang::AddMIPSTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); StringRef CPUName; StringRef ABIName; - getMipsCPUAndABI(Args, getToolChain(), CPUName, ABIName); - - CmdArgs.push_back("-target-cpu"); - CmdArgs.push_back(CPUName.data()); + const llvm::Triple &Triple = getToolChain().getTriple(); + getMipsCPUAndABI(Args, Triple, CPUName, ABIName); CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName.data()); @@ -977,12 +1070,6 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, CmdArgs.push_back("-mfloat-abi"); CmdArgs.push_back("soft"); - // FIXME: Note, this is a hack. We need to pass the selected float - // mode to the MipsTargetInfoBase to define appropriate macros there. - // Now it is the only method. - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("+soft-float"); - if (FloatABI == "hard" && IsMips16) { CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-mips16-hard-float"); @@ -995,22 +1082,6 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, CmdArgs.push_back("hard"); } - AddTargetFeature(Args, CmdArgs, - options::OPT_msingle_float, options::OPT_mdouble_float, - "single-float"); - AddTargetFeature(Args, CmdArgs, - options::OPT_mips16, options::OPT_mno_mips16, - "mips16"); - AddTargetFeature(Args, CmdArgs, - options::OPT_mmicromips, options::OPT_mno_micromips, - "micromips"); - AddTargetFeature(Args, CmdArgs, - options::OPT_mdsp, options::OPT_mno_dsp, - "dsp"); - AddTargetFeature(Args, CmdArgs, - options::OPT_mdspr2, options::OPT_mno_dspr2, - "dspr2"); - if (Arg *A = Args.getLastArg(options::OPT_mxgot, options::OPT_mno_xgot)) { if (A->getOption().matches(options::OPT_mxgot)) { CmdArgs.push_back("-mllvm"); @@ -1018,6 +1089,22 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, } } + if (Arg *A = Args.getLastArg(options::OPT_mldc1_sdc1, + options::OPT_mno_ldc1_sdc1)) { + if (A->getOption().matches(options::OPT_mno_ldc1_sdc1)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-mno-ldc1-sdc1"); + } + } + + if (Arg *A = Args.getLastArg(options::OPT_mcheck_zero_division, + options::OPT_mno_check_zero_division)) { + if (A->getOption().matches(options::OPT_mno_check_zero_division)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-mno-check-zero-division"); + } + } + if (Arg *A = Args.getLastArg(options::OPT_G)) { StringRef v = A->getValue(); CmdArgs.push_back("-mllvm"); @@ -1081,62 +1168,48 @@ static std::string getPPCTargetCPU(const ArgList &Args) { .Case("pwr7", "pwr7") .Case("powerpc", "ppc") .Case("powerpc64", "ppc64") + .Case("powerpc64le", "ppc64le") .Default(""); } return ""; } -void Clang::AddPPCTargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - std::string TargetCPUName = getPPCTargetCPU(Args); - - // LLVM may default to generating code for the native CPU, - // but, like gcc, we default to a more generic option for - // each architecture. (except on Darwin) - llvm::Triple Triple = getToolChain().getTriple(); - if (TargetCPUName.empty() && !Triple.isOSDarwin()) { - if (Triple.getArch() == llvm::Triple::ppc64) - TargetCPUName = "ppc64"; - else - TargetCPUName = "ppc"; - } - - if (!TargetCPUName.empty()) { - CmdArgs.push_back("-target-cpu"); - CmdArgs.push_back(Args.MakeArgString(TargetCPUName.c_str())); - } - - // Allow override of the Altivec feature. - AddTargetFeature(Args, CmdArgs, - options::OPT_faltivec, options::OPT_fno_altivec, - "altivec"); +static void getPPCTargetFeatures(const ArgList &Args, + std::vector<const char *> &Features) { + for (arg_iterator it = Args.filtered_begin(options::OPT_m_ppc_Features_Group), + ie = Args.filtered_end(); + it != ie; ++it) { + StringRef Name = (*it)->getOption().getName(); + (*it)->claim(); - AddTargetFeature(Args, CmdArgs, - options::OPT_mfprnd, options::OPT_mno_fprnd, - "fprnd"); + // Skip over "-m". + assert(Name.startswith("m") && "Invalid feature name."); + Name = Name.substr(1); - // Note that gcc calls this mfcrf and LLVM calls this mfocrf. - AddTargetFeature(Args, CmdArgs, - options::OPT_mmfcrf, options::OPT_mno_mfcrf, - "mfocrf"); + bool IsNegative = Name.startswith("no-"); + if (IsNegative) + Name = Name.substr(3); - AddTargetFeature(Args, CmdArgs, - options::OPT_mpopcntd, options::OPT_mno_popcntd, - "popcntd"); + // Note that gcc calls this mfcrf and LLVM calls this mfocrf so we + // pass the correct option to the backend while calling the frontend + // option the same. + // TODO: Change the LLVM backend option maybe? + if (Name == "mfcrf") + Name = "mfocrf"; - // It is really only possible to turn qpx off because turning qpx on is tied - // to using the a2q CPU. - if (Args.hasFlag(options::OPT_mno_qpx, options::OPT_mqpx, false)) { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("-qpx"); + Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); } + + // Altivec is a bit weird, allow overriding of the Altivec feature here. + AddTargetFeature(Args, Features, options::OPT_faltivec, + options::OPT_fno_altivec, "altivec"); } /// Get the (LLVM) name of the R600 gpu we are targeting. static std::string getR600TargetGPU(const ArgList &Args) { if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { - std::string GPUName = A->getValue(); + const char *GPUName = A->getValue(); return llvm::StringSwitch<const char *>(GPUName) .Cases("rv630", "rv635", "r600") .Cases("rv610", "rv620", "rs780", "rs880") @@ -1145,27 +1218,27 @@ static std::string getR600TargetGPU(const ArgList &Args) { .Cases("sumo", "sumo2", "sumo") .Case("hemlock", "cypress") .Case("aruba", "cayman") - .Default(GPUName.c_str()); + .Default(GPUName); } return ""; } -void Clang::AddR600TargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - std::string TargetGPUName = getR600TargetGPU(Args); - CmdArgs.push_back("-target-cpu"); - CmdArgs.push_back(Args.MakeArgString(TargetGPUName.c_str())); +static void getSparcTargetFeatures(const ArgList &Args, + std::vector<const char *> Features) { + bool SoftFloatABI = true; + if (Arg *A = + Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) { + if (A->getOption().matches(options::OPT_mhard_float)) + SoftFloatABI = false; + } + if (SoftFloatABI) + Features.push_back("+soft-float"); } void Clang::AddSparcTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); - if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { - CmdArgs.push_back("-target-cpu"); - CmdArgs.push_back(A->getValue()); - } - // Select the float ABI as determined by -msoft-float, -mhard-float, and StringRef FloatABI; if (Arg *A = Args.getLastArg(options::OPT_msoft_float, @@ -1178,13 +1251,9 @@ void Clang::AddSparcTargetArgs(const ArgList &Args, // If unspecified, choose the default based on the platform. if (FloatABI.empty()) { - switch (getToolChain().getTriple().getOS()) { - default: - // Assume "soft", but warn the user we are guessing. - FloatABI = "soft"; - D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft"; - break; - } + // Assume "soft", but warn the user we are guessing. + FloatABI = "soft"; + D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft"; } if (FloatABI == "soft") { @@ -1192,19 +1261,27 @@ void Clang::AddSparcTargetArgs(const ArgList &Args, // // FIXME: This changes CPP defines, we need -target-soft-float. CmdArgs.push_back("-msoft-float"); - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("+soft-float"); } else { assert(FloatABI == "hard" && "Invalid float abi!"); CmdArgs.push_back("-mhard-float"); } } +static const char *getSystemZTargetCPU(const ArgList &Args) { + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) + return A->getValue(); + return "z10"; +} + static const char *getX86TargetCPU(const ArgList &Args, const llvm::Triple &Triple) { if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { - if (StringRef(A->getValue()) != "native") + if (StringRef(A->getValue()) != "native") { + if (Triple.isOSDarwin() && Triple.getArchName() == "x86_64h") + return "core-avx2"; + return A->getValue(); + } // FIXME: Reject attempts to use -march=native unless the target matches // the host. @@ -1225,30 +1302,128 @@ static const char *getX86TargetCPU(const ArgList &Args, bool Is64Bit = Triple.getArch() == llvm::Triple::x86_64; // FIXME: Need target hooks. - if (Triple.isOSDarwin()) + if (Triple.isOSDarwin()) { + if (Triple.getArchName() == "x86_64h") + return "core-avx2"; return Is64Bit ? "core2" : "yonah"; + } + + // All x86 devices running Android have core2 as their common + // denominator. This makes a better choice than pentium4. + if (Triple.getEnvironment() == llvm::Triple::Android) + return "core2"; // Everything else goes to x86-64 in 64-bit mode. if (Is64Bit) return "x86-64"; - if (Triple.getOSName().startswith("haiku")) - return "i586"; - if (Triple.getOSName().startswith("openbsd")) + switch (Triple.getOS()) { + case llvm::Triple::FreeBSD: + case llvm::Triple::NetBSD: + case llvm::Triple::OpenBSD: return "i486"; - if (Triple.getOSName().startswith("bitrig")) + case llvm::Triple::Haiku: + return "i586"; + case llvm::Triple::Bitrig: return "i686"; - if (Triple.getOSName().startswith("freebsd")) - return "i486"; - if (Triple.getOSName().startswith("netbsd")) - return "i486"; - // All x86 devices running Android have core2 as their common - // denominator. This makes a better choice than pentium4. - if (Triple.getEnvironment() == llvm::Triple::Android) - return "core2"; + default: + // Fallback to p4. + return "pentium4"; + } +} + +static std::string getCPUName(const ArgList &Args, const llvm::Triple &T) { + switch(T.getArch()) { + default: + return ""; - // Fallback to p4. - return "pentium4"; + case llvm::Triple::aarch64: + return getAArch64TargetCPU(Args, T); + + case llvm::Triple::arm: + case llvm::Triple::thumb: + return getARMTargetCPU(Args, T); + + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: { + StringRef CPUName; + StringRef ABIName; + getMipsCPUAndABI(Args, T, CPUName, ABIName); + return CPUName; + } + + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: { + std::string TargetCPUName = getPPCTargetCPU(Args); + // LLVM may default to generating code for the native CPU, + // but, like gcc, we default to a more generic option for + // each architecture. (except on Darwin) + if (TargetCPUName.empty() && !T.isOSDarwin()) { + if (T.getArch() == llvm::Triple::ppc64) + TargetCPUName = "ppc64"; + else if (T.getArch() == llvm::Triple::ppc64le) + TargetCPUName = "ppc64le"; + else + TargetCPUName = "ppc"; + } + return TargetCPUName; + } + + case llvm::Triple::sparc: + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) + return A->getValue(); + return ""; + + case llvm::Triple::x86: + case llvm::Triple::x86_64: + return getX86TargetCPU(Args, T); + + case llvm::Triple::hexagon: + return "hexagon" + toolchains::Hexagon_TC::GetTargetCPU(Args).str(); + + case llvm::Triple::systemz: + return getSystemZTargetCPU(Args); + + case llvm::Triple::r600: + return getR600TargetGPU(Args); + } +} + +static void getX86TargetFeatures(const llvm::Triple &Triple, + const ArgList &Args, + std::vector<const char *> &Features) { + if (Triple.getArchName() == "x86_64h") { + // x86_64h implies quite a few of the more modern subtarget features + // for Haswell class CPUs, but not all of them. Opt-out of a few. + Features.push_back("-rdrnd"); + Features.push_back("-aes"); + Features.push_back("-pclmul"); + Features.push_back("-rtm"); + Features.push_back("-hle"); + Features.push_back("-fsgsbase"); + } + + // Now add any that the user explicitly requested on the command line, + // which may override the defaults. + for (arg_iterator it = Args.filtered_begin(options::OPT_m_x86_Features_Group), + ie = Args.filtered_end(); + it != ie; ++it) { + StringRef Name = (*it)->getOption().getName(); + (*it)->claim(); + + // Skip over "-m". + assert(Name.startswith("m") && "Invalid feature name."); + Name = Name.substr(1); + + bool IsNegative = Name.startswith("no-"); + if (IsNegative) + Name = Name.substr(3); + + Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); + } } void Clang::AddX86TargetArgs(const ArgList &Args, @@ -1274,45 +1449,6 @@ void Clang::AddX86TargetArgs(const ArgList &Args, } if (NoImplicitFloat) CmdArgs.push_back("-no-implicit-float"); - - if (const char *CPUName = getX86TargetCPU(Args, getToolChain().getTriple())) { - CmdArgs.push_back("-target-cpu"); - CmdArgs.push_back(CPUName); - } - - // The required algorithm here is slightly strange: the options are applied - // in order (so -mno-sse -msse2 disables SSE3), but any option that gets - // directly overridden later is ignored (so "-mno-sse -msse2 -mno-sse2 -msse" - // is equivalent to "-mno-sse2 -msse"). The -cc1 handling deals with the - // former correctly, but not the latter; handle directly-overridden - // attributes here. - llvm::StringMap<unsigned> PrevFeature; - std::vector<const char*> Features; - for (arg_iterator it = Args.filtered_begin(options::OPT_m_x86_Features_Group), - ie = Args.filtered_end(); it != ie; ++it) { - StringRef Name = (*it)->getOption().getName(); - (*it)->claim(); - - // Skip over "-m". - assert(Name.startswith("m") && "Invalid feature name."); - Name = Name.substr(1); - - bool IsNegative = Name.startswith("no-"); - if (IsNegative) - Name = Name.substr(3); - - unsigned& Prev = PrevFeature[Name]; - if (Prev) - Features[Prev - 1] = 0; - Prev = Features.size() + 1; - Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); - } - for (unsigned i = 0; i < Features.size(); i++) { - if (Features[i]) { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back(Features[i]); - } - } } static inline bool HasPICArg(const ArgList &Args) { @@ -1339,12 +1475,6 @@ static std::string GetHexagonSmallDataThresholdValue(const ArgList &Args) { void Clang::AddHexagonTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - llvm::Triple Triple = getToolChain().getTriple(); - - CmdArgs.push_back("-target-cpu"); - CmdArgs.push_back(Args.MakeArgString( - "hexagon" - + toolchains::Hexagon_TC::GetTargetCPU(Args))); CmdArgs.push_back("-fno-signed-char"); CmdArgs.push_back("-mqdsp6-compat"); CmdArgs.push_back("-Wreturn-type"); @@ -1366,6 +1496,70 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args, CmdArgs.push_back ("-machine-sink-split=0"); } +static void getAArch64TargetFeatures(const Driver &D, const ArgList &Args, + std::vector<const char *> &Features) { + // Honor -mfpu=. + if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) + getAArch64FPUFeatures(D, A, Args, Features); +} + +static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args, ArgStringList &CmdArgs) { + std::vector<const char *> Features; + switch (Triple.getArch()) { + default: + break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + getMIPSTargetFeatures(D, Args, Features); + break; + + case llvm::Triple::arm: + case llvm::Triple::thumb: + getARMTargetFeatures(D, Triple, Args, Features); + break; + + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + getPPCTargetFeatures(Args, Features); + break; + case llvm::Triple::sparc: + getSparcTargetFeatures(Args, Features); + break; + case llvm::Triple::aarch64: + getAArch64TargetFeatures(D, Args, Features); + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + getX86TargetFeatures(Triple, Args, Features); + break; + } + + // Find the last of each feature. + llvm::StringMap<unsigned> LastOpt; + for (unsigned I = 0, N = Features.size(); I < N; ++I) { + const char *Name = Features[I]; + assert(Name[0] == '-' || Name[0] == '+'); + LastOpt[Name + 1] = I; + } + + for (unsigned I = 0, N = Features.size(); I < N; ++I) { + // If this feature was overridden, ignore it. + const char *Name = Features[I]; + llvm::StringMap<unsigned>::iterator LastI = LastOpt.find(Name + 1); + assert(LastI != LastOpt.end()); + unsigned Last = LastI->second; + if (Last != I) + continue; + + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back(Name); + } +} + static bool shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime, const llvm::Triple &Triple) { @@ -1532,117 +1726,75 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) { RelaxDefault); } -SanitizerArgs::SanitizerArgs(const ToolChain &TC, const ArgList &Args) - : Kind(0), BlacklistFile(""), MsanTrackOrigins(false), - AsanZeroBaseShadow(false) { - unsigned AllKinds = 0; // All kinds of sanitizers that were turned on - // at least once (possibly, disabled further). - const Driver &D = TC.getDriver(); - for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) { - unsigned Add, Remove; - if (!parse(D, Args, *I, Add, Remove, true)) - continue; - (*I)->claim(); - Kind |= Add; - Kind &= ~Remove; - AllKinds |= Add; - } +static void CollectArgsForIntegratedAssembler(Compilation &C, + const ArgList &Args, + ArgStringList &CmdArgs, + const Driver &D) { + if (UseRelaxAll(C, Args)) + CmdArgs.push_back("-mrelax-all"); - UbsanTrapOnError = - Args.hasArg(options::OPT_fcatch_undefined_behavior) || - Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, - options::OPT_fno_sanitize_undefined_trap_on_error, false); + // When passing -I arguments to the assembler we sometimes need to + // unconditionally take the next argument. For example, when parsing + // '-Wa,-I -Wa,foo' we need to accept the -Wa,foo arg after seeing the + // -Wa,-I arg and when parsing '-Wa,-I,foo' we need to accept the 'foo' + // arg after parsing the '-I' arg. + bool TakeNextArg = false; - if (Args.hasArg(options::OPT_fcatch_undefined_behavior) && - !Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, - options::OPT_fno_sanitize_undefined_trap_on_error, true)) { - D.Diag(diag::err_drv_argument_not_allowed_with) - << "-fcatch-undefined-behavior" - << "-fno-sanitize-undefined-trap-on-error"; - } + // When using an integrated assembler, translate -Wa, and -Xassembler + // options. + for (arg_iterator it = Args.filtered_begin(options::OPT_Wa_COMMA, + options::OPT_Xassembler), + ie = Args.filtered_end(); it != ie; ++it) { + const Arg *A = *it; + A->claim(); - // Warn about undefined sanitizer options that require runtime support. - if (UbsanTrapOnError && notAllowedWithTrap()) { - if (Args.hasArg(options::OPT_fcatch_undefined_behavior)) - D.Diag(diag::err_drv_argument_not_allowed_with) - << lastArgumentForKind(D, Args, NotAllowedWithTrap) - << "-fcatch-undefined-behavior"; - else if (Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, - options::OPT_fno_sanitize_undefined_trap_on_error, - false)) - D.Diag(diag::err_drv_argument_not_allowed_with) - << lastArgumentForKind(D, Args, NotAllowedWithTrap) - << "-fsanitize-undefined-trap-on-error"; - } - - // Only one runtime library can be used at once. - bool NeedsAsan = needsAsanRt(); - bool NeedsTsan = needsTsanRt(); - bool NeedsMsan = needsMsanRt(); - if (NeedsAsan && NeedsTsan) - D.Diag(diag::err_drv_argument_not_allowed_with) - << lastArgumentForKind(D, Args, NeedsAsanRt) - << lastArgumentForKind(D, Args, NeedsTsanRt); - if (NeedsAsan && NeedsMsan) - D.Diag(diag::err_drv_argument_not_allowed_with) - << lastArgumentForKind(D, Args, NeedsAsanRt) - << lastArgumentForKind(D, Args, NeedsMsanRt); - if (NeedsTsan && NeedsMsan) - D.Diag(diag::err_drv_argument_not_allowed_with) - << lastArgumentForKind(D, Args, NeedsTsanRt) - << lastArgumentForKind(D, Args, NeedsMsanRt); - - // If -fsanitize contains extra features of ASan, it should also - // explicitly contain -fsanitize=address (probably, turned off later in the - // command line). - if ((Kind & AddressFull) != 0 && (AllKinds & Address) == 0) - D.Diag(diag::warn_drv_unused_sanitizer) - << lastArgumentForKind(D, Args, AddressFull) - << "-fsanitize=address"; - - // Parse -f(no-)sanitize-blacklist options. - if (Arg *BLArg = Args.getLastArg(options::OPT_fsanitize_blacklist, - options::OPT_fno_sanitize_blacklist)) { - if (BLArg->getOption().matches(options::OPT_fsanitize_blacklist)) { - std::string BLPath = BLArg->getValue(); - bool BLExists = false; - if (!llvm::sys::fs::exists(BLPath, BLExists) && BLExists) - BlacklistFile = BLPath; - else - D.Diag(diag::err_drv_no_such_file) << BLPath; - } - } else { - // If no -fsanitize-blacklist option is specified, try to look up for - // blacklist in the resource directory. - std::string BLPath; - bool BLExists = false; - if (getDefaultBlacklistForKind(D, Kind, BLPath) && - !llvm::sys::fs::exists(BLPath, BLExists) && BLExists) - BlacklistFile = BLPath; - } - - // Parse -f(no-)sanitize-memory-track-origins options. - if (NeedsMsan) - MsanTrackOrigins = - Args.hasFlag(options::OPT_fsanitize_memory_track_origins, - options::OPT_fno_sanitize_memory_track_origins, - /* Default */false); - - // Parse -f(no-)sanitize-address-zero-base-shadow options. - if (NeedsAsan) { - bool IsAndroid = (TC.getTriple().getEnvironment() == llvm::Triple::Android); - bool ZeroBaseShadowDefault = IsAndroid; - AsanZeroBaseShadow = - Args.hasFlag(options::OPT_fsanitize_address_zero_base_shadow, - options::OPT_fno_sanitize_address_zero_base_shadow, - ZeroBaseShadowDefault); - // Zero-base shadow is a requirement on Android. - if (IsAndroid && !AsanZeroBaseShadow) { - D.Diag(diag::err_drv_argument_not_allowed_with) - << "-fno-sanitize-address-zero-base-shadow" - << lastArgumentForKind(D, Args, Address); + for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) { + StringRef Value = A->getValue(i); + if (TakeNextArg) { + CmdArgs.push_back(Value.data()); + TakeNextArg = false; + continue; + } + + if (Value == "-force_cpusubtype_ALL") { + // Do nothing, this is the default and we don't support anything else. + } else if (Value == "-L") { + CmdArgs.push_back("-msave-temp-labels"); + } else if (Value == "--fatal-warnings") { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-fatal-assembler-warnings"); + } else if (Value == "--noexecstack") { + CmdArgs.push_back("-mnoexecstack"); + } else if (Value.startswith("-I")) { + CmdArgs.push_back(Value.data()); + // We need to consume the next argument if the current arg is a plain + // -I. The next arg will be the include directory. + if (Value == "-I") + TakeNextArg = true; + } else { + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; + } + } } - } +} + +static void addProfileRTLinux( + const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { + if (!(Args.hasArg(options::OPT_fprofile_arcs) || + Args.hasArg(options::OPT_fprofile_generate) || + Args.hasArg(options::OPT_fcreate_profile) || + Args.hasArg(options::OPT_coverage))) + return; + + // The profile runtime is located in the Linux library directory and has name + // "libclang_rt.profile-<ArchName>.a". + SmallString<128> LibProfile(TC.getDriver().ResourceDir); + llvm::sys::path::append( + LibProfile, "lib", "linux", + Twine("libclang_rt.profile-") + TC.getArchName() + ".a"); + + CmdArgs.push_back(Args.MakeArgString(LibProfile)); } static void addSanitizerRTLinkFlagsLinux( @@ -1673,6 +1825,7 @@ static void addSanitizerRTLinkFlagsLinux( CmdArgs.push_back("-lpthread"); CmdArgs.push_back("-lrt"); CmdArgs.push_back("-ldl"); + CmdArgs.push_back("-lm"); // If possible, use a dynamic symbols file to export the symbols from the // runtime library. If we can't do so, use -export-dynamic instead to export @@ -1690,16 +1843,15 @@ static void addSanitizerRTLinkFlagsLinux( /// This needs to be called before we add the C run-time (malloc, etc). static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { - if(TC.getTriple().getEnvironment() == llvm::Triple::Android) { + if (TC.getTriple().getEnvironment() == llvm::Triple::Android) { SmallString<128> LibAsan(TC.getDriver().ResourceDir); llvm::sys::path::append(LibAsan, "lib", "linux", (Twine("libclang_rt.asan-") + TC.getArchName() + "-android.so")); CmdArgs.insert(CmdArgs.begin(), Args.MakeArgString(LibAsan)); } else { - if (!Args.hasArg(options::OPT_shared)) { + if (!Args.hasArg(options::OPT_shared)) addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "asan", true); - } } } @@ -1707,18 +1859,24 @@ static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args, /// This needs to be called before we add the C run-time (malloc, etc). static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { - if (!Args.hasArg(options::OPT_shared)) { + if (!Args.hasArg(options::OPT_shared)) addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "tsan", true); - } } /// If MemorySanitizer is enabled, add appropriate linker flags (Linux). /// This needs to be called before we add the C run-time (malloc, etc). static void addMsanRTLinux(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { - if (!Args.hasArg(options::OPT_shared)) { + if (!Args.hasArg(options::OPT_shared)) addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "msan", true); - } +} + +/// If LeakSanitizer is enabled, add appropriate linker flags (Linux). +/// This needs to be called before we add the C run-time (malloc, etc). +static void addLsanRTLinux(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + if (!Args.hasArg(options::OPT_shared)) + addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "lsan", true); } /// If UndefinedBehaviorSanitizer is enabled, add appropriate linker flags @@ -1726,9 +1884,6 @@ static void addMsanRTLinux(const ToolChain &TC, const ArgList &Args, static void addUbsanRTLinux(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, bool IsCXX, bool HasOtherSanitizerRt) { - if (Args.hasArg(options::OPT_shared)) - return; - // Need a copy of sanitizer_common. This could come from another sanitizer // runtime; if we're not including one, include our own copy. if (!HasOtherSanitizerRt) @@ -1742,22 +1897,42 @@ static void addUbsanRTLinux(const ToolChain &TC, const ArgList &Args, addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "ubsan_cxx", false); } +static void addDfsanRTLinux(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + if (!Args.hasArg(options::OPT_shared)) + addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "dfsan", true); +} + +static bool shouldUseFramePointerForTarget(const ArgList &Args, + const llvm::Triple &Triple) { + switch (Triple.getArch()) { + // Don't use a frame pointer on linux if optimizing for certain targets. + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::systemz: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + if (Triple.isOSLinux()) + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) + if (!A->getOption().matches(options::OPT_O0)) + return false; + return true; + case llvm::Triple::xcore: + return false; + default: + return true; + } +} + static bool shouldUseFramePointer(const ArgList &Args, const llvm::Triple &Triple) { if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer, options::OPT_fomit_frame_pointer)) return A->getOption().matches(options::OPT_fno_omit_frame_pointer); - // Don't use a frame pointer on linux x86 and x86_64 if optimizing. - if ((Triple.getArch() == llvm::Triple::x86_64 || - Triple.getArch() == llvm::Triple::x86) && - Triple.getOS() == llvm::Triple::Linux) { - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) - if (!A->getOption().matches(options::OPT_O0)) - return false; - } - - return true; + return shouldUseFramePointerForTarget(Args, Triple); } static bool shouldUseLeafFramePointer(const ArgList &Args, @@ -1766,38 +1941,11 @@ static bool shouldUseLeafFramePointer(const ArgList &Args, options::OPT_momit_leaf_frame_pointer)) return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer); - // Don't use a leaf frame pointer on linux x86 and x86_64 if optimizing. - if ((Triple.getArch() == llvm::Triple::x86_64 || - Triple.getArch() == llvm::Triple::x86) && - Triple.getOS() == llvm::Triple::Linux) { - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) - if (!A->getOption().matches(options::OPT_O0)) - return false; - } - - return true; + return shouldUseFramePointerForTarget(Args, Triple); } -/// If the PWD environment variable is set, add a CC1 option to specify the -/// debug compilation directory. +/// Add a CC1 option to specify the debug compilation directory. static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs) { - struct stat StatPWDBuf, StatDotBuf; - - const char *pwd = ::getenv("PWD"); - if (!pwd) - return; - - if (llvm::sys::path::is_absolute(pwd) && - stat(pwd, &StatPWDBuf) == 0 && - stat(".", &StatDotBuf) == 0 && - StatPWDBuf.st_ino == StatDotBuf.st_ino && - StatPWDBuf.st_dev == StatDotBuf.st_dev) { - CmdArgs.push_back("-fdebug-compilation-dir"); - CmdArgs.push_back(Args.MakeArgString(pwd)); - return; - } - - // Fall back to using getcwd. SmallString<128> cwd; if (!llvm::sys::fs::current_path(cwd)) { CmdArgs.push_back("-fdebug-compilation-dir"); @@ -1854,6 +2002,37 @@ static bool isOptimizationLevelFast(const ArgList &Args) { return false; } +/// \brief Vectorize at all optimization levels greater than 1 except for -Oz. +static bool shouldEnableVectorizerAtOLevel(const ArgList &Args) { + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + if (A->getOption().matches(options::OPT_O4) || + A->getOption().matches(options::OPT_Ofast)) + return true; + + if (A->getOption().matches(options::OPT_O0)) + return false; + + assert(A->getOption().matches(options::OPT_O) && "Must have a -O flag"); + + // Vectorize -Os. + StringRef S(A->getValue()); + if (S == "s") + return true; + + // Don't vectorize -Oz. + if (S == "z") + return false; + + unsigned OptLevel = 0; + if (S.getAsInteger(10, OptLevel)) + return false; + + return OptLevel > 1; + } + + return false; +} + void Clang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -1896,35 +2075,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } else if (isa<AssembleJobAction>(JA)) { CmdArgs.push_back("-emit-obj"); - if (UseRelaxAll(C, Args)) - CmdArgs.push_back("-mrelax-all"); - - // When using an integrated assembler, translate -Wa, and -Xassembler - // options. - for (arg_iterator it = Args.filtered_begin(options::OPT_Wa_COMMA, - options::OPT_Xassembler), - ie = Args.filtered_end(); it != ie; ++it) { - const Arg *A = *it; - A->claim(); - - for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) { - StringRef Value = A->getValue(i); - - if (Value == "-force_cpusubtype_ALL") { - // Do nothing, this is the default and we don't support anything else. - } else if (Value == "-L") { - CmdArgs.push_back("-msave-temp-labels"); - } else if (Value == "--fatal-warnings") { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-fatal-assembler-warnings"); - } else if (Value == "--noexecstack") { - CmdArgs.push_back("-mnoexecstack"); - } else { - D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; - } - } - } + CollectArgsForIntegratedAssembler(C, Args, CmdArgs, D); // Also ignore explicit -force_cpusubtype_ALL option. (void) Args.hasArg(options::OPT_force__cpusubtype__ALL); @@ -2071,7 +2222,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } - // Inroduce a Darwin-specific hack. If the default is PIC but the flags + // Introduce a Darwin-specific hack. If the default is PIC but the flags // specified while enabling PIC enabled level 1 PIC, just force it back to // level 2 PIC instead. This matches the behavior of Darwin GCC (based on my // informal testing). @@ -2082,8 +2233,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // PIC or PIE options above, if these show up, PIC is disabled. llvm::Triple Triple(TripleStr); if (KernelOrKext && - (Triple.getOS() != llvm::Triple::IOS || - Triple.isOSVersionLT(6))) + (!Triple.isiOS() || Triple.isOSVersionLT(6))) PIC = PIE = false; if (Args.hasArg(options::OPT_static)) PIC = PIE = false; @@ -2134,6 +2284,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } + if (Arg *A = Args.getLastArg(options::OPT_fpcc_struct_return, + options::OPT_freg_struct_return)) { + if (getToolChain().getArch() != llvm::Triple::x86) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << getToolChain().getTriple().str(); + } else if (A->getOption().matches(options::OPT_fpcc_struct_return)) { + CmdArgs.push_back("-fpcc-struct-return"); + } else { + assert(A->getOption().matches(options::OPT_freg_struct_return)); + CmdArgs.push_back("-freg-struct-return"); + } + } + if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) CmdArgs.push_back("-mrtd"); @@ -2149,11 +2312,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, OptSpecifier StrictAliasingAliasOption = OFastEnabled ? options::OPT_Ofast : options::OPT_fstrict_aliasing; if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption, - options::OPT_fno_strict_aliasing, - getToolChain().IsStrictAliasingDefault())) + options::OPT_fno_strict_aliasing, true)) CmdArgs.push_back("-relaxed-aliasing"); - if (Args.hasArg(options::OPT_fstruct_path_tbaa)) - CmdArgs.push_back("-struct-path-tbaa"); + if (!Args.hasFlag(options::OPT_fstruct_path_tbaa, + options::OPT_fno_struct_path_tbaa)) + CmdArgs.push_back("-no-struct-path-tbaa"); if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums, false)) CmdArgs.push_back("-fstrict-enums"); @@ -2201,8 +2364,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_fmath_errno, - options::OPT_fno_math_errno)) - MathErrno = A->getOption().getID() == options::OPT_fmath_errno; + options::OPT_fno_math_errno)) { + // Turning on -ffast_math (with either flag) removes the need for MathErrno. + // However, turning *off* -ffast_math merely restores the toolchain default + // (which may be false). + if (A->getOption().getID() == options::OPT_fno_math_errno || + A->getOption().getID() == options::OPT_ffast_math || + A->getOption().getID() == options::OPT_Ofast) + MathErrno = false; + else if (A->getOption().getID() == options::OPT_fmath_errno) + MathErrno = true; + } if (MathErrno) CmdArgs.push_back("-fmath-errno"); @@ -2349,8 +2521,25 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } - // Add target specific cpu and features flags. - switch(getToolChain().getTriple().getArch()) { + // Add the target cpu + std::string ETripleStr = getToolChain().ComputeEffectiveClangTriple(Args); + llvm::Triple ETriple(ETripleStr); + std::string CPU = getCPUName(Args, ETriple); + if (!CPU.empty()) { + CmdArgs.push_back("-target-cpu"); + CmdArgs.push_back(Args.MakeArgString(CPU)); + } + + if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) { + CmdArgs.push_back("-mfpmath"); + CmdArgs.push_back(A->getValue()); + } + + // Add the target features + getTargetFeatures(D, ETriple, Args, CmdArgs); + + // Add target specific flags. + switch(getToolChain().getArch()) { default: break; @@ -2366,15 +2555,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, AddMIPSTargetArgs(Args, CmdArgs); break; - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - AddPPCTargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::r600: - AddR600TargetArgs(Args, CmdArgs); - break; - case llvm::Triple::sparc: AddSparcTargetArgs(Args, CmdArgs); break; @@ -2389,7 +2569,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, break; } - + // Add clang-cl arguments. + if (getToolChain().getDriver().IsCLMode()) + AddClangCLArgs(Args, CmdArgs); // Pass the linker version in use. if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { @@ -2407,7 +2589,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Arg *Unsupported; if (types::isCXX(InputType) && getToolChain().getTriple().isOSDarwin() && - getToolChain().getTriple().getArch() == llvm::Triple::x86) { + getToolChain().getArch() == llvm::Triple::x86) { if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext)) || (Unsupported = Args.getLastArg(options::OPT_mkernel))) D.Diag(diag::err_drv_clang_unsupported_opt_cxx_darwin_i386) @@ -2437,9 +2619,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_g_Group)) { if (A->getOption().matches(options::OPT_gline_tables_only)) CmdArgs.push_back("-gline-tables-only"); + else if (A->getOption().matches(options::OPT_gdwarf_2)) + CmdArgs.push_back("-gdwarf-2"); + else if (A->getOption().matches(options::OPT_gdwarf_3)) + CmdArgs.push_back("-gdwarf-3"); + else if (A->getOption().matches(options::OPT_gdwarf_4)) + CmdArgs.push_back("-gdwarf-4"); else if (!A->getOption().matches(options::OPT_g0) && - !A->getOption().matches(options::OPT_ggdb0)) - CmdArgs.push_back("-g"); + !A->getOption().matches(options::OPT_ggdb0)) { + // Default is dwarf-2 for darwin. + if (getToolChain().getTriple().isOSDarwin()) + CmdArgs.push_back("-gdwarf-2"); + else + CmdArgs.push_back("-g"); + } } // We ignore flags -gstrict-dwarf and -grecord-gcc-switches for now. @@ -2447,16 +2640,25 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_gcolumn_info)) CmdArgs.push_back("-dwarf-column-info"); + // FIXME: Move backend command line options to the module. // -gsplit-dwarf should turn on -g and enable the backend dwarf // splitting and extraction. // FIXME: Currently only works on Linux. - if (getToolChain().getTriple().getOS() == llvm::Triple::Linux && + if (getToolChain().getTriple().isOSLinux() && Args.hasArg(options::OPT_gsplit_dwarf)) { CmdArgs.push_back("-g"); CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-split-dwarf=Enable"); } + // -ggnu-pubnames turns on gnu style pubnames in the backend. + if (Args.hasArg(options::OPT_ggnu_pubnames)) { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-generate-gnu-dwarf-pub-sections"); + } + + Args.AddAllArgs(CmdArgs, options::OPT_fdebug_types_section); + Args.AddAllArgs(CmdArgs, options::OPT_ffunction_sections); Args.AddAllArgs(CmdArgs, options::OPT_fdata_sections); @@ -2475,12 +2677,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-coverage-file"); SmallString<128> CoverageFilename(Output.getFilename()); if (llvm::sys::path::is_relative(CoverageFilename.str())) { - if (const char *pwd = ::getenv("PWD")) { - if (llvm::sys::path::is_absolute(pwd)) { - SmallString<128> Pwd(pwd); - llvm::sys::path::append(Pwd, CoverageFilename.str()); - CoverageFilename.swap(Pwd); - } + SmallString<128> Pwd; + if (!llvm::sys::fs::current_path(Pwd)) { + llvm::sys::path::append(Pwd, CoverageFilename.str()); + CoverageFilename.swap(Pwd); } } CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); @@ -2505,7 +2705,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_working_directory); bool ARCMTEnabled = false; - if (!Args.hasArg(options::OPT_fno_objc_arc)) { + if (!Args.hasArg(options::OPT_fno_objc_arc, options::OPT_fobjc_arc)) { if (const Arg *A = Args.getLastArg(options::OPT_ccc_arcmt_check, options::OPT_ccc_arcmt_modify, options::OPT_ccc_arcmt_migrate)) { @@ -2529,6 +2729,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, break; } } + } else { + Args.ClaimAllArgs(options::OPT_ccc_arcmt_check); + Args.ClaimAllArgs(options::OPT_ccc_arcmt_modify); + Args.ClaimAllArgs(options::OPT_ccc_arcmt_migrate); } if (const Arg *A = Args.getLastArg(options::OPT_ccc_objcmt_migrate)) { @@ -2540,14 +2744,32 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); if (!Args.hasArg(options::OPT_objcmt_migrate_literals, - options::OPT_objcmt_migrate_subscripting)) { + options::OPT_objcmt_migrate_subscripting, + options::OPT_objcmt_migrate_property)) { // None specified, means enable them all. CmdArgs.push_back("-objcmt-migrate-literals"); CmdArgs.push_back("-objcmt-migrate-subscripting"); + CmdArgs.push_back("-objcmt-migrate-property"); } else { Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals); Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property); } + } else { + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_all); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readonly_property); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readwrite_property); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_annotation); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_instancetype); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_nsmacros); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_protocol_conformance); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_atomic_property); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_returns_innerpointer_property); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_ns_nonatomic_iosonly); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_white_list_dir_path); } // Add preprocessing options like -I, -D, etc. if we are using the @@ -2563,16 +2785,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // preprocessed inputs and configure concludes that -fPIC is not supported. Args.ClaimAllArgs(options::OPT_D); - // Manually translate -O to -O2 and -O4 to -O3; let clang reject - // others. + // Manually translate -O4 to -O3; let clang reject others. if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { - if (A->getOption().matches(options::OPT_O4)) + if (A->getOption().matches(options::OPT_O4)) { CmdArgs.push_back("-O3"); - else if (A->getOption().matches(options::OPT_O) && - A->getValue()[0] == '\0') - CmdArgs.push_back("-O2"); - else + D.Diag(diag::warn_O4_is_O3); + } else { A->render(Args, CmdArgs); + } } // Don't warn about unused -flto. This can happen when we're preprocessing or @@ -2586,7 +2806,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_w); // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi} - // (-ansi is equivalent to -std=c89). + // (-ansi is equivalent to -std=c89 or -std=c++98). // // If a std is supplied, only add -trigraphs if it follows the // option. @@ -2619,13 +2839,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_trigraphs); } - // Map the bizarre '-Wwrite-strings' flag to a more sensible - // '-fconst-strings'; this better indicates its actual behavior. - if (Args.hasFlag(options::OPT_Wwrite_strings, options::OPT_Wno_write_strings, - false)) { - // For perfect compatibility with GCC, we do this even in the presence of - // '-w'. This flag names something other than a warning for GCC. - CmdArgs.push_back("-fconst-strings"); + // GCC's behavior for -Wwrite-strings is a bit strange: + // * In C, this "warning flag" changes the types of string literals from + // 'char[N]' to 'const char[N]', and thus triggers an unrelated warning + // for the discarded qualifier. + // * In C++, this is just a normal warning flag. + // + // Implementing this warning correctly in C is hard, so we follow GCC's + // behavior for now. FIXME: Directly diagnose uses of a string literal as + // a non-const char* in C, rather than using this crude hack. + if (!types::isCXX(InputType)) { + DiagnosticsEngine::Level DiagLevel = D.getDiags().getDiagnosticLevel( + diag::warn_deprecated_string_literal_conversion_c, SourceLocation()); + if (DiagLevel > DiagnosticsEngine::Ignored) + CmdArgs.push_back("-fconst-strings"); } // GCC provides a macro definition '__DEPRECATED' when -Wdeprecated is active @@ -2663,11 +2890,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } + if (Arg *A = Args.getLastArg(options::OPT_foperator_arrow_depth_EQ)) { + CmdArgs.push_back("-foperator-arrow-depth"); + CmdArgs.push_back(A->getValue()); + } + if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) { CmdArgs.push_back("-fconstexpr-depth"); CmdArgs.push_back(A->getValue()); } + if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_steps_EQ)) { + CmdArgs.push_back("-fconstexpr-steps"); + CmdArgs.push_back(A->getValue()); + } + if (Arg *A = Args.getLastArg(options::OPT_fbracket_depth_EQ)) { CmdArgs.push_back("-fbracket-depth"); CmdArgs.push_back(A->getValue()); @@ -2759,11 +2996,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info); Args.AddLastArg(CmdArgs, options::OPT_fno_limit_debug_info); Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names); - Args.AddLastArg(CmdArgs, options::OPT_faltivec); + // AltiVec language extensions aren't relevant for assembling. + if (!isa<PreprocessJobAction>(JA) || + Output.getType() != types::TY_PP_Asm) + Args.AddLastArg(CmdArgs, options::OPT_faltivec); Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree); Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type); - SanitizerArgs Sanitize(getToolChain(), Args); + const SanitizerArgs &Sanitize = getToolChain().getSanitizerArgs(); Sanitize.addArgs(Args, CmdArgs); if (!Args.hasFlag(options::OPT_fsanitize_recover, @@ -2778,10 +3018,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Report an error for -faltivec on anything other than PowerPC. if (const Arg *A = Args.getLastArg(options::OPT_faltivec)) - if (!(getToolChain().getTriple().getArch() == llvm::Triple::ppc || - getToolChain().getTriple().getArch() == llvm::Triple::ppc64)) + if (!(getToolChain().getArch() == llvm::Triple::ppc || + getToolChain().getArch() == llvm::Triple::ppc64 || + getToolChain().getArch() == llvm::Triple::ppc64le)) D.Diag(diag::err_drv_argument_only_allowed_with) - << A->getAsString(Args) << "ppc/ppc64"; + << A->getAsString(Args) << "ppc/ppc64/ppc64le"; if (getToolChain().SupportsProfiling()) Args.AddLastArg(CmdArgs, options::OPT_pg); @@ -2822,8 +3063,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (A->getOption().matches(options::OPT_fno_strict_overflow)) CmdArgs.push_back("-fwrapv"); } + + if (Arg *A = Args.getLastArg(options::OPT_freroll_loops, + options::OPT_fno_reroll_loops)) + if (A->getOption().matches(options::OPT_freroll_loops)) + CmdArgs.push_back("-freroll-loops"); + Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings); - Args.AddLastArg(CmdArgs, options::OPT_funroll_loops); + Args.AddLastArg(CmdArgs, options::OPT_funroll_loops, + options::OPT_fno_unroll_loops); Args.AddLastArg(CmdArgs, options::OPT_pthread); @@ -2876,13 +3124,39 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment)); } // -mkernel implies -mstrict-align; don't add the redundant option. - if (Args.hasArg(options::OPT_mstrict_align) && !KernelOrKext) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-arm-strict-align"); + if (!KernelOrKext) { + if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, + options::OPT_munaligned_access)) { + if (A->getOption().matches(options::OPT_mno_unaligned_access)) { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-arm-strict-align"); + } else { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-arm-no-strict-align"); + } + } + } + + if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it, + options::OPT_mno_restrict_it)) { + if (A->getOption().matches(options::OPT_mrestrict_it)) { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-arm-restrict-it"); + } else { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-arm-no-restrict-it"); + } } // Forward -f options with positive and negative forms; we translate // these by hand. + if (Arg *A = Args.getLastArg(options::OPT_fprofile_sample_use_EQ)) { + StringRef fname = A->getValue(); + if (!llvm::sys::fs::exists(fname)) + D.Diag(diag::err_drv_no_such_file) << fname; + else + A->render(Args, CmdArgs); + } if (Args.hasArg(options::OPT_mkernel)) { if (!Args.hasArg(options::OPT_fapple_kext) && types::isCXX(InputType)) @@ -2926,6 +3200,35 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + // -fmodule-maps enables module map processing (off by default) for header + // checking. It is implied by -fmodules. + if (Args.hasFlag(options::OPT_fmodule_maps, options::OPT_fno_module_maps, + false)) { + CmdArgs.push_back("-fmodule-maps"); + } + + // -fmodules-decluse checks that modules used are declared so (off by + // default). + if (Args.hasFlag(options::OPT_fmodules_decluse, + options::OPT_fno_modules_decluse, + false)) { + CmdArgs.push_back("-fmodules-decluse"); + } + + // -fmodule-name specifies the module that is currently being built (or + // used for header checking by -fmodule-maps). + if (Arg *A = Args.getLastArg(options::OPT_fmodule_name)) { + A->claim(); + A->render(Args, CmdArgs); + } + + // -fmodule-map-file can be used to specify a file containing module + // definitions. + if (Arg *A = Args.getLastArg(options::OPT_fmodule_map_file)) { + A->claim(); + A->render(Args, CmdArgs); + } + // If a module path was provided, pass it along. Otherwise, use a temporary // directory. if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) { @@ -2981,7 +3284,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fshort-enums=0 is default for all architectures except Hexagon. if (Args.hasFlag(options::OPT_fshort_enums, options::OPT_fno_short_enums, - getToolChain().getTriple().getArch() == + getToolChain().getArch() == llvm::Triple::hexagon)) CmdArgs.push_back("-fshort-enums"); @@ -2996,11 +3299,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fno-threadsafe-statics"); // -fuse-cxa-atexit is default. - if (!Args.hasFlag(options::OPT_fuse_cxa_atexit, - options::OPT_fno_use_cxa_atexit, - getToolChain().getTriple().getOS() != llvm::Triple::Cygwin && - getToolChain().getTriple().getOS() != llvm::Triple::MinGW32 && - getToolChain().getTriple().getArch() != llvm::Triple::hexagon) || + if (!Args.hasFlag( + options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit, + getToolChain().getTriple().getOS() != llvm::Triple::Cygwin && + getToolChain().getTriple().getOS() != llvm::Triple::MinGW32 && + getToolChain().getArch() != llvm::Triple::hexagon && + getToolChain().getArch() != llvm::Triple::xcore) || KernelOrKext) CmdArgs.push_back("-fno-use-cxa-atexit"); @@ -3018,13 +3322,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, true)))) CmdArgs.push_back("-fms-compatibility"); - // -fmsc-version=1300 is default. + // -fmsc-version=1700 is default. if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, getToolChain().getTriple().getOS() == llvm::Triple::Win32) || Args.hasArg(options::OPT_fmsc_version)) { StringRef msc_ver = Args.getLastArgValue(options::OPT_fmsc_version); if (msc_ver.empty()) - CmdArgs.push_back("-fmsc-version=1300"); + CmdArgs.push_back("-fmsc-version=1700"); else CmdArgs.push_back(Args.MakeArgString("-fmsc-version=" + msc_ver)); } @@ -3062,12 +3366,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, ObjCRuntime objcRuntime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind); // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and - // legacy is the default. - if (objcRuntime.isNonFragile()) { + // legacy is the default. Next runtime is always legacy dispatch and + // -fno-objc-legacy-dispatch gets ignored silently. + if (objcRuntime.isNonFragile() && !objcRuntime.isNeXTFamily()) { if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch, options::OPT_fno_objc_legacy_dispatch, objcRuntime.isLegacyDispatchDefaultForArch( - getToolChain().getTriple().getArch()))) { + getToolChain().getArch()))) { if (getToolChain().UseObjCMixedDispatch()) CmdArgs.push_back("-fobjc-dispatch-method=mixed"); else @@ -3075,12 +3380,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } - // -fobjc-default-synthesize-properties=1 is default. This only has an effect - // if the nonfragile objc abi is used. - if (getToolChain().IsObjCDefaultSynthPropertiesDefault()) { - CmdArgs.push_back("-fobjc-default-synthesize-properties"); - } - + // When ObjectiveC legacy runtime is in effect on MacOSX, + // turn on the option to do Array/Dictionary subscripting + // by default. + if (getToolChain().getTriple().getArch() == llvm::Triple::x86 && + getToolChain().getTriple().isMacOSX() && + !getToolChain().getTriple().isMacOSXVersionLT(10, 7) && + objcRuntime.getKind() == ObjCRuntime::FragileMacOSX && + objcRuntime.isNeXTFamily()) + CmdArgs.push_back("-fobjc-subscripting-legacy-runtime"); + // -fencode-extended-block-signature=1 is default. if (getToolChain().IsEncodeExtendedBlockSignatureDefault()) { CmdArgs.push_back("-fencode-extended-block-signature"); @@ -3160,16 +3469,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar)) A->render(Args, CmdArgs); - // -fno-pascal-strings is default, only pass non-default. If the tool chain - // happened to translate to -mpascal-strings, we want to back translate here. - // - // FIXME: This is gross; that translation should be pulled from the - // tool chain. + // -fno-pascal-strings is default, only pass non-default. if (Args.hasFlag(options::OPT_fpascal_strings, options::OPT_fno_pascal_strings, - false) || - Args.hasFlag(options::OPT_mpascal_strings, - options::OPT_mno_pascal_strings, false)) CmdArgs.push_back("-fpascal-strings"); @@ -3184,7 +3486,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fpack-struct=1"); } - if (KernelOrKext) { + if (KernelOrKext || isNoCommonDefault(getToolChain().getTriple())) { if (!Args.hasArg(options::OPT_fcommon)) CmdArgs.push_back("-fno-common"); Args.ClaimAllArgs(options::OPT_fno_common); @@ -3284,6 +3586,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, (ShowColors == Colors_Auto && llvm::sys::Process::StandardErrHasColors())) CmdArgs.push_back("-fcolor-diagnostics"); + if (Args.hasArg(options::OPT_fansi_escape_codes)) + CmdArgs.push_back("-fansi-escape-codes"); + if (!Args.hasFlag(options::OPT_fshow_source_location, options::OPT_fno_show_source_location)) CmdArgs.push_back("-fno-show-source-location"); @@ -3303,31 +3608,25 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, false)) CmdArgs.push_back("-fasm-blocks"); - // If -Ofast is the optimization level, then -fvectorize should be enabled. - // This alias option is being used to simplify the hasFlag logic. - OptSpecifier VectorizeAliasOption = OFastEnabled ? options::OPT_Ofast : + // Enable vectorization per default according to the optimization level + // selected. For optimization levels that want vectorization we use the alias + // option to simplify the hasFlag logic. + bool EnableVec = shouldEnableVectorizerAtOLevel(Args); + OptSpecifier VectorizeAliasOption = EnableVec ? options::OPT_O_Group : options::OPT_fvectorize; - - // -fvectorize is default. if (Args.hasFlag(options::OPT_fvectorize, VectorizeAliasOption, - options::OPT_fno_vectorize, true)) { - CmdArgs.push_back("-backend-option"); + options::OPT_fno_vectorize, EnableVec)) CmdArgs.push_back("-vectorize-loops"); - } - // -fno-slp-vectorize is default. + // -fslp-vectorize is default. if (Args.hasFlag(options::OPT_fslp_vectorize, - options::OPT_fno_slp_vectorize, false)) { - CmdArgs.push_back("-backend-option"); + options::OPT_fno_slp_vectorize, true)) CmdArgs.push_back("-vectorize-slp"); - } // -fno-slp-vectorize-aggressive is default. if (Args.hasFlag(options::OPT_fslp_vectorize_aggressive, - options::OPT_fno_slp_vectorize_aggressive, false)) { - CmdArgs.push_back("-backend-option"); + options::OPT_fno_slp_vectorize_aggressive, false)) CmdArgs.push_back("-vectorize-slp-aggressive"); - } if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ)) A->render(Args, CmdArgs); @@ -3354,13 +3653,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_apple_pragma_pack, false)) CmdArgs.push_back("-fapple-pragma-pack"); + // le32-specific flags: + // -fno-math-builtin: clang should not convert math builtins to intrinsics + // by default. + if (getToolChain().getArch() == llvm::Triple::le32) { + CmdArgs.push_back("-fno-math-builtin"); + } + // Default to -fno-builtin-str{cat,cpy} on Darwin for ARM. // // FIXME: This is disabled until clang -cc1 supports -fno-builtin-foo. PR4941. #if 0 if (getToolChain().getTriple().isOSDarwin() && - (getToolChain().getTriple().getArch() == llvm::Triple::arm || - getToolChain().getTriple().getArch() == llvm::Triple::thumb)) { + (getToolChain().getArch() == llvm::Triple::arm || + getToolChain().getArch() == llvm::Triple::thumb)) { if (!Args.hasArg(options::OPT_fbuiltin_strcat)) CmdArgs.push_back("-fno-builtin-strcat"); if (!Args.hasArg(options::OPT_fbuiltin_strcpy)) @@ -3457,7 +3763,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Add the split debug info name to the command lines here so we // can propagate it to the backend. bool SplitDwarf = Args.hasArg(options::OPT_gsplit_dwarf) && - (getToolChain().getTriple().getOS() == llvm::Triple::Linux) && + getToolChain().getTriple().isOSLinux() && (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA)); const char *SplitDwarfOut; if (SplitDwarf) { @@ -3467,7 +3773,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // Finally add the compile command to the compilation. - C.addCommand(new Command(JA, *this, Exec, CmdArgs)); + if (Args.hasArg(options::OPT__SLASH_fallback)) { + tools::visualstudio::Compile CL(getToolChain()); + Command *CLCommand = CL.GetCommand(C, JA, Output, Inputs, Args, + LinkingOutput); + C.addCommand(new FallbackCommand(JA, *this, Exec, CmdArgs, CLCommand)); + } else { + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); + } + // Handle the debug info splitting at object creation time if we're // creating an object. @@ -3492,38 +3806,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.ClaimAllArgs(options::OPT_clang_ignored_f_Group); Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group); - // Disable warnings for clang -E -use-gold-plugin -emit-llvm foo.c - Args.ClaimAllArgs(options::OPT_use_gold_plugin); + // Disable warnings for clang -E -emit-llvm foo.c Args.ClaimAllArgs(options::OPT_emit_llvm); } -void ClangAs::AddARMTargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - const Driver &D = getToolChain().getDriver(); - llvm::Triple Triple = getToolChain().getTriple(); - - // Set the CPU based on -march= and -mcpu=. - CmdArgs.push_back("-target-cpu"); - CmdArgs.push_back(Args.MakeArgString(getARMTargetCPU(Args, Triple))); - - // Honor -mfpu=. - if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) - addFPUArgs(D, A, Args, CmdArgs); - - // Honor -mfpmath=. - if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) - addFPMathArgs(D, A, Args, CmdArgs, getARMTargetCPU(Args, Triple)); -} - -void ClangAs::AddX86TargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - // Set the CPU based on -march=. - if (const char *CPUName = getX86TargetCPU(Args, getToolChain().getTriple())) { - CmdArgs.push_back("-target-cpu"); - CmdArgs.push_back(CPUName); - } -} - /// Add options related to the Objective-C runtime/ABI. /// /// Returns true if the runtime is non-fragile. @@ -3649,6 +3935,67 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, return runtime; } +void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + unsigned RTOptionID = options::OPT__SLASH_MT; + + if (Args.hasArg(options::OPT__SLASH_LDd)) + // The /LDd option implies /MTd. The dependent lib part can be overridden, + // but defining _DEBUG is sticky. + RTOptionID = options::OPT__SLASH_MTd; + + if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group)) + RTOptionID = A->getOption().getID(); + + switch(RTOptionID) { + case options::OPT__SLASH_MD: + if (Args.hasArg(options::OPT__SLASH_LDd)) + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-D_DLL"); + CmdArgs.push_back("--dependent-lib=msvcrt"); + break; + case options::OPT__SLASH_MDd: + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-D_DLL"); + CmdArgs.push_back("--dependent-lib=msvcrtd"); + break; + case options::OPT__SLASH_MT: + if (Args.hasArg(options::OPT__SLASH_LDd)) + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("--dependent-lib=libcmt"); + break; + case options::OPT__SLASH_MTd: + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("--dependent-lib=libcmtd"); + break; + default: + llvm_unreachable("Unexpected option ID."); + } + + // This provides POSIX compatibility (maps 'open' to '_open'), which most + // users want. The /Za flag to cl.exe turns this off, but it's not + // implemented in clang. + CmdArgs.push_back("--dependent-lib=oldnames"); + + // FIXME: Make this default for the win32 triple. + CmdArgs.push_back("-cxx-abi"); + CmdArgs.push_back("microsoft"); + + if (Arg *A = Args.getLastArg(options::OPT_show_includes)) + A->render(Args, CmdArgs); + + if (!Args.hasArg(options::OPT_fdiagnostics_format_EQ)) { + CmdArgs.push_back("-fdiagnostics-format"); + if (Args.hasArg(options::OPT__SLASH_fallback)) + CmdArgs.push_back("msvc-fallback"); + else + CmdArgs.push_back("msvc"); + } +} + void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -3663,8 +4010,6 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, Args.ClaimAllArgs(options::OPT_w); // and "clang -emit-llvm -c foo.s" Args.ClaimAllArgs(options::OPT_emit_llvm); - // and "clang -use-gold-plugin -c foo.s" - Args.ClaimAllArgs(options::OPT_use_gold_plugin); // Invoke ourselves in -cc1as mode. // @@ -3687,25 +4032,18 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-main-file-name"); CmdArgs.push_back(Clang::getBaseInputName(Args, Inputs)); - if (UseRelaxAll(C, Args)) - CmdArgs.push_back("-relax-all"); - - // Add target specific cpu and features flags. - switch(getToolChain().getTriple().getArch()) { - default: - break; - - case llvm::Triple::arm: - case llvm::Triple::thumb: - AddARMTargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::x86: - case llvm::Triple::x86_64: - AddX86TargetArgs(Args, CmdArgs); - break; + // Add the target cpu + const llvm::Triple &Triple = getToolChain().getTriple(); + std::string CPU = getCPUName(Args, Triple); + if (!CPU.empty()) { + CmdArgs.push_back("-target-cpu"); + CmdArgs.push_back(Args.MakeArgString(CPU)); } + // Add the target features + const Driver &D = getToolChain().getDriver(); + getTargetFeatures(D, Triple, Args, CmdArgs); + // Ignore explicit -force_cpusubtype_ALL option. (void) Args.hasArg(options::OPT_force__cpusubtype__ALL); @@ -3755,8 +4093,9 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // FIXME: Add -static support, once we have it. - Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, - options::OPT_Xassembler); + CollectArgsForIntegratedAssembler(C, Args, CmdArgs, + getToolChain().getDriver()); + Args.AddAllArgs(CmdArgs, options::OPT_mllvm); assert(Output.isFilename() && "Unexpected lipo output."); @@ -3773,7 +4112,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // creating an object. // TODO: Currently only works on linux with newer objcopy. if (Args.hasArg(options::OPT_gsplit_dwarf) && - (getToolChain().getTriple().getOS() == llvm::Triple::Linux)) + getToolChain().getTriple().isOSLinux()) SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDebugName(Args, Inputs)); } @@ -3795,6 +4134,11 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, A->getOption().matches(options::OPT_g_Group)) continue; + // Don't forward any -W arguments to assembly and link steps. + if ((isa<AssembleJobAction>(JA) || isa<LinkJobAction>(JA)) && + A->getOption().matches(options::OPT_W_Group)) + continue; + // It is unfortunate that we have to claim here, as this means // we will basically never report anything interesting for // platforms using a generic gcc, even if we are just using gcc @@ -3816,6 +4160,8 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("ppc"); else if (Arch == llvm::Triple::ppc64) CmdArgs.push_back("ppc64"); + else if (Arch == llvm::Triple::ppc64le) + CmdArgs.push_back("ppc64le"); else CmdArgs.push_back(Args.MakeArgString(getToolChain().getArchName())); } @@ -3827,7 +4173,8 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, // here. if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) CmdArgs.push_back("-m32"); - else if (Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::ppc64) + else if (Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::ppc64 || + Arch == llvm::Triple::ppc64le) CmdArgs.push_back("-m64"); if (Output.isFilename()) { @@ -3890,7 +4237,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, const char *GCCName; if (!customGCCName.empty()) GCCName = customGCCName.c_str(); - else if (D.CCCIsCXX) { + else if (D.CCCIsCXX()) { GCCName = "g++"; } else GCCName = "gcc"; @@ -4152,7 +4499,7 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA, // Libraries //---------------------------------------------------------------------------- if (incStdLib && incDefLibs) { - if (D.CCCIsCXX) { + if (D.CCCIsCXX()) { ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } @@ -4179,10 +4526,7 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA, } std::string Linker = ToolChain.GetProgramPath("hexagon-ld"); - C.addCommand( - new Command( - JA, *this, - Args.MakeArgString(Linker), CmdArgs)); + C.addCommand(new Command(JA, *this, Args.MakeArgString(Linker), CmdArgs)); } // Hexagon tools end. @@ -4206,7 +4550,7 @@ llvm::Triple::ArchType darwin::getArchTypeForDarwinArchName(StringRef Str) { .Cases("i386", "i486", "i486SX", "i586", "i686", llvm::Triple::x86) .Cases("pentium", "pentpro", "pentIIm3", "pentIIm5", "pentium4", llvm::Triple::x86) - .Case("x86_64", llvm::Triple::x86_64) + .Cases("x86_64", "x86_64h", llvm::Triple::x86_64) // This is derived from the driver driver. .Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm) .Cases("armv7", "armv7em", "armv7f", "armv7k", "armv7m", llvm::Triple::arm) @@ -4266,6 +4610,11 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, SourceAction = SourceAction->getInputs()[0]; } + // If -no_integrated_as is used add -Q to the darwin assember driver to make + // sure it runs its system assembler not clang's integrated assembler. + if (Args.hasArg(options::OPT_no_integrated_as)) + CmdArgs.push_back("-Q"); + // Forward -g, assuming we are dealing with an actual assembly file. if (SourceAction->getType() == types::TY_Asm || SourceAction->getType() == types::TY_PP_Asm) { @@ -4279,12 +4628,12 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, AddDarwinArch(Args, CmdArgs); // Use -force_cpusubtype_ALL on x86 by default. - if (getToolChain().getTriple().getArch() == llvm::Triple::x86 || - getToolChain().getTriple().getArch() == llvm::Triple::x86_64 || + if (getToolChain().getArch() == llvm::Triple::x86 || + getToolChain().getArch() == llvm::Triple::x86_64 || Args.hasArg(options::OPT_force__cpusubtype__ALL)) CmdArgs.push_back("-force_cpusubtype_ALL"); - if (getToolChain().getTriple().getArch() != llvm::Triple::x86_64 && + if (getToolChain().getArch() != llvm::Triple::x86_64 && (((Args.hasArg(options::OPT_mkernel) || Args.hasArg(options::OPT_fapple_kext)) && (!getDarwinToolChain().isTargetIPhoneOS() || @@ -4375,6 +4724,9 @@ void darwin::Link::AddLinkArgs(Compilation &C, CmdArgs.push_back("-demangle"); } + if (Args.hasArg(options::OPT_rdynamic) && Version[0] >= 137) + CmdArgs.push_back("-export_dynamic"); + // If we are using LTO, then automatically create a temporary file path for // the linker to use, so that it's lifetime will extend past a possible // dsymutil step. @@ -4573,7 +4925,6 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_u_Group); Args.AddLastArg(CmdArgs, options::OPT_e); - Args.AddAllArgs(CmdArgs, options::OPT_m_Separate); Args.AddAllArgs(CmdArgs, options::OPT_r); // Forward -ObjC when either -ObjC or -ObjC++ is used, to force loading @@ -4582,9 +4933,6 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_ObjC) || Args.hasArg(options::OPT_ObjCXX)) CmdArgs.push_back("-ObjC"); - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export_dynamic"); - CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); @@ -4681,19 +5029,6 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); - SanitizerArgs Sanitize(getToolChain(), Args); - // If we're building a dynamic lib with -fsanitize=address, - // unresolved symbols may appear. Mark all - // of them as dynamic_lookup. Linking executables is handled in - // lib/Driver/ToolChains.cpp. - if (Sanitize.needsAsanRt()) { - if (Args.hasArg(options::OPT_dynamiclib) || - Args.hasArg(options::OPT_bundle)) { - CmdArgs.push_back("-undefined"); - CmdArgs.push_back("dynamic_lookup"); - } - } - if (Args.hasArg(options::OPT_fopenmp)) // This is more complicated in gcc... CmdArgs.push_back("-lgomp"); @@ -4733,7 +5068,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { - if (getToolChain().getDriver().CCCIsCXX) + if (getToolChain().getDriver().CCCIsCXX()) getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); // link_ssp spec is empty. @@ -4858,18 +5193,17 @@ void solaris::Link::ConstructJob(Compilation &C, const JobAction &JA, std::string LibPath = "/usr/lib/"; llvm::Triple::ArchType Arch = T.getArch(); switch (Arch) { - case llvm::Triple::x86: - GCCLibPath += ("i386-" + T.getVendorName() + "-" + - T.getOSName()).str() + "/4.5.2/"; - break; - case llvm::Triple::x86_64: - GCCLibPath += ("i386-" + T.getVendorName() + "-" + - T.getOSName()).str(); - GCCLibPath += "/4.5.2/amd64/"; - LibPath += "amd64/"; - break; - default: - assert(0 && "Unsupported architecture"); + case llvm::Triple::x86: + GCCLibPath += + ("i386-" + T.getVendorName() + "-" + T.getOSName()).str() + "/4.5.2/"; + break; + case llvm::Triple::x86_64: + GCCLibPath += ("i386-" + T.getVendorName() + "-" + T.getOSName()).str(); + GCCLibPath += "/4.5.2/amd64/"; + LibPath += "amd64/"; + break; + default: + llvm_unreachable("Unsupported architecture"); } ArgStringList CmdArgs; @@ -4915,7 +5249,7 @@ void solaris::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(LibPath + "values-Xa.o")); CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtbegin.o")); } - if (getToolChain().getDriver().CCCIsCXX) + if (getToolChain().getDriver().CCCIsCXX()) CmdArgs.push_back(Args.MakeArgString(LibPath + "cxa_finalize.o")); } @@ -4930,7 +5264,7 @@ void solaris::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { - if (getToolChain().getDriver().CCCIsCXX) + if (getToolChain().getDriver().CCCIsCXX()) getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lgcc_s"); if (!Args.hasArg(options::OPT_shared)) { @@ -5072,6 +5406,40 @@ void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { ArgStringList CmdArgs; + // When building 32-bit code on OpenBSD/amd64, we have to explicitly + // instruct as in the base system to assemble 32-bit code. + if (getToolChain().getArch() == llvm::Triple::x86) + CmdArgs.push_back("--32"); + else if (getToolChain().getArch() == llvm::Triple::ppc) { + CmdArgs.push_back("-mppc"); + CmdArgs.push_back("-many"); + } else if (getToolChain().getArch() == llvm::Triple::mips64 || + getToolChain().getArch() == llvm::Triple::mips64el) { + StringRef CPUName; + StringRef ABIName; + getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); + + CmdArgs.push_back("-mabi"); + CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data()); + + if (getToolChain().getArch() == llvm::Triple::mips64) + CmdArgs.push_back("-EB"); + else + CmdArgs.push_back("-EL"); + + Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, + options::OPT_fpic, options::OPT_fno_pic, + options::OPT_fPIE, options::OPT_fno_PIE, + options::OPT_fpie, options::OPT_fno_pie); + if (LastPICArg && + (LastPICArg->getOption().matches(options::OPT_fPIC) || + LastPICArg->getOption().matches(options::OPT_fpic) || + LastPICArg->getOption().matches(options::OPT_fPIE) || + LastPICArg->getOption().matches(options::OPT_fpie))) { + CmdArgs.push_back("-KPIC"); + } + } + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); @@ -5105,6 +5473,11 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); + if (getToolChain().getArch() == llvm::Triple::mips64) + CmdArgs.push_back("-EB"); + else if (getToolChain().getArch() == llvm::Triple::mips64el) + CmdArgs.push_back("-EL"); + if ((!Args.hasArg(options::OPT_nostdlib)) && (!Args.hasArg(options::OPT_shared))) { CmdArgs.push_back("-e"); @@ -5126,6 +5499,9 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, } } + if (Args.hasArg(options::OPT_nopie)) + CmdArgs.push_back("-nopie"); + if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); @@ -5168,7 +5544,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { - if (D.CCCIsCXX) { + if (D.CCCIsCXX()) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); @@ -5298,7 +5674,7 @@ void bitrig::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { - if (D.CCCIsCXX) { + if (D.CCCIsCXX()) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); @@ -5321,23 +5697,21 @@ void bitrig::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lc"); } - std::string myarch = "-lclang_rt."; - const llvm::Triple &T = getToolChain().getTriple(); - llvm::Triple::ArchType Arch = T.getArch(); - switch (Arch) { - case llvm::Triple::arm: - myarch += ("arm"); - break; - case llvm::Triple::x86: - myarch += ("i386"); - break; - case llvm::Triple::x86_64: - myarch += ("amd64"); - break; - default: - assert(0 && "Unsupported architecture"); - } - CmdArgs.push_back(Args.MakeArgString(myarch)); + StringRef MyArch; + switch (getToolChain().getTriple().getArch()) { + case llvm::Triple::arm: + MyArch = "arm"; + break; + case llvm::Triple::x86: + MyArch = "i386"; + break; + case llvm::Triple::x86_64: + MyArch = "amd64"; + break; + default: + llvm_unreachable("Unsupported architecture"); + } + CmdArgs.push_back(Args.MakeArgString("-lclang_rt." + MyArch)); } if (!Args.hasArg(options::OPT_nostdlib) && @@ -5374,7 +5748,7 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().getArch() == llvm::Triple::mips64el) { StringRef CPUName; StringRef ABIName; - getMipsCPUAndABI(Args, getToolChain(), CPUName, ABIName); + getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); CmdArgs.push_back("-march"); CmdArgs.push_back(CPUName.data()); @@ -5534,11 +5908,31 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); + // Tell the linker to load the plugin. This has to come before AddLinkerInputs + // as gold requires -plugin to come before any -plugin-opt that -Wl might + // forward. + if (D.IsUsingLTO(Args)) { + CmdArgs.push_back("-plugin"); + std::string Plugin = ToolChain.getDriver().Dir + "/../lib/LLVMgold.so"; + CmdArgs.push_back(Args.MakeArgString(Plugin)); + + // Try to pass driver level flags relevant to LTO code generation down to + // the plugin. + + // Handle flags for selecting CPU variants. + std::string CPU = getCPUName(Args, ToolChain.getTriple()); + if (!CPU.empty()) { + CmdArgs.push_back( + Args.MakeArgString(Twine("-plugin-opt=mcpu=") + + CPU)); + } + } + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { - if (D.CCCIsCXX) { + if (D.CCCIsCXX()) { ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); @@ -5618,11 +6012,45 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, if (getToolChain().getArch() == llvm::Triple::x86) CmdArgs.push_back("--32"); - // Set byte order explicitly - if (getToolChain().getArch() == llvm::Triple::mips) - CmdArgs.push_back("-EB"); - else if (getToolChain().getArch() == llvm::Triple::mipsel) - CmdArgs.push_back("-EL"); + // Pass the target CPU to GNU as for ARM, since the source code might + // not have the correct .cpu annotation. + if (getToolChain().getArch() == llvm::Triple::arm) { + std::string MArch(getARMTargetCPU(Args, getToolChain().getTriple())); + CmdArgs.push_back(Args.MakeArgString("-mcpu=" + MArch)); + } + + if (getToolChain().getArch() == llvm::Triple::mips || + getToolChain().getArch() == llvm::Triple::mipsel || + getToolChain().getArch() == llvm::Triple::mips64 || + getToolChain().getArch() == llvm::Triple::mips64el) { + StringRef CPUName; + StringRef ABIName; + getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); + + CmdArgs.push_back("-march"); + CmdArgs.push_back(CPUName.data()); + + CmdArgs.push_back("-mabi"); + CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data()); + + if (getToolChain().getArch() == llvm::Triple::mips || + getToolChain().getArch() == llvm::Triple::mips64) + CmdArgs.push_back("-EB"); + else + CmdArgs.push_back("-EL"); + + Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, + options::OPT_fpic, options::OPT_fno_pic, + options::OPT_fPIE, options::OPT_fno_PIE, + options::OPT_fpie, options::OPT_fno_pie); + if (LastPICArg && + (LastPICArg->getOption().matches(options::OPT_fPIC) || + LastPICArg->getOption().matches(options::OPT_fpic) || + LastPICArg->getOption().matches(options::OPT_fPIE) || + LastPICArg->getOption().matches(options::OPT_fpie))) { + CmdArgs.push_back("-KPIC"); + } + } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); @@ -5706,34 +6134,39 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + unsigned Major, Minor, Micro; + getToolChain().getTriple().getOSVersion(Major, Minor, Micro); + bool useLibgcc = true; + if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 23) || Major == 0) { + if (getToolChain().getArch() == llvm::Triple::x86 || + getToolChain().getArch() == llvm::Triple::x86_64) + useLibgcc = false; + } + if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { - if (D.CCCIsCXX) { + if (D.CCCIsCXX()) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } - // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding - // the default system libraries. Just mimic this for now. - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-lgcc_eh"); - } else { - CmdArgs.push_back("--as-needed"); - CmdArgs.push_back("-lgcc_s"); - CmdArgs.push_back("--no-as-needed"); - } - CmdArgs.push_back("-lgcc"); - if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lgcc"); - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-lgcc_eh"); - } else { - CmdArgs.push_back("--as-needed"); - CmdArgs.push_back("-lgcc_s"); - CmdArgs.push_back("--no-as-needed"); + if (useLibgcc) { + if (Args.hasArg(options::OPT_static)) { + // libgcc_eh depends on libc, so resolve as much as possible, + // pull in any new requirements from libc and then get the rest + // of libgcc. + CmdArgs.push_back("-lgcc_eh"); + CmdArgs.push_back("-lc"); + CmdArgs.push_back("-lgcc"); + } else { + CmdArgs.push_back("-lgcc"); + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lgcc_s"); + CmdArgs.push_back("--no-as-needed"); + } } } @@ -5776,10 +6209,16 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-a64"); CmdArgs.push_back("-mppc64"); CmdArgs.push_back("-many"); + } else if (getToolChain().getArch() == llvm::Triple::ppc64le) { + CmdArgs.push_back("-a64"); + CmdArgs.push_back("-mppc64le"); + CmdArgs.push_back("-many"); } else if (getToolChain().getArch() == llvm::Triple::arm) { StringRef MArch = getToolChain().getArchName(); if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a") CmdArgs.push_back("-mfpu=neon"); + if (MArch == "armv8" || MArch == "armv8a" || MArch == "armv8-a") + CmdArgs.push_back("-mfpu=crypto-neon-fp-armv8"); StringRef ARMFloatABI = getARMFloatABI(getToolChain().getDriver(), Args, getToolChain().getTriple()); @@ -5794,7 +6233,7 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().getArch() == llvm::Triple::mips64el) { StringRef CPUName; StringRef ABIName; - getMipsCPUAndABI(Args, getToolChain(), CPUName, ABIName); + getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); CmdArgs.push_back("-march"); CmdArgs.push_back(CPUName.data()); @@ -5808,12 +6247,31 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("-EL"); + if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) { + if (StringRef(A->getValue()) == "2008") + CmdArgs.push_back(Args.MakeArgString("-mnan=2008")); + } + + if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfp64)) { + if (A->getOption().matches(options::OPT_mfp32)) + CmdArgs.push_back(Args.MakeArgString("-mfp32")); + else + CmdArgs.push_back(Args.MakeArgString("-mfp64")); + } + Args.AddLastArg(CmdArgs, options::OPT_mips16, options::OPT_mno_mips16); Args.AddLastArg(CmdArgs, options::OPT_mmicromips, options::OPT_mno_micromips); Args.AddLastArg(CmdArgs, options::OPT_mdsp, options::OPT_mno_dsp); Args.AddLastArg(CmdArgs, options::OPT_mdspr2, options::OPT_mno_dspr2); + if (Arg *A = Args.getLastArg(options::OPT_mmsa, options::OPT_mno_msa)) { + // Do not use AddLastArg because not all versions of MIPS assembler + // support -mmsa / -mno-msa options. + if (A->getOption().matches(options::OPT_mmsa)) + CmdArgs.push_back(Args.MakeArgString("-mmsa")); + } + Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, options::OPT_fpic, options::OPT_fno_pic, options::OPT_fPIE, options::OPT_fno_PIE, @@ -5826,8 +6284,10 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-KPIC"); } } else if (getToolChain().getArch() == llvm::Triple::systemz) { - // At the moment we always produce z10 code. - CmdArgs.push_back("-march=z10"); + // Always pass an -march option, since our default of z10 is later + // than the GNU assembler's default. + StringRef CPUName = getSystemZTargetCPU(Args); + CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName)); } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, @@ -5845,6 +6305,14 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); + + // Handle the debug info splitting at object creation time if we're + // creating an object. + // TODO: Currently only works on linux with newer objcopy. + if (Args.hasArg(options::OPT_gsplit_dwarf) && + getToolChain().getTriple().isOSLinux()) + SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, + SplitDebugName(Args, Inputs)); } static void AddLibgcc(llvm::Triple Triple, const Driver &D, @@ -5852,23 +6320,23 @@ static void AddLibgcc(llvm::Triple Triple, const Driver &D, bool isAndroid = Triple.getEnvironment() == llvm::Triple::Android; bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) || Args.hasArg(options::OPT_static); - if (!D.CCCIsCXX) + if (!D.CCCIsCXX()) CmdArgs.push_back("-lgcc"); if (StaticLibgcc || isAndroid) { - if (D.CCCIsCXX) + if (D.CCCIsCXX()) CmdArgs.push_back("-lgcc"); } else { - if (!D.CCCIsCXX) + if (!D.CCCIsCXX()) CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lgcc_s"); - if (!D.CCCIsCXX) + if (!D.CCCIsCXX()) CmdArgs.push_back("--no-as-needed"); } if (StaticLibgcc && !isAndroid) CmdArgs.push_back("-lgcc_eh"); - else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX) + else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX()) CmdArgs.push_back("-lgcc"); // According to Android ABI, we have to link with libdl if we are @@ -5885,6 +6353,39 @@ static bool hasMipsN32ABIArg(const ArgList &Args) { return A && (A->getValue() == StringRef("n32")); } +static StringRef getLinuxDynamicLinker(const ArgList &Args, + const toolchains::Linux &ToolChain) { + if (ToolChain.getTriple().getEnvironment() == llvm::Triple::Android) + return "/system/bin/linker"; + else if (ToolChain.getArch() == llvm::Triple::x86) + return "/lib/ld-linux.so.2"; + else if (ToolChain.getArch() == llvm::Triple::aarch64) + return "/lib/ld-linux-aarch64.so.1"; + else if (ToolChain.getArch() == llvm::Triple::arm || + ToolChain.getArch() == llvm::Triple::thumb) { + if (ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUEABIHF) + return "/lib/ld-linux-armhf.so.3"; + else + return "/lib/ld-linux.so.3"; + } else if (ToolChain.getArch() == llvm::Triple::mips || + ToolChain.getArch() == llvm::Triple::mipsel) + return "/lib/ld.so.1"; + else if (ToolChain.getArch() == llvm::Triple::mips64 || + ToolChain.getArch() == llvm::Triple::mips64el) { + if (hasMipsN32ABIArg(Args)) + return "/lib32/ld.so.1"; + else + return "/lib64/ld.so.1"; + } else if (ToolChain.getArch() == llvm::Triple::ppc) + return "/lib/ld.so.1"; + else if (ToolChain.getArch() == llvm::Triple::ppc64 || + ToolChain.getArch() == llvm::Triple::ppc64le || + ToolChain.getArch() == llvm::Triple::systemz) + return "/lib64/ld64.so.1"; + else + return "/lib64/ld-linux-x86-64.so.2"; +} + void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -5895,7 +6396,7 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, const Driver &D = ToolChain.getDriver(); const bool isAndroid = ToolChain.getTriple().getEnvironment() == llvm::Triple::Android; - SanitizerArgs Sanitize(getToolChain(), Args); + const SanitizerArgs &Sanitize = ToolChain.getSanitizerArgs(); const bool IsPIE = !Args.hasArg(options::OPT_shared) && (Args.hasArg(options::OPT_pie) || Sanitize.hasZeroBaseShadow()); @@ -5982,36 +6483,8 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, (!Args.hasArg(options::OPT_static) && !Args.hasArg(options::OPT_shared))) { CmdArgs.push_back("-dynamic-linker"); - if (isAndroid) - CmdArgs.push_back("/system/bin/linker"); - else if (ToolChain.getArch() == llvm::Triple::x86) - CmdArgs.push_back("/lib/ld-linux.so.2"); - else if (ToolChain.getArch() == llvm::Triple::aarch64) - CmdArgs.push_back("/lib/ld-linux-aarch64.so.1"); - else if (ToolChain.getArch() == llvm::Triple::arm || - ToolChain.getArch() == llvm::Triple::thumb) { - if (ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUEABIHF) - CmdArgs.push_back("/lib/ld-linux-armhf.so.3"); - else - CmdArgs.push_back("/lib/ld-linux.so.3"); - } - else if (ToolChain.getArch() == llvm::Triple::mips || - ToolChain.getArch() == llvm::Triple::mipsel) - CmdArgs.push_back("/lib/ld.so.1"); - else if (ToolChain.getArch() == llvm::Triple::mips64 || - ToolChain.getArch() == llvm::Triple::mips64el) { - if (hasMipsN32ABIArg(Args)) - CmdArgs.push_back("/lib32/ld.so.1"); - else - CmdArgs.push_back("/lib64/ld.so.1"); - } - else if (ToolChain.getArch() == llvm::Triple::ppc) - CmdArgs.push_back("/lib/ld.so.1"); - else if (ToolChain.getArch() == llvm::Triple::ppc64 || - ToolChain.getArch() == llvm::Triple::systemz) - CmdArgs.push_back("/lib64/ld64.so.1"); - else - CmdArgs.push_back("/lib64/ld-linux-x86-64.so.2"); + CmdArgs.push_back(Args.MakeArgString( + D.DyldPrefix + getLinuxDynamicLinker(Args, ToolChain))); } CmdArgs.push_back("-o"); @@ -6022,7 +6495,9 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!isAndroid) { const char *crt1 = NULL; if (!Args.hasArg(options::OPT_shared)){ - if (IsPIE) + if (Args.hasArg(options::OPT_pg)) + crt1 = "gcrt1.o"; + else if (IsPIE) crt1 = "Scrt1.o"; else crt1 = "crt1.o"; @@ -6059,7 +6534,7 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, // Tell the linker to load the plugin. This has to come before AddLinkerInputs // as gold requires -plugin to come before any -plugin-opt that -Wl might // forward. - if (D.IsUsingLTO(Args) || Args.hasArg(options::OPT_use_gold_plugin)) { + if (D.IsUsingLTO(Args)) { CmdArgs.push_back("-plugin"); std::string Plugin = ToolChain.getDriver().Dir + "/../lib/LLVMgold.so"; CmdArgs.push_back(Args.MakeArgString(Plugin)); @@ -6067,20 +6542,13 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, // Try to pass driver level flags relevant to LTO code generation down to // the plugin. - // Handle architecture-specific flags for selecting CPU variants. - if (ToolChain.getArch() == llvm::Triple::x86 || - ToolChain.getArch() == llvm::Triple::x86_64) + // Handle flags for selecting CPU variants. + std::string CPU = getCPUName(Args, ToolChain.getTriple()); + if (!CPU.empty()) { CmdArgs.push_back( - Args.MakeArgString(Twine("-plugin-opt=mcpu=") + - getX86TargetCPU(Args, ToolChain.getTriple()))); - else if (ToolChain.getArch() == llvm::Triple::arm || - ToolChain.getArch() == llvm::Triple::thumb) - CmdArgs.push_back( - Args.MakeArgString(Twine("-plugin-opt=mcpu=") + - getARMTargetCPU(Args, ToolChain.getTriple()))); - - // FIXME: Factor out logic for MIPS, PPC, and other targets to support this - // as well. + Args.MakeArgString(Twine("-plugin-opt=mcpu=") + + CPU)); + } } @@ -6091,17 +6559,24 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, // Call these before we add the C++ ABI library. if (Sanitize.needsUbsanRt()) - addUbsanRTLinux(getToolChain(), Args, CmdArgs, D.CCCIsCXX, + addUbsanRTLinux(getToolChain(), Args, CmdArgs, D.CCCIsCXX(), Sanitize.needsAsanRt() || Sanitize.needsTsanRt() || - Sanitize.needsMsanRt()); + Sanitize.needsMsanRt() || Sanitize.needsLsanRt()); if (Sanitize.needsAsanRt()) addAsanRTLinux(getToolChain(), Args, CmdArgs); if (Sanitize.needsTsanRt()) addTsanRTLinux(getToolChain(), Args, CmdArgs); if (Sanitize.needsMsanRt()) addMsanRTLinux(getToolChain(), Args, CmdArgs); + if (Sanitize.needsLsanRt()) + addLsanRTLinux(getToolChain(), Args, CmdArgs); + if (Sanitize.needsDfsanRt()) + addDfsanRTLinux(getToolChain(), Args, CmdArgs); - if (D.CCCIsCXX && + // The profile runtime also needs access to system libraries. + addProfileRTLinux(getToolChain(), Args, CmdArgs); + + if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && @@ -6157,8 +6632,6 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, } } - addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple()); - C.addCommand(new Command(JA, *this, ToolChain.Linker.c_str(), CmdArgs)); } @@ -6219,7 +6692,7 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { - if (D.CCCIsCXX) { + if (D.CCCIsCXX()) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } @@ -6367,7 +6840,7 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, } } - if (D.CCCIsCXX) { + if (D.CCCIsCXX()) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } @@ -6439,22 +6912,223 @@ void visualstudio::Link::ConstructJob(Compilation &C, const JobAction &JA, } if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + !Args.hasArg(options::OPT_nostartfiles) && + !C.getDriver().IsCLMode()) { CmdArgs.push_back("-defaultlib:libcmt"); } CmdArgs.push_back("-nologo"); + bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd); + + if (DLL) { + CmdArgs.push_back(Args.MakeArgString("-dll")); + + SmallString<128> ImplibName(Output.getFilename()); + llvm::sys::path::replace_extension(ImplibName, "lib"); + CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + + ImplibName.str())); + } + + if (getToolChain().getSanitizerArgs().needsAsanRt()) { + CmdArgs.push_back(Args.MakeArgString("-debug")); + CmdArgs.push_back(Args.MakeArgString("-incremental:no")); + SmallString<128> LibSanitizer(getToolChain().getDriver().ResourceDir); + llvm::sys::path::append(LibSanitizer, "lib", "windows"); + if (DLL) { + llvm::sys::path::append(LibSanitizer, "clang_rt.asan_dll_thunk-i386.lib"); + } else { + llvm::sys::path::append(LibSanitizer, "clang_rt.asan-i386.lib"); + } + // FIXME: Handle 64-bit. + CmdArgs.push_back(Args.MakeArgString(LibSanitizer)); + } + Args.AddAllArgValues(CmdArgs, options::OPT_l); + Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link); // Add filenames immediately. for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { if (it->isFilename()) CmdArgs.push_back(it->getFilename()); + else + it->getInputArg().renderAsInput(Args, CmdArgs); } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("link.exe")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } + +void visualstudio::Compile::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + C.addCommand(GetCommand(C, JA, Output, Inputs, Args, LinkingOutput)); +} + +// Try to find FallbackName on PATH that is not identical to ClangProgramPath. +// If one cannot be found, return FallbackName. +// We do this special search to prevent clang-cl from falling back onto itself +// if it's available as cl.exe on the path. +static std::string FindFallback(const char *FallbackName, + const char *ClangProgramPath) { + llvm::Optional<std::string> OptPath = llvm::sys::Process::GetEnv("PATH"); + if (!OptPath.hasValue()) + return FallbackName; + +#ifdef LLVM_ON_WIN32 + const StringRef PathSeparators = ";"; +#else + const StringRef PathSeparators = ":"; +#endif + + SmallVector<StringRef, 8> PathSegments; + llvm::SplitString(OptPath.getValue(), PathSegments, PathSeparators); + + for (size_t i = 0, e = PathSegments.size(); i != e; ++i) { + const StringRef &PathSegment = PathSegments[i]; + if (PathSegment.empty()) + continue; + + SmallString<128> FilePath(PathSegment); + llvm::sys::path::append(FilePath, FallbackName); + if (llvm::sys::fs::can_execute(Twine(FilePath)) && + !llvm::sys::fs::equivalent(Twine(FilePath), ClangProgramPath)) + return FilePath.str(); + } + + return FallbackName; +} + +Command *visualstudio::Compile::GetCommand(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + CmdArgs.push_back("/nologo"); + CmdArgs.push_back("/c"); // Compile only. + CmdArgs.push_back("/W0"); // No warnings. + + // The goal is to be able to invoke this tool correctly based on + // any flag accepted by clang-cl. + + // These are spelled the same way in clang and cl.exe,. + Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U); + Args.AddAllArgs(CmdArgs, options::OPT_I); + + // Optimization level. + if (Arg *A = Args.getLastArg(options::OPT_O, options::OPT_O0)) { + if (A->getOption().getID() == options::OPT_O0) { + CmdArgs.push_back("/Od"); + } else { + StringRef OptLevel = A->getValue(); + if (OptLevel == "1" || OptLevel == "2" || OptLevel == "s") + A->render(Args, CmdArgs); + else if (OptLevel == "3") + CmdArgs.push_back("/Ox"); + } + } + + // Flags for which clang-cl have an alias. + // FIXME: How can we ensure this stays in sync with relevant clang-cl options? + + if (Arg *A = Args.getLastArg(options::OPT_frtti, options::OPT_fno_rtti)) + CmdArgs.push_back(A->getOption().getID() == options::OPT_frtti ? "/GR" + : "/GR-"); + if (Args.hasArg(options::OPT_fsyntax_only)) + CmdArgs.push_back("/Zs"); + + std::vector<std::string> Includes = Args.getAllArgValues(options::OPT_include); + for (size_t I = 0, E = Includes.size(); I != E; ++I) + CmdArgs.push_back(Args.MakeArgString(std::string("/FI") + Includes[I])); + + // Flags that can simply be passed through. + Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LD); + Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LDd); + + // The order of these flags is relevant, so pick the last one. + if (Arg *A = Args.getLastArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd, + options::OPT__SLASH_MT, options::OPT__SLASH_MTd)) + A->render(Args, CmdArgs); + + + // Input filename. + assert(Inputs.size() == 1); + const InputInfo &II = Inputs[0]; + assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX); + CmdArgs.push_back(II.getType() == types::TY_C ? "/Tc" : "/Tp"); + if (II.isFilename()) + CmdArgs.push_back(II.getFilename()); + else + II.getInputArg().renderAsInput(Args, CmdArgs); + + // Output filename. + assert(Output.getType() == types::TY_Object); + const char *Fo = Args.MakeArgString(std::string("/Fo") + + Output.getFilename()); + CmdArgs.push_back(Fo); + + const Driver &D = getToolChain().getDriver(); + std::string Exec = FindFallback("cl.exe", D.getClangProgramPath()); + + return new Command(JA, *this, Args.MakeArgString(Exec), CmdArgs); +} + + +/// XCore Tools +// We pass assemble and link construction to the xcc tool. + +void XCore::Assemble::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + CmdArgs.push_back("-c"); + + if (Args.hasArg(options::OPT_g_Group)) { + CmdArgs.push_back("-g"); + } + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, + options::OPT_Xassembler); + + for (InputInfoList::const_iterator + it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { + const InputInfo &II = *it; + CmdArgs.push_back(II.getFilename()); + } + + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath("xcc")); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); +} + +void XCore::Link::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else { + assert(Output.isNothing() && "Invalid output."); + } + + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath("xcc")); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); +} diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.h b/contrib/llvm/tools/clang/lib/Driver/Tools.h index d647171..d5b2848 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tools.h +++ b/contrib/llvm/tools/clang/lib/Driver/Tools.h @@ -14,12 +14,14 @@ #include "clang/Driver/Types.h" #include "clang/Driver/Util.h" #include "llvm/ADT/Triple.h" +#include "llvm/Option/Option.h" #include "llvm/Support/Compiler.h" namespace clang { class ObjCRuntime; namespace driver { + class Command; class Driver; namespace toolchains { @@ -27,40 +29,53 @@ namespace toolchains { } namespace tools { +using llvm::opt::ArgStringList; /// \brief Clang compiler tool. class LLVM_LIBRARY_VISIBILITY Clang : public Tool { public: - static const char *getBaseInputName(const ArgList &Args, + static const char *getBaseInputName(const llvm::opt::ArgList &Args, const InputInfoList &Inputs); - static const char *getBaseInputStem(const ArgList &Args, + static const char *getBaseInputStem(const llvm::opt::ArgList &Args, const InputInfoList &Inputs); - static const char *getDependencyFileName(const ArgList &Args, + static const char *getDependencyFileName(const llvm::opt::ArgList &Args, const InputInfoList &Inputs); private: - void AddPreprocessingOptions(Compilation &C, - const JobAction &JA, + void AddPreprocessingOptions(Compilation &C, const JobAction &JA, const Driver &D, - const ArgList &Args, - ArgStringList &CmdArgs, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, const InputInfo &Output, const InputInfoList &Inputs) const; - void AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs, + void AddAArch64TargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddARMTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, bool KernelOrKext) const; - void AddMIPSTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; - void AddPPCTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; - void AddR600TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; - void AddSparcTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; - void AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; - void AddHexagonTargetArgs (const ArgList &Args, ArgStringList &CmdArgs) const; + void AddMIPSTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddR600TargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddSparcTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddSystemZTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddX86TargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddHexagonTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; enum RewriteKind { RK_None, RK_Fragile, RK_NonFragile }; - ObjCRuntime AddObjCRuntimeArgs(const ArgList &args, ArgStringList &cmdArgs, + ObjCRuntime AddObjCRuntimeArgs(const llvm::opt::ArgList &args, + llvm::opt::ArgStringList &cmdArgs, RewriteKind rewrite) const; + void AddClangCLArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + public: Clang(const ToolChain &TC) : Tool("clang", "clang frontend", TC) {} @@ -71,14 +86,12 @@ namespace tools { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; /// \brief Clang integrated assembler tool. class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool { - void AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; - void AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; public: ClangAs(const ToolChain &TC) : Tool("clang::as", "clang integrated assembler", TC) {} @@ -90,7 +103,7 @@ namespace tools { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; @@ -104,16 +117,16 @@ namespace gcc { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; /// RenderExtraToolArgs - Render any arguments necessary to force /// the particular tool mode. - virtual void RenderExtraToolArgs(const JobAction &JA, - ArgStringList &CmdArgs) const = 0; + virtual void + RenderExtraToolArgs(const JobAction &JA, + llvm::opt::ArgStringList &CmdArgs) const = 0; }; - class LLVM_LIBRARY_VISIBILITY Preprocess : public Common { public: Preprocess(const ToolChain &TC) : Common("gcc::Preprocess", @@ -123,7 +136,7 @@ namespace gcc { virtual bool hasIntegratedCPP() const { return false; } virtual void RenderExtraToolArgs(const JobAction &JA, - ArgStringList &CmdArgs) const; + llvm::opt::ArgStringList &CmdArgs) const; }; class LLVM_LIBRARY_VISIBILITY Precompile : public Common { @@ -135,7 +148,7 @@ namespace gcc { virtual bool hasIntegratedCPP() const { return true; } virtual void RenderExtraToolArgs(const JobAction &JA, - ArgStringList &CmdArgs) const; + llvm::opt::ArgStringList &CmdArgs) const; }; class LLVM_LIBRARY_VISIBILITY Compile : public Common { @@ -147,7 +160,7 @@ namespace gcc { virtual bool hasIntegratedCPP() const { return true; } virtual void RenderExtraToolArgs(const JobAction &JA, - ArgStringList &CmdArgs) const; + llvm::opt::ArgStringList &CmdArgs) const; }; class LLVM_LIBRARY_VISIBILITY Assemble : public Common { @@ -158,7 +171,7 @@ namespace gcc { virtual bool hasIntegratedCPP() const { return false; } virtual void RenderExtraToolArgs(const JobAction &JA, - ArgStringList &CmdArgs) const; + llvm::opt::ArgStringList &CmdArgs) const; }; class LLVM_LIBRARY_VISIBILITY Link : public Common { @@ -170,7 +183,7 @@ namespace gcc { virtual bool isLinkJob() const { return true; } virtual void RenderExtraToolArgs(const JobAction &JA, - ArgStringList &CmdArgs) const; + llvm::opt::ArgStringList &CmdArgs) const; }; } // end namespace gcc @@ -185,11 +198,11 @@ namespace hexagon { virtual bool hasIntegratedCPP() const { return false; } virtual void RenderExtraToolArgs(const JobAction &JA, - ArgStringList &CmdArgs) const; + llvm::opt::ArgStringList &CmdArgs) const; virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; @@ -202,11 +215,11 @@ namespace hexagon { virtual bool isLinkJob() const { return true; } virtual void RenderExtraToolArgs(const JobAction &JA, - ArgStringList &CmdArgs) const; + llvm::opt::ArgStringList &CmdArgs) const; virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; } // end namespace hexagon. @@ -218,7 +231,8 @@ namespace darwin { class LLVM_LIBRARY_VISIBILITY DarwinTool : public Tool { virtual void anchor(); protected: - void AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const; + void AddDarwinArch(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; const toolchains::Darwin &getDarwinToolChain() const { return reinterpret_cast<const toolchains::Darwin&>(getToolChain()); @@ -239,14 +253,15 @@ namespace darwin { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; class LLVM_LIBRARY_VISIBILITY Link : public DarwinTool { bool NeedsTempPath(const InputInfoList &Inputs) const; - void AddLinkArgs(Compilation &C, const ArgList &Args, - ArgStringList &CmdArgs, const InputInfoList &Inputs) const; + void AddLinkArgs(Compilation &C, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + const InputInfoList &Inputs) const; public: Link(const ToolChain &TC) : DarwinTool("darwin::Link", "linker", TC) {} @@ -257,7 +272,7 @@ namespace darwin { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; @@ -270,7 +285,7 @@ namespace darwin { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; @@ -285,7 +300,7 @@ namespace darwin { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; @@ -299,7 +314,7 @@ namespace darwin { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; @@ -317,7 +332,7 @@ namespace openbsd { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; class LLVM_LIBRARY_VISIBILITY Link : public Tool { @@ -330,7 +345,7 @@ namespace openbsd { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; } // end namespace openbsd @@ -347,7 +362,7 @@ namespace bitrig { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; class LLVM_LIBRARY_VISIBILITY Link : public Tool { @@ -360,7 +375,7 @@ namespace bitrig { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; } // end namespace bitrig @@ -377,7 +392,7 @@ namespace freebsd { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; class LLVM_LIBRARY_VISIBILITY Link : public Tool { @@ -390,7 +405,7 @@ namespace freebsd { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; } // end namespace freebsd @@ -408,7 +423,7 @@ namespace netbsd { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; class LLVM_LIBRARY_VISIBILITY Link : public Tool { @@ -423,7 +438,7 @@ namespace netbsd { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; } // end namespace netbsd @@ -439,7 +454,7 @@ namespace gnutools { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; class LLVM_LIBRARY_VISIBILITY Link : public Tool { @@ -452,7 +467,7 @@ namespace gnutools { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; } @@ -468,7 +483,7 @@ namespace minix { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; class LLVM_LIBRARY_VISIBILITY Link : public Tool { @@ -481,7 +496,7 @@ namespace minix { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; } // end namespace minix @@ -498,7 +513,7 @@ namespace solaris { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; class LLVM_LIBRARY_VISIBILITY Link : public Tool { @@ -511,7 +526,7 @@ namespace solaris { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; } // end namespace solaris @@ -528,7 +543,7 @@ namespace auroraux { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; class LLVM_LIBRARY_VISIBILITY Link : public Tool { @@ -541,7 +556,7 @@ namespace auroraux { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; } // end namespace auroraux @@ -558,7 +573,7 @@ namespace dragonfly { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; class LLVM_LIBRARY_VISIBILITY Link : public Tool { @@ -571,14 +586,14 @@ namespace dragonfly { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; }; } // end namespace dragonfly /// Visual studio tools. namespace visualstudio { - class LLVM_LIBRARY_VISIBILITY Link : public Tool { + class LLVM_LIBRARY_VISIBILITY Link : public Tool { public: Link(const ToolChain &TC) : Tool("visualstudio::Link", "linker", TC) {} @@ -588,11 +603,64 @@ namespace visualstudio { virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &TCArgs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const; + }; + + class LLVM_LIBRARY_VISIBILITY Compile : public Tool { + public: + Compile(const ToolChain &TC) : Tool("visualstudio::Compile", "compiler", TC) {} + + virtual bool hasIntegratedAssembler() const { return true; } + virtual bool hasIntegratedCPP() const { return true; } + virtual bool isLinkJob() const { return false; } + + virtual void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const; + + Command *GetCommand(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const; }; } // end namespace visualstudio +namespace XCore { + // For XCore, we do not need to instantiate tools for PreProcess, PreCompile and Compile. + // We simply use "clang -cc1" for those actions. + class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { + public: + Assemble(const ToolChain &TC) : Tool("XCore::Assemble", + "XCore-as", TC) {} + + virtual bool hasIntegratedCPP() const { return false; } + virtual void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const; + }; + + class LLVM_LIBRARY_VISIBILITY Link : public Tool { + public: + Link(const ToolChain &TC) : Tool("XCore::Link", + "XCore-ld", TC) {} + + virtual bool hasIntegratedCPP() const { return false; } + virtual bool isLinkJob() const { return true; } + virtual void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const; + }; +} // end namespace XCore. + + } // end namespace toolchains } // end namespace driver } // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Driver/Types.cpp b/contrib/llvm/tools/clang/lib/Driver/Types.cpp index 7d22596..d947ae7 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Types.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Types.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Types.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" #include <cassert> #include <string.h> @@ -28,7 +29,7 @@ static const TypeInfo TypeInfos[] = { #include "clang/Driver/Types.def" #undef TYPE }; -static const unsigned numTypes = sizeof(TypeInfos) / sizeof(TypeInfos[0]); +static const unsigned numTypes = llvm::array_lengthof(TypeInfos); static const TypeInfo &getInfo(unsigned id) { assert(id > 0 && id - 1 < numTypes && "Invalid Type ID."); @@ -43,7 +44,13 @@ types::ID types::getPreprocessedType(ID Id) { return getInfo(Id).PreprocessedType; } -const char *types::getTypeTempSuffix(ID Id) { +const char *types::getTypeTempSuffix(ID Id, bool CLMode) { + if (Id == TY_Object && CLMode) + return "obj"; + if (Id == TY_Image && CLMode) + return "exe"; + if (Id == TY_PP_Asm && CLMode) + return "asm"; return getInfo(Id).TempSuffix; } @@ -132,8 +139,10 @@ types::ID types::lookupTypeForExtension(const char *Ext) { .Case("f", TY_PP_Fortran) .Case("F", TY_Fortran) .Case("s", TY_PP_Asm) + .Case("asm", TY_PP_Asm) .Case("S", TY_Asm) .Case("o", TY_Object) + .Case("obj", TY_Object) .Case("ii", TY_PP_CXX) .Case("mi", TY_PP_ObjC) .Case("mm", TY_ObjCXX) @@ -180,9 +189,7 @@ types::ID types::lookupTypeForTypeSpecifier(const char *Name) { } // FIXME: Why don't we just put this list in the defs file, eh. -void types::getCompilationPhases( - ID Id, - llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> &P) { +void types::getCompilationPhases(ID Id, llvm::SmallVectorImpl<phases::ID> &P) { if (Id != TY_Object) { if (getPreprocessedType(Id) != TY_INVALID) { P.push_back(phases::Preprocess); diff --git a/contrib/llvm/tools/clang/lib/Driver/WindowsToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/WindowsToolChain.cpp index 622c492..2b6320a 100644 --- a/contrib/llvm/tools/clang/lib/Driver/WindowsToolChain.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/WindowsToolChain.cpp @@ -10,12 +10,12 @@ #include "ToolChains.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Version.h" -#include "clang/Driver/Arg.h" -#include "clang/Driver/ArgList.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Path.h" @@ -31,6 +31,7 @@ using namespace clang::driver; using namespace clang::driver::toolchains; using namespace clang; +using namespace llvm::opt; Windows::Windows(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) @@ -44,7 +45,7 @@ Tool *Windows::buildLinker() const { Tool *Windows::buildAssembler() const { if (getTriple().getEnvironment() == llvm::Triple::MachO) return new tools::darwin::Assemble(*this); - getDriver().Diag(clang::diag::err_no_external_windows_assembler); + getDriver().Diag(clang::diag::err_no_external_assembler); return NULL; } @@ -125,7 +126,8 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName, strncpy(partialKey, subKey, partialKeyLength); partialKey[partialKeyLength] = '\0'; HKEY hTopKey = NULL; - lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ, &hTopKey); + lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY, + &hTopKey); if (lResult == ERROR_SUCCESS) { char keyName[256]; int bestIndex = -1; @@ -144,33 +146,34 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName, char numBuf[32]; strncpy(numBuf, sp, sizeof(numBuf) - 1); numBuf[sizeof(numBuf) - 1] = '\0'; - double value = strtod(numBuf, NULL); - if (value > bestValue) { - bestIndex = (int)index; - bestValue = value; + double dvalue = strtod(numBuf, NULL); + if (dvalue > bestValue) { + // Test that InstallDir is indeed there before keeping this index. + // Open the chosen key path remainder. strcpy(bestName, keyName); + // Append rest of key. + strncat(bestName, nextKey, sizeof(bestName) - 1); + bestName[sizeof(bestName) - 1] = '\0'; + lResult = RegOpenKeyEx(hTopKey, bestName, 0, + KEY_READ | KEY_WOW64_32KEY, &hKey); + if (lResult == ERROR_SUCCESS) { + lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType, + (LPBYTE)value, &valueSize); + if (lResult == ERROR_SUCCESS) { + bestIndex = (int)index; + bestValue = dvalue; + returnValue = true; + } + RegCloseKey(hKey); + } } size = sizeof(keyName) - 1; } - // If we found the highest versioned key, open the key and get the value. - if (bestIndex != -1) { - // Append rest of key. - strncat(bestName, nextKey, sizeof(bestName) - 1); - bestName[sizeof(bestName) - 1] = '\0'; - // Open the chosen key path remainder. - lResult = RegOpenKeyEx(hTopKey, bestName, 0, KEY_READ, &hKey); - if (lResult == ERROR_SUCCESS) { - lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType, - (LPBYTE)value, &valueSize); - if (lResult == ERROR_SUCCESS) - returnValue = true; - RegCloseKey(hKey); - } - } RegCloseKey(hTopKey); } } else { - lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ, &hKey); + lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ | KEY_WOW64_32KEY, + &hKey); if (lResult == ERROR_SUCCESS) { lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType, (LPBYTE)value, &valueSize); @@ -282,8 +285,8 @@ void Windows::AddClangSystemIncludeArgs(const ArgList &DriverArgs, return; if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { - llvm::sys::Path P(getDriver().ResourceDir); - P.appendComponent("include"); + SmallString<128> P(getDriver().ResourceDir); + llvm::sys::path::append(P, "include"); addSystemInclude(DriverArgs, CC1Args, P.str()); } |