diff options
author | dim <dim@FreeBSD.org> | 2014-03-21 17:53:59 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2014-03-21 17:53:59 +0000 |
commit | 9cedb8bb69b89b0f0c529937247a6a80cabdbaec (patch) | |
tree | c978f0e9ec1ab92dc8123783f30b08a7fd1e2a39 /contrib/llvm/tools/clang/lib/Driver | |
parent | 03fdc2934eb61c44c049a02b02aa974cfdd8a0eb (diff) | |
download | FreeBSD-src-9cedb8bb69b89b0f0c529937247a6a80cabdbaec.zip FreeBSD-src-9cedb8bb69b89b0f0c529937247a6a80cabdbaec.tar.gz |
MFC 261991:
Upgrade our copy of llvm/clang to 3.4 release. This version supports
all of the features in the current working draft of the upcoming C++
standard, provisionally named C++1y.
The code generator's performance is greatly increased, and the loop
auto-vectorizer is now enabled at -Os and -O2 in addition to -O3. The
PowerPC backend has made several major improvements to code generation
quality and compile time, and the X86, SPARC, ARM32, Aarch64 and SystemZ
backends have all seen major feature work.
Release notes for llvm and clang can be found here:
<http://llvm.org/releases/3.4/docs/ReleaseNotes.html>
<http://llvm.org/releases/3.4/tools/clang/docs/ReleaseNotes.html>
MFC 262121 (by emaste):
Update lldb for clang/llvm 3.4 import
This commit largely restores the lldb source to the upstream r196259
snapshot with the addition of threaded inferior support and a few bug
fixes.
Specific upstream lldb revisions restored include:
SVN git
181387 779e6ac
181703 7bef4e2
182099 b31044e
182650 f2dcf35
182683 0d91b80
183862 15c1774
183929 99447a6
184177 0b2934b
184948 4dc3761
184954 007e7bc
186990 eebd175
Sponsored by: DARPA, AFRL
MFC 262186 (by emaste):
Fix mismerge in r262121
A break statement was lost in the merge. The error had no functional
impact, but restore it to reduce the diff against upstream.
MFC 262303:
Pull in r197521 from upstream clang trunk (by rdivacky):
Use the integrated assembler by default on FreeBSD/ppc and ppc64.
Requested by: jhibbits
MFC 262611:
Pull in r196874 from upstream llvm trunk:
Fix a crash that occurs when PWD is invalid.
MCJIT needs to be able to run in hostile environments, even when PWD
is invalid. There's no need to crash MCJIT in this case.
The obvious fix is to simply leave MCContext's CompilationDir empty
when PWD can't be determined. This way, MCJIT clients,
and other clients that link with LLVM don't need a valid working directory.
If we do want to guarantee valid CompilationDir, that should be done
only for clients of getCompilationDir(). This is as simple as checking
for an empty string.
The only current use of getCompilationDir is EmitGenDwarfInfo, which
won't conceivably run with an invalid working dir. However, in the
purely hypothetically and untestable case that this happens, the
AT_comp_dir will be omitted from the compilation_unit DIE.
This should help fix assertions occurring with ports-mgmt/tinderbox,
when it is using jails, and sometimes invalidates clang's current
working directory.
Reported by: decke
MFC 262809:
Pull in r203007 from upstream clang trunk:
Don't produce an alias between destructors with different calling conventions.
Fixes pr19007.
(Please note that is an LLVM PR identifier, not a FreeBSD one.)
This should fix Firefox and/or libxul crashes (due to problems with
regparm/stdcall calling conventions) on i386.
Reported by: multiple users on freebsd-current
PR: bin/187103
MFC 263048:
Repair recognition of "CC" as an alias for the C++ compiler, since it
was silently broken by upstream for a Windows-specific use-case.
Apparently some versions of CMake still rely on this archaic feature...
Reported by: rakuco
MFC 263049:
Garbage collect the old way of adding the libstdc++ include directories
in clang's InitHeaderSearch.cpp. This has been superseded by David
Chisnall's commit in r255321.
Moreover, if libc++ is used, the libstdc++ include directories should
not be in the search path at all. These directories are now only used
if you pass -stdlib=libstdc++.
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()); } |