diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Driver')
18 files changed, 1888 insertions, 1815 deletions
diff --git a/contrib/llvm/tools/clang/lib/Driver/Action.cpp b/contrib/llvm/tools/clang/lib/Driver/Action.cpp index d7b4bc7..2b5bbee 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Action.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Action.cpp @@ -9,7 +9,6 @@ #include "clang/Driver/Action.h" #include "llvm/Support/ErrorHandling.h" - #include <cassert> using namespace clang::driver; diff --git a/contrib/llvm/tools/clang/lib/Driver/ArgList.cpp b/contrib/llvm/tools/clang/lib/Driver/ArgList.cpp index b3a43df..6c57b62 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ArgList.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ArgList.cpp @@ -11,7 +11,6 @@ #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" @@ -84,7 +83,6 @@ Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1) const { (*it)->getOption().matches(Id1)) { Res = *it; Res->claim(); - } } @@ -308,6 +306,14 @@ const char *ArgList::GetOrMakeJoinedArgString(unsigned Index, 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, diff --git a/contrib/llvm/tools/clang/lib/Driver/CC1AsOptions.cpp b/contrib/llvm/tools/clang/lib/Driver/CC1AsOptions.cpp index 4f89b73..9048043 100644 --- a/contrib/llvm/tools/clang/lib/Driver/CC1AsOptions.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/CC1AsOptions.cpp @@ -8,8 +8,8 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/CC1AsOptions.h" -#include "clang/Driver/Option.h" #include "clang/Driver/OptTable.h" +#include "clang/Driver/Option.h" using namespace clang; using namespace clang::driver; using namespace clang::driver::options; diff --git a/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp b/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp index 124e50c..1bff4a3 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp @@ -8,20 +8,18 @@ //===----------------------------------------------------------------------===// #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/raw_ostream.h" #include "llvm/Support/Program.h" -#include <sys/stat.h> +#include "llvm/Support/raw_ostream.h" #include <errno.h> +#include <sys/stat.h> using namespace clang::driver; using namespace clang; @@ -113,7 +111,7 @@ static bool skipArg(const char *Flag, bool &SkipNextArg) { bool Res = llvm::StringSwitch<bool>(Flag) .Cases("-I", "-MF", "-MT", "-MQ", true) .Cases("-o", "-coverage-file", "-dependency-file", true) - .Cases("-fdebug-compilation-dir", "-fmodule-cache-path", "-idirafter", 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) @@ -201,39 +199,56 @@ void Compilation::PrintDiagnosticJob(raw_ostream &OS, const Job &J) const { } } +bool Compilation::CleanupFile(const char *File, bool IssueErrors) const { + llvm::sys::Path P(File); + std::string Error; + + // 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()) + 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. + + // 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; + } + } + return true; +} + bool Compilation::CleanupFileList(const ArgStringList &Files, bool IssueErrors) const { bool Success = true; - for (ArgStringList::const_iterator - it = Files.begin(), ie = Files.end(); it != ie; ++it) { + it = Files.begin(), ie = Files.end(); it != ie; ++it) + Success &= CleanupFile(*it, IssueErrors); + return Success; +} - llvm::sys::Path P(*it); - std::string Error; +bool Compilation::CleanupFileMap(const ArgStringMap &Files, + const JobAction *JA, + bool IssueErrors) const { + bool Success = true; + for (ArgStringMap::const_iterator + it = Files.begin(), ie = Files.end(); it != ie; ++it) { - // Don't try to remove files which we don't have write access to (but may be - // able to remove). Underlying tools may have intentionally not overwritten - // them. - if (!P.canWrite()) + // If specified, only delete the files associated with the JobAction. + // Otherwise, delete all files in the map. + if (JA && it->first != JA) continue; - - 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. - - // 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; - Success = false; - } - } + Success &= CleanupFile(it->second, IssueErrors); } - return Success; } @@ -275,11 +290,12 @@ 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); + &Error, &ExecutionFailed); if (!Error.empty()) { assert(Res && "Error string set with 0 result code!"); getDriver().Diag(clang::diag::err_drv_command_failure) << Error; @@ -289,24 +305,51 @@ int Compilation::ExecuteCommand(const Command &C, FailingCommand = &C; delete[] Argv; - return Res; + return ExecutionFailed ? 1 : Res; +} + +typedef SmallVectorImpl< std::pair<int, const Command *> > FailingCommandList; + +static bool ActionFailed(const Action *A, + const FailingCommandList &FailingCommands) { + + if (FailingCommands.empty()) + return false; + + for (FailingCommandList::const_iterator CI = FailingCommands.begin(), + CE = FailingCommands.end(); CI != CE; ++CI) + if (A == &(CI->second->getSource())) + return true; + + for (Action::const_iterator AI = A->begin(), AE = A->end(); AI != AE; ++AI) + if (ActionFailed(*AI, FailingCommands)) + return true; + + return false; } -int Compilation::ExecuteJob(const Job &J, - const Command *&FailingCommand) const { +static bool InputsOk(const Command &C, + const FailingCommandList &FailingCommands) { + return !ActionFailed(&C.getSource(), FailingCommands); +} + +void Compilation::ExecuteJob(const Job &J, + FailingCommandList &FailingCommands) const { if (const Command *C = dyn_cast<Command>(&J)) { - return ExecuteCommand(*C, FailingCommand); + if (!InputsOk(*C, FailingCommands)) + return; + const Command *FailingCommand = 0; + if (int Res = ExecuteCommand(*C, FailingCommand)) + FailingCommands.push_back(std::make_pair(Res, FailingCommand)); } else { const JobList *Jobs = cast<JobList>(&J); - for (JobList::const_iterator - it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it) - if (int Res = ExecuteJob(**it, FailingCommand)) - return Res; - return 0; + for (JobList::const_iterator it = Jobs->begin(), ie = Jobs->end(); + it != ie; ++it) + ExecuteJob(**it, FailingCommands); } } -void Compilation::initCompilationForDiagnostics(void) { +void Compilation::initCompilationForDiagnostics() { // Free actions and jobs. DeleteContainerPointers(Actions); Jobs.clear(); @@ -314,6 +357,7 @@ void Compilation::initCompilationForDiagnostics(void) { // Clear temporary/results file lists. TempFiles.clear(); ResultFiles.clear(); + FailureResultFiles.clear(); // Remove any user specified output. Claim any unclaimed arguments, so as // to avoid emitting warnings about unused args. @@ -331,6 +375,6 @@ void Compilation::initCompilationForDiagnostics(void) { Redirects[2] = new const llvm::sys::Path(); } -StringRef Compilation::getSysRoot(void) const { +StringRef Compilation::getSysRoot() const { return getDriver().SysRoot; } diff --git a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp index 3c410bb..6af03bd 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp @@ -8,7 +8,9 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Driver.h" - +#include "InputInfo.h" +#include "ToolChains.h" +#include "clang/Basic/Version.h" #include "clang/Driver/Action.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" @@ -20,24 +22,20 @@ #include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" - -#include "clang/Basic/Version.h" - #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringSet.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Program.h" - -#include "InputInfo.h" -#include "ToolChains.h" - +#include "llvm/Support/raw_ostream.h" #include <map> +// FIXME: It would prevent us from including llvm-config.h +// if config.h were included before system_error.h. #include "clang/Config/config.h" using namespace clang::driver; @@ -46,7 +44,6 @@ using namespace clang; Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple, StringRef DefaultImageName, - bool IsProduction, DiagnosticsEngine &Diags) : Opts(createDriverOptTable()), Diags(Diags), ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT), @@ -129,6 +126,7 @@ const { // -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler. } else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) || + (PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) || (PhaseArg = DAL.getLastArg(options::OPT_rewrite_objc)) || (PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) || (PhaseArg = DAL.getLastArg(options::OPT__migrate)) || @@ -242,7 +240,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { if (char *env = ::getenv("COMPILER_PATH")) { StringRef CompilerPath = env; while (!CompilerPath.empty()) { - std::pair<StringRef, StringRef> Split = CompilerPath.split(':'); + std::pair<StringRef, StringRef> Split + = CompilerPath.split(llvm::sys::PathSeparator); PrefixDirs.push_back(Split.first); CompilerPath = Split.second; } @@ -251,7 +250,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // 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 = false, CCCPrintActions = false; + bool CCCPrintOptions, CCCPrintActions; InputArgList *Args = ParseArgStrings(ArgList.slice(1)); @@ -293,6 +292,9 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { if (Args->hasArg(options::OPT_nostdlib)) UseStdLib = false; + if (const Arg *A = Args->getLastArg(options::OPT_resource_dir)) + ResourceDir = A->getValue(); + // Perform the default argument translations. DerivedArgList *TranslatedArgs = TranslateInputArgs(*Args); @@ -342,8 +344,9 @@ void Driver::generateCompilationDiagnostics(Compilation &C, if (C.getArgs().hasArg(options::OPT_fno_crash_diagnostics)) return; - // Don't try to generate diagnostics for link jobs. - if (FailingCommand && FailingCommand->getCreator().isLinkJob()) + // Don't try to generate diagnostics for link or dsymutil jobs. + if (FailingCommand && (FailingCommand->getCreator().isLinkJob() || + FailingCommand->getCreator().isDsymutilJob())) return; // Print the version of the compiler. @@ -369,9 +372,12 @@ void Driver::generateCompilationDiagnostics(Compilation &C, C.PrintDiagnosticJob(OS, C.getJobs()); OS.flush(); - // Clear stale state and suppress tool output. + // Keep track of whether we produce any errors while trying to produce + // preprocessed sources. + DiagnosticErrorTrap Trap(Diags); + + // Suppress tool output. C.initCompilationForDiagnostics(); - Diags.Reset(); // Construct the list of inputs. InputList Inputs; @@ -398,6 +404,12 @@ void Driver::generateCompilationDiagnostics(Compilation &C, } } + if (Inputs.empty()) { + Diag(clang::diag::note_drv_command_failed_diag_msg) + << "Error generating preprocessed source(s) - no preprocessable inputs."; + return; + } + // Don't attempt to generate preprocessed files if multiple -arch options are // used, unless they're all duplicates. llvm::StringSet<> ArchNames; @@ -416,12 +428,6 @@ void Driver::generateCompilationDiagnostics(Compilation &C, return; } - if (Inputs.empty()) { - Diag(clang::diag::note_drv_command_failed_diag_msg) - << "Error generating preprocessed source(s) - no preprocessable inputs."; - return; - } - // Construct the list of abstract actions to perform for this compilation. On // Darwin OSes this uses the driver-driver and builds universal actions. const ToolChain &TC = C.getDefaultToolChain(); @@ -433,18 +439,18 @@ void Driver::generateCompilationDiagnostics(Compilation &C, BuildJobs(C); // If there were errors building the compilation, quit now. - if (Diags.hasErrorOccurred()) { + if (Trap.hasErrorOccurred()) { Diag(clang::diag::note_drv_command_failed_diag_msg) << "Error generating preprocessed source(s)."; return; } // Generate preprocessed output. - FailingCommand = 0; - int Res = C.ExecuteJob(C.getJobs(), FailingCommand); + SmallVector<std::pair<int, const Command *>, 4> FailingCommands; + C.ExecuteJob(C.getJobs(), FailingCommands); // If the command succeeded, we are done. - if (Res == 0) { + if (FailingCommands.empty()) { Diag(clang::diag::note_drv_command_failed_diag_msg) << "\n********************\n\n" "PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:\n" @@ -485,8 +491,9 @@ void Driver::generateCompilationDiagnostics(Compilation &C, << "\n\n********************"; } else { // Failure, remove preprocessed files. - if (!C.getArgs().hasArg(options::OPT_save_temps)) + if (!C.getArgs().hasArg(options::OPT_save_temps)) { C.CleanupFileList(C.getTempFiles(), true); + } Diag(clang::diag::note_drv_command_failed_diag_msg) << "Error generating preprocessed source(s)."; @@ -494,7 +501,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C, } int Driver::ExecuteCompilation(const Compilation &C, - const Command *&FailingCommand) const { + 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); @@ -505,44 +512,52 @@ int Driver::ExecuteCompilation(const Compilation &C, if (Diags.hasErrorOccurred()) return 1; - int Res = C.ExecuteJob(C.getJobs(), FailingCommand); + C.ExecuteJob(C.getJobs(), FailingCommands); // Remove temp files. C.CleanupFileList(C.getTempFiles()); // If the command succeeded, we are done. - if (Res == 0) - return Res; - - // Otherwise, remove result files as well. - if (!C.getArgs().hasArg(options::OPT_save_temps)) { - C.CleanupFileList(C.getResultFiles(), true); + if (FailingCommands.empty()) + return 0; - // Failure result files are valid unless we crashed. - if (Res < 0) - C.CleanupFileList(C.getFailureResultFiles(), true); - } + // Otherwise, remove result files and print extra information about abnormal + // failures. + for (SmallVectorImpl< std::pair<int, const Command *> >::iterator it = + FailingCommands.begin(), ie = FailingCommands.end(); it != ie; ++it) { + int Res = it->first; + const Command *FailingCommand = it->second; + + // Remove result files if we're not saving temps. + if (!C.getArgs().hasArg(options::OPT_save_temps)) { + const JobAction *JA = cast<JobAction>(&FailingCommand->getSource()); + C.CleanupFileMap(C.getResultFiles(), JA, true); + + // Failure result files are valid unless we crashed. + if (Res < 0) + C.CleanupFileMap(C.getFailureResultFiles(), JA, true); + } - // Print extra information about abnormal failures, if possible. - // - // This is ad-hoc, but we don't want to be excessively noisy. If the result - // status was 1, assume the command failed normally. In particular, if it was - // the compiler then assume it gave a reasonable error code. Failures in other - // tools are less common, and they generally have worse diagnostics, so always - // print the diagnostic there. - const Tool &FailingTool = FailingCommand->getCreator(); - - if (!FailingCommand->getCreator().hasGoodDiagnostics() || Res != 1) { - // FIXME: See FIXME above regarding result code interpretation. - if (Res < 0) - Diag(clang::diag::err_drv_command_signalled) - << FailingTool.getShortName(); - else - Diag(clang::diag::err_drv_command_failed) - << FailingTool.getShortName() << Res; + // Print extra information about abnormal failures, if possible. + // + // This is ad-hoc, but we don't want to be excessively noisy. If the result + // status was 1, assume the command failed normally. In particular, if it + // was the compiler then assume it gave a reasonable error code. Failures + // in other tools are less common, and they generally have worse + // diagnostics, so always print the diagnostic there. + const Tool &FailingTool = FailingCommand->getCreator(); + + if (!FailingCommand->getCreator().hasGoodDiagnostics() || Res != 1) { + // FIXME: See FIXME above regarding result code interpretation. + if (Res < 0) + Diag(clang::diag::err_drv_command_signalled) + << FailingTool.getShortName(); + else + Diag(clang::diag::err_drv_command_failed) + << FailingTool.getShortName() << Res; + } } - - return Res; + return 0; } void Driver::PrintOptions(const ArgList &Args) const { @@ -861,7 +876,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC, // Add a 'dsymutil' step if necessary, when debug info is enabled and we // have a compile input. We need to run 'dsymutil' ourselves in such cases - // because the debug info will refer to a temporary object file which is + // because the debug info will refer to a temporary object file which // will be removed at the end of the compilation process. if (Act->getType() == types::TY_Image) { ActionList Inputs; @@ -1026,17 +1041,18 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args, // Construct the actions to perform. ActionList LinkerInputs; - unsigned NumSteps = 0; + ActionList SplitInputs; + llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PL; for (unsigned i = 0, e = Inputs.size(); i != e; ++i) { types::ID InputType = Inputs[i].first; const Arg *InputArg = Inputs[i].second; - NumSteps = types::getNumCompilationPhases(InputType); - assert(NumSteps && "Invalid number of steps!"); + PL.clear(); + types::getCompilationPhases(InputType, PL); // If the first step comes after the final phase we are doing as part of // this compilation, warn the user about it. - phases::ID InitialPhase = types::getCompilationPhase(InputType, 0); + phases::ID InitialPhase = PL[0]; if (InitialPhase > FinalPhase) { // Claim here to avoid the more general unused warning. InputArg->claim(); @@ -1071,8 +1087,9 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args, // Build the pipeline for this file. OwningPtr<Action> Current(new InputAction(*InputArg, InputType)); - for (unsigned i = 0; i != NumSteps; ++i) { - phases::ID Phase = types::getCompilationPhase(InputType, i); + for (llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases>::iterator + i = PL.begin(), e = PL.end(); i != e; ++i) { + phases::ID Phase = *i; // We are done if this step is past what the user requested. if (Phase > FinalPhase) @@ -1080,7 +1097,7 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args, // Queue linker inputs. if (Phase == phases::Link) { - assert(i + 1 == NumSteps && "linking must be final compilation step."); + assert((i + 1) == e && "linking must be final compilation step."); LinkerInputs.push_back(Current.take()); break; } @@ -1108,7 +1125,7 @@ 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 && (NumSteps == 1)) + if (FinalPhase == phases::Link && PL.size() == 1) Args.ClaimAllArgs(options::OPT_CompileOnly_Group); } @@ -1154,6 +1171,8 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, return new MigrateJobAction(Input, types::TY_Remap); } else if (Args.hasArg(options::OPT_emit_ast)) { return new CompileJobAction(Input, types::TY_AST); + } else if (Args.hasArg(options::OPT_module_file_info)) { + return new CompileJobAction(Input, types::TY_ModuleFile); } else if (IsUsingLTO(Args)) { types::ID Output = Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC; @@ -1272,7 +1291,7 @@ void Driver::BuildJobs(Compilation &C) const { } } -static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC, +static const Tool *SelectToolForJob(Compilation &C, const ToolChain *TC, const JobAction *JA, const ActionList *&Inputs) { const Tool *ToolForJob = 0; @@ -1281,23 +1300,23 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC, // bottom up, so what we are actually looking for is an assembler job with a // compiler input. - if (C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - TC->IsIntegratedAssemblerDefault()) && + if (TC->useIntegratedAs() && !C.getArgs().hasArg(options::OPT_save_temps) && isa<AssembleJobAction>(JA) && Inputs->size() == 1 && isa<CompileJobAction>(*Inputs->begin())) { - const Tool &Compiler = TC->SelectTool( - C, cast<JobAction>(**Inputs->begin()), (*Inputs)[0]->getInputs()); - if (Compiler.hasIntegratedAssembler()) { + const Tool *Compiler = + TC->SelectTool(cast<JobAction>(**Inputs->begin())); + if (!Compiler) + return NULL; + if (Compiler->hasIntegratedAssembler()) { Inputs = &(*Inputs)[0]->getInputs(); - ToolForJob = &Compiler; + ToolForJob = Compiler; } } // Otherwise use the tool for the current job. if (!ToolForJob) - ToolForJob = &TC->SelectTool(C, *JA, *Inputs); + ToolForJob = TC->SelectTool(*JA); // See if we should use an integrated preprocessor. We do so when we have // exactly one input, since this is the only use case we care about @@ -1310,7 +1329,7 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC, ToolForJob->hasIntegratedCPP()) Inputs = &(*Inputs)[0]->getInputs(); - return *ToolForJob; + return ToolForJob; } void Driver::BuildJobsForAction(Compilation &C, @@ -1352,23 +1371,19 @@ void Driver::BuildJobsForAction(Compilation &C, const ActionList *Inputs = &A->getInputs(); const JobAction *JA = cast<JobAction>(A); - const Tool &T = SelectToolForJob(C, TC, JA, Inputs); + const Tool *T = SelectToolForJob(C, TC, JA, Inputs); + if (!T) + return; // Only use pipes when there is exactly one input. InputInfoList InputInfos; for (ActionList::const_iterator it = Inputs->begin(), ie = Inputs->end(); it != ie; ++it) { - // Treat dsymutil sub-jobs as being at the top-level too, they shouldn't get - // temporary output names. - // + // Treat dsymutil and verify sub-jobs as being at the top-level too, they + // shouldn't get temporary output names. // FIXME: Clean this up. bool SubJobAtTopLevel = false; - if (AtTopLevel && isa<DsymutilJobAction>(A)) - SubJobAtTopLevel = true; - - // Also treat verify sub-jobs as being at the top-level. They don't - // produce any output and so don't need temporary output names. - if (AtTopLevel && isa<VerifyJobAction>(A)) + if (AtTopLevel && (isa<DsymutilJobAction>(A) || isa<VerifyJobAction>(A))) SubJobAtTopLevel = true; InputInfo II; @@ -1386,16 +1401,15 @@ void Driver::BuildJobsForAction(Compilation &C, BaseInput = InputInfos[0].getFilename(); // Determine the place to write output to, if any. - if (JA->getType() == types::TY_Nothing) { + if (JA->getType() == types::TY_Nothing) Result = InputInfo(A->getType(), BaseInput); - } else { + else Result = InputInfo(GetNamedOutputPath(C, *JA, BaseInput, AtTopLevel), A->getType(), BaseInput); - } if (CCCPrintBindings && !CCGenDiagnostics) { - llvm::errs() << "# \"" << T.getToolChain().getTripleString() << '"' - << " - \"" << T.getName() << "\", inputs: ["; + llvm::errs() << "# \"" << T->getToolChain().getTripleString() << '"' + << " - \"" << T->getName() << "\", inputs: ["; for (unsigned i = 0, e = InputInfos.size(); i != e; ++i) { llvm::errs() << InputInfos[i].getAsString(); if (i + 1 != e) @@ -1403,8 +1417,8 @@ void Driver::BuildJobsForAction(Compilation &C, } llvm::errs() << "], output: " << Result.getAsString() << "\n"; } else { - T.ConstructJob(C, *JA, Result, InputInfos, - C.getArgsForToolChain(TC, BoundArch), LinkingOutput); + T->ConstructJob(C, *JA, Result, InputInfos, + C.getArgsForToolChain(TC, BoundArch), LinkingOutput); } } @@ -1417,11 +1431,12 @@ const char *Driver::GetNamedOutputPath(Compilation &C, if (AtTopLevel && !isa<DsymutilJobAction>(JA) && !isa<VerifyJobAction>(JA)) { if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) - return C.addResultFile(FinalOutput->getValue()); + return C.addResultFile(FinalOutput->getValue(), &JA); } // Default to writing to stdout? - if (AtTopLevel && isa<PreprocessJobAction>(JA) && !CCGenDiagnostics) + if (AtTopLevel && !CCGenDiagnostics && + (isa<PreprocessJobAction>(JA) || JA.getType() == types::TY_ModuleFile)) return "-"; // Output to a temporary file? @@ -1487,9 +1502,9 @@ const char *Driver::GetNamedOutputPath(Compilation &C, BasePath = NamedOutput; else llvm::sys::path::append(BasePath, NamedOutput); - return C.addResultFile(C.getArgs().MakeArgString(BasePath.c_str())); + return C.addResultFile(C.getArgs().MakeArgString(BasePath.c_str()), &JA); } else { - return C.addResultFile(NamedOutput); + return C.addResultFile(NamedOutput, &JA); } } @@ -1638,6 +1653,21 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, } } + // Handle pseudo-target flags '-EL' and '-EB'. + if (Arg *A = Args.getLastArg(options::OPT_EL, options::OPT_EB)) { + if (A->getOption().matches(options::OPT_EL)) { + if (Target.getArch() == llvm::Triple::mips) + Target.setArch(llvm::Triple::mipsel); + else if (Target.getArch() == llvm::Triple::mips64) + Target.setArch(llvm::Triple::mips64el); + } else { + if (Target.getArch() == llvm::Triple::mipsel) + Target.setArch(llvm::Triple::mips); + else if (Target.getArch() == llvm::Triple::mips64el) + Target.setArch(llvm::Triple::mips64); + } + } + // Skip further flag support on OSes which don't support '-m32' or '-m64'. if (Target.getArchName() == "tce" || Target.getOS() == llvm::Triple::AuroraUX || @@ -1681,7 +1711,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, Target.getArch() == llvm::Triple::x86_64 || Target.getArch() == llvm::Triple::arm || Target.getArch() == llvm::Triple::thumb) - TC = new toolchains::DarwinClang(*this, Target); + TC = new toolchains::DarwinClang(*this, Target, Args); else TC = new toolchains::Darwin_Generic_GCC(*this, Target, Args); break; @@ -1705,7 +1735,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, break; case llvm::Triple::Linux: if (Target.getArch() == llvm::Triple::hexagon) - TC = new toolchains::Hexagon_TC(*this, Target); + TC = new toolchains::Hexagon_TC(*this, Target, Args); else TC = new toolchains::Linux(*this, Target, Args); break; @@ -1713,17 +1743,21 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, TC = new toolchains::Solaris(*this, Target, Args); break; case llvm::Triple::Win32: - TC = new toolchains::Windows(*this, Target); + TC = new toolchains::Windows(*this, Target, Args); break; case llvm::Triple::MinGW32: // FIXME: We need a MinGW toolchain. Fallthrough for now. default: // TCE is an OSless target if (Target.getArchName() == "tce") { - TC = new toolchains::TCEToolChain(*this, Target); + TC = new toolchains::TCEToolChain(*this, Target, Args); + break; + } + // If Hexagon is configured as an OSless target + if (Target.getArch() == llvm::Triple::hexagon) { + TC = new toolchains::Hexagon_TC(*this, Target, Args); break; } - TC = new toolchains::Generic_GCC(*this, Target, Args); break; } @@ -1731,8 +1765,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, return *TC; } -bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA, - const llvm::Triple &Triple) const { +bool Driver::ShouldUseClangCompiler(const JobAction &JA) const { // Check if user requested no clang, or clang doesn't understand this type (we // only handle single inputs for now). if (JA.size() != 1 || diff --git a/contrib/llvm/tools/clang/lib/Driver/InputInfo.h b/contrib/llvm/tools/clang/lib/Driver/InputInfo.h index 2a2f4b9..a243d32 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 <cassert> #include <string> diff --git a/contrib/llvm/tools/clang/lib/Driver/Job.cpp b/contrib/llvm/tools/clang/lib/Driver/Job.cpp index 825c86a..8c46705 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Job.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Job.cpp @@ -8,9 +8,7 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Job.h" - #include "llvm/ADT/STLExtras.h" - #include <cassert> using namespace clang::driver; diff --git a/contrib/llvm/tools/clang/lib/Driver/OptTable.cpp b/contrib/llvm/tools/clang/lib/Driver/OptTable.cpp index 6e7b695..20214a6 100644 --- a/contrib/llvm/tools/clang/lib/Driver/OptTable.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/OptTable.cpp @@ -12,8 +12,8 @@ #include "clang/Driver/ArgList.h" #include "clang/Driver/Option.h" #include "clang/Driver/Options.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" #include <algorithm> #include <map> using namespace clang::driver; diff --git a/contrib/llvm/tools/clang/lib/Driver/Option.cpp b/contrib/llvm/tools/clang/lib/Driver/Option.cpp index 9a34df5..dbc61ea 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Option.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Option.cpp @@ -8,14 +8,13 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Option.h" - #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/ADT/Twine.h" -#include <cassert> +#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) diff --git a/contrib/llvm/tools/clang/lib/Driver/Phases.cpp b/contrib/llvm/tools/clang/lib/Driver/Phases.cpp index b885eee..155e53b 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Phases.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Phases.cpp @@ -9,7 +9,6 @@ #include "clang/Driver/Phases.h" #include "llvm/Support/ErrorHandling.h" - #include <cassert> using namespace clang::driver; diff --git a/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.h b/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.h index ecb396e..e61f15a 100644 --- a/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.h +++ b/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.h @@ -9,7 +9,13 @@ #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 { @@ -30,59 +36,151 @@ class SanitizerArgs { #include "clang/Basic/Sanitizers.def" NeedsAsanRt = Address, NeedsTsanRt = Thread, - NeedsUbsanRt = Undefined + NeedsMsanRt = Memory, + NeedsUbsanRt = Undefined | Integer, + NotAllowedWithTrap = Vptr }; unsigned Kind; + std::string BlacklistFile; + bool MsanTrackOrigins; + bool AsanZeroBaseShadow; + bool UbsanTrapOnError; public: - SanitizerArgs() : Kind(0) {} + SanitizerArgs() : Kind(0), BlacklistFile(""), MsanTrackOrigins(false), + AsanZeroBaseShadow(false), UbsanTrapOnError(false) {} /// Parses the sanitizer arguments from an argument list. SanitizerArgs(const Driver &D, const ArgList &Args); bool needsAsanRt() const { return Kind & NeedsAsanRt; } bool needsTsanRt() const { return Kind & NeedsTsanRt; } - bool needsUbsanRt() const { return Kind & NeedsUbsanRt; } + 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; } + void addArgs(const ArgList &Args, ArgStringList &CmdArgs) const { if (!Kind) return; - llvm::SmallString<256> SanitizeOpt("-fsanitize="); + 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 a member of the \c SanitizeKind enumeration, or \c 0 if \p Value - /// is not known. + /// Returns OR of members of the \c SanitizeKind enumeration, or \c 0 + /// if \p Value is not known. static unsigned parse(const char *Value) { - return llvm::StringSwitch<SanitizeKind>(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) { + 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 + 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 @@ -98,6 +196,18 @@ class SanitizerArgs { 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 diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp index de8ed1d..19270b2 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp @@ -7,8 +7,9 @@ // //===----------------------------------------------------------------------===// +#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" @@ -18,12 +19,12 @@ #include "clang/Driver/Options.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" -#include "clang/Basic/ObjCRuntime.h" using namespace clang::driver; using namespace clang; -ToolChain::ToolChain(const Driver &D, const llvm::Triple &T) - : D(D), Triple(T) { +ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, + const ArgList &A) + : D(D), Triple(T), Args(A) { } ToolChain::~ToolChain() { @@ -33,6 +34,12 @@ const Driver &ToolChain::getDriver() const { return D; } +bool ToolChain::useIntegratedAs() const { + return Args.hasFlag(options::OPT_integrated_as, + options::OPT_no_integrated_as, + IsIntegratedAssemblerDefault()); +} + 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 @@ -52,6 +59,73 @@ bool ToolChain::IsUnwindTablesDefault() const { return false; } +Tool *ToolChain::getClang() const { + if (!Clang) + Clang.reset(new tools::Clang(*this)); + return Clang.get(); +} + +Tool *ToolChain::buildAssembler() const { + return new tools::ClangAs(*this); +} + +Tool *ToolChain::buildLinker() const { + llvm_unreachable("Linking is not supported by this toolchain"); +} + +Tool *ToolChain::getAssemble() const { + if (!Assemble) + Assemble.reset(buildAssembler()); + return Assemble.get(); +} + +Tool *ToolChain::getClangAs() const { + if (!Assemble) + Assemble.reset(new tools::ClangAs(*this)); + return Assemble.get(); +} + +Tool *ToolChain::getLink() const { + if (!Link) + Link.reset(buildLinker()); + return Link.get(); +} + +Tool *ToolChain::getTool(Action::ActionClass AC) const { + switch (AC) { + case Action::AssembleJobClass: + return getAssemble(); + + case Action::LinkJobClass: + return getLink(); + + case Action::InputClass: + case Action::BindArchClass: + case Action::LipoJobClass: + case Action::DsymutilJobClass: + case Action::VerifyJobClass: + llvm_unreachable("Invalid tool kind."); + + case Action::CompileJobClass: + case Action::PrecompileJobClass: + case Action::PreprocessJobClass: + case Action::AnalyzeJobClass: + case Action::MigrateJobClass: + return getClang(); + } + + llvm_unreachable("Invalid tool kind."); +} + +Tool *ToolChain::SelectTool(const JobAction &JA) const { + if (getDriver().ShouldUseClangCompiler(JA)) + return getClang(); + Action::ActionClass AC = JA.getKind(); + if (AC == Action::AssembleJobClass && useIntegratedAs()) + return getClangAs(); + return getTool(AC); +} + std::string ToolChain::GetFilePath(const char *Name) const { return D.GetFilePath(Name, *this); @@ -110,15 +184,17 @@ static const char *getARMTargetCPU(const ArgList &Args, .Case("armv6j", "arm1136j-s") .Cases("armv6z", "armv6zk", "arm1176jzf-s") .Case("armv6t2", "arm1156t2-s") + .Cases("armv6m", "armv6-m", "cortex-m0") .Cases("armv7", "armv7a", "armv7-a", "cortex-a8") + .Cases("armv7l", "armv7-l", "cortex-a8") .Cases("armv7f", "armv7-f", "cortex-a9-mp") .Cases("armv7s", "armv7-s", "swift") .Cases("armv7r", "armv7-r", "cortex-r4") .Cases("armv7m", "armv7-m", "cortex-m3") + .Cases("armv7em", "armv7e-m", "cortex-m4") .Case("ep9312", "ep9312") .Case("iwmmxt", "iwmmxt") .Case("xscale", "xscale") - .Cases("armv6m", "armv6-m", "cortex-m0") // If all else failed, return the most base CPU LLVM supports. .Default("arm7tdmi"); } @@ -141,10 +217,12 @@ static const char *getLLVMArchSuffixForARM(StringRef CPU) { .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6") .Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6") .Cases("arm1156t2-s", "arm1156t2f-s", "v6t2") - .Cases("cortex-a8", "cortex-a9", "cortex-a15", "v7") - .Case("cortex-m3", "v7m") - .Case("cortex-m4", "v7m") + .Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7") + .Cases("cortex-a9", "cortex-a15", "v7") + .Case("cortex-r5", "v7r") .Case("cortex-m0", "v6m") + .Case("cortex-m3", "v7m") + .Case("cortex-m4", "v7em") .Case("cortex-a9-mp", "v7f") .Case("swift", "v7s") .Default(""); @@ -166,7 +244,8 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, // FIXME: Thumb should just be another -target-feaure, not in the triple. StringRef Suffix = getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple)); - bool ThumbDefault = (Suffix.startswith("v7") && getTriple().isOSDarwin()); + bool ThumbDefault = Suffix.startswith("v6m") || + (Suffix.startswith("v7") && getTriple().isOSDarwin()); std::string ArchName = "arm"; // Assembly files should start in ARM mode. @@ -197,7 +276,8 @@ void ToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // Each toolchain should provide the appropriate include flags. } -void ToolChain::addClangTargetOptions(ArgStringList &CC1Args) const { +void ToolChain::addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { } ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType( diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp index c5460b2..bcfe51e 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp @@ -8,7 +8,9 @@ //===----------------------------------------------------------------------===// #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" @@ -17,34 +19,31 @@ #include "clang/Driver/OptTable.h" #include "clang/Driver/Option.h" #include "clang/Driver/Options.h" -#include "clang/Basic/ObjCRuntime.h" -#include "clang/Basic/Version.h" - +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" -#include "SanitizerArgs.h" +// FIXME: This needs to be listed last until we fix the broken include guards +// in these files and the LLVM config.h files. +#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX #include <cstdlib> // ::getenv -#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX - using namespace clang::driver; using namespace clang::driver::toolchains; using namespace clang; /// Darwin - Darwin tool chain for i386 and x86_64. -Darwin::Darwin(const Driver &D, const llvm::Triple& Triple) - : ToolChain(D, Triple), TargetInitialized(false) +Darwin::Darwin(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) + : ToolChain(D, Triple, Args), TargetInitialized(false) { // Compute the initial Darwin version from the triple unsigned Major, Minor, Micro; @@ -100,15 +99,17 @@ bool Darwin::hasBlocksRuntime() const { static const char *GetArmArchForMArch(StringRef Value) { return llvm::StringSwitch<const char*>(Value) .Case("armv6k", "armv6") + .Case("armv6m", "armv6m") .Case("armv5tej", "armv5") .Case("xscale", "xscale") .Case("armv4t", "armv4t") .Case("armv7", "armv7") .Cases("armv7a", "armv7-a", "armv7") .Cases("armv7r", "armv7-r", "armv7") - .Cases("armv7m", "armv7-m", "armv7") + .Cases("armv7em", "armv7e-m", "armv7em") .Cases("armv7f", "armv7-f", "armv7f") .Cases("armv7k", "armv7-k", "armv7k") + .Cases("armv7m", "armv7-m", "armv7m") .Cases("armv7s", "armv7-s", "armv7s") .Default(0); } @@ -119,11 +120,12 @@ static const char *GetArmArchForMCpu(StringRef Value) { .Cases("arm10e", "arm10tdmi", "armv5") .Cases("arm1020t", "arm1020e", "arm1022e", "arm1026ej-s", "armv5") .Case("xscale", "xscale") - .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", - "arm1176jzf-s", "cortex-m0", "armv6") - .Cases("cortex-a8", "cortex-r4", "cortex-m3", "cortex-a9", "cortex-a15", - "armv7") + .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "arm1176jzf-s", "armv6") + .Case("cortex-m0", "armv6m") + .Cases("cortex-a8", "cortex-r4", "cortex-a9", "cortex-a15", "armv7") .Case("cortex-a9-mp", "armv7f") + .Case("cortex-m3", "armv7m") + .Case("cortex-m4", "armv7em") .Case("swift", "armv7s") .Default(0); } @@ -149,10 +151,6 @@ StringRef Darwin::getDarwinArchName(const ArgList &Args) const { } Darwin::~Darwin() { - // Free tool implementations. - for (llvm::DenseMap<unsigned, Tool*>::iterator - it = Tools.begin(), ie = Tools.end(); it != ie; ++it) - delete it->second; } std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, @@ -174,57 +172,36 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, void Generic_ELF::anchor() {} -Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key = JA.getKind(); - - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) { - // FIXME: This seems like a hacky way to choose clang frontend. - Key = Action::AnalyzeJobClass; - } - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::InputClass: - case Action::BindArchClass: - llvm_unreachable("Invalid tool kind."); - case Action::PreprocessJobClass: - T = new tools::darwin::Preprocess(*this); break; - case Action::AnalyzeJobClass: - case Action::MigrateJobClass: - T = new tools::Clang(*this); break; - case Action::PrecompileJobClass: - case Action::CompileJobClass: - T = new tools::darwin::Compile(*this); break; - case Action::AssembleJobClass: { - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::darwin::Assemble(*this); - break; - } - case Action::LinkJobClass: - T = new tools::darwin::Link(*this); break; - case Action::LipoJobClass: - T = new tools::darwin::Lipo(*this); break; - case Action::DsymutilJobClass: - T = new tools::darwin::Dsymutil(*this); break; - case Action::VerifyJobClass: - T = new tools::darwin::VerifyDebug(*this); break; - } +Tool *Darwin::getTool(Action::ActionClass AC) const { + switch (AC) { + case Action::LipoJobClass: + if (!Lipo) + Lipo.reset(new tools::darwin::Lipo(*this)); + return Lipo.get(); + case Action::DsymutilJobClass: + if (!Dsymutil) + Dsymutil.reset(new tools::darwin::Dsymutil(*this)); + return Dsymutil.get(); + case Action::VerifyJobClass: + if (!VerifyDebug) + VerifyDebug.reset(new tools::darwin::VerifyDebug(*this)); + return VerifyDebug.get(); + default: + return ToolChain::getTool(AC); } +} - return *T; +Tool *Darwin::buildLinker() const { + return new tools::darwin::Link(*this); } +Tool *Darwin::buildAssembler() const { + return new tools::darwin::Assemble(*this); +} -DarwinClang::DarwinClang(const Driver &D, const llvm::Triple& Triple) - : Darwin(D, Triple) +DarwinClang::DarwinClang(const Driver &D, const llvm::Triple& Triple, + const ArgList &Args) + : Darwin(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) @@ -261,16 +238,18 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args, void DarwinClang::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, - const char *DarwinStaticLib) const { + const char *DarwinStaticLib, + bool AlwaysLink) const { llvm::sys::Path P(getDriver().ResourceDir); P.appendComponent("lib"); P.appendComponent("darwin"); P.appendComponent(DarwinStaticLib); // For now, allow missing resource libraries to support developers who may - // not have compiler-rt checked out or integrated into their build. + // not have compiler-rt checked out or integrated into their build (unless + // we explicitly force linking with this library). bool Exists; - if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) + if (AlwaysLink || (!llvm::sys::fs::exists(P.str(), Exists) && Exists)) CmdArgs.push_back(Args.MakeArgString(P.str())); } @@ -317,21 +296,35 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, SanitizerArgs Sanitize(getDriver(), Args); + // Add Ubsan runtime library, if required. + if (Sanitize.needsUbsanRt()) { + if (isTargetIPhoneOS()) { + getDriver().Diag(diag::err_drv_clang_unsupported_per_platform) + << "-fsanitize=undefined"; + } else { + AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ubsan_osx.a", true); + + // The Ubsan runtime library requires C++. + AddCXXStdlibLibArgs(Args, CmdArgs); + } + } + // Add ASAN runtime library, if required. Dynamic libraries and bundles // should not be linked with the runtime library. if (Sanitize.needsAsanRt()) { - if (Args.hasArg(options::OPT_dynamiclib) || - Args.hasArg(options::OPT_bundle)) return; - if (isTargetIPhoneOS()) { + if (isTargetIPhoneOS() && !isTargetIOSSimulator()) { getDriver().Diag(diag::err_drv_clang_unsupported_per_platform) << "-fsanitize=address"; } else { - AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.asan_osx.a"); - - // The ASAN runtime library requires C++ and CoreFoundation. - AddCXXStdlibLibArgs(Args, CmdArgs); - CmdArgs.push_back("-framework"); - CmdArgs.push_back("CoreFoundation"); + 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); + // The ASAN runtime library requires C++. + AddCXXStdlibLibArgs(Args, CmdArgs); + } } } @@ -381,11 +374,17 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { // Support allowing the SDKROOT environment variable used by xcrun and other // Xcode tools to define the default sysroot, by making it the default for // isysroot. - if (!Args.hasArg(options::OPT_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) + getDriver().Diag(clang::diag::warn_missing_sysroot) << A->getValue(); + } else { if (char *env = ::getenv("SDKROOT")) { - // We only use this value as the default if it is an absolute path and - // exists. - if (llvm::sys::path::is_absolute(env) && llvm::sys::fs::exists(env)) { + // We only use this value as the default if it is an absolute path, + // exists, and it is not the root path. + if (llvm::sys::path::is_absolute(env) && llvm::sys::fs::exists(env) && + StringRef(env) != "/") { Args.append(Args.MakeSeparateArg( 0, Opts.getOption(options::OPT_isysroot), env)); } @@ -796,12 +795,18 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, DAL->AddJoinedArg(0, MArch, "xscale"); else if (Name == "armv6") DAL->AddJoinedArg(0, MArch, "armv6k"); + else if (Name == "armv6m") + DAL->AddJoinedArg(0, MArch, "armv6m"); else if (Name == "armv7") DAL->AddJoinedArg(0, MArch, "armv7a"); + else if (Name == "armv7em") + DAL->AddJoinedArg(0, MArch, "armv7em"); else if (Name == "armv7f") DAL->AddJoinedArg(0, MArch, "armv7f"); else if (Name == "armv7k") DAL->AddJoinedArg(0, MArch, "armv7k"); + else if (Name == "armv7m") + DAL->AddJoinedArg(0, MArch, "armv7m"); else if (Name == "armv7s") DAL->AddJoinedArg(0, MArch, "armv7s"); @@ -931,7 +936,7 @@ Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) { // And retains any patch number it finds. StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str(); if (!PatchText.empty()) { - if (unsigned EndNumber = PatchText.find_first_not_of("0123456789")) { + if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) { // Try to parse the number and any suffix. if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) || GoodVersion.Patch < 0) @@ -945,20 +950,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 true; if (Major > RHS.Major) return false; - if (Minor < RHS.Minor) return true; if (Minor > RHS.Minor) return false; - - // Note that we rank versions with *no* patch specified is better than ones - // hard-coding a patch version. Thus if the RHS has no patch, it always - // wins, and the LHS only wins if it has no patch and the RHS does have - // a patch. - if (RHS.Patch == -1) return true; if (Patch == -1) return false; - if (Patch < RHS.Patch) return true; if (Patch > RHS.Patch) return false; - if (PatchSuffix == RHS.PatchSuffix) return false; - - // Finally, between completely tied version numbers, the version with the - // suffix loses as we prefer full releases. - if (RHS.PatchSuffix.empty()) return true; + if (Major != RHS.Major) + return Major < RHS.Major; + if (Minor != RHS.Minor) + return Minor < RHS.Minor; + if (Patch != RHS.Patch) { + // Note that versions without a specified patch sort higher than those with + // a patch. + if (RHS.Patch == -1) + return true; + if (Patch == -1) + return false; + + // Otherwise just sort on the patch itself. + return Patch < RHS.Patch; + } + if (PatchSuffix != RHS.PatchSuffix) { + // Sort empty suffixes higher. + if (RHS.PatchSuffix.empty()) + return true; + if (PatchSuffix.empty()) + return false; + + // Provide a lexicographic sort to make this a total ordering. + return PatchSuffix < RHS.PatchSuffix; + } + + // The versions are equal. return false; } @@ -1051,6 +1069,12 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( // 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 ARMLibDirs[] = { "/lib" }; static const char *const ARMTriples[] = { "arm-linux-gnueabi", @@ -1078,6 +1102,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( "i686-pc-linux-gnu", "i486-linux-gnu", "i386-linux-gnu", + "i386-redhat-linux6E", "i686-redhat-linux", "i586-redhat-linux", "i386-redhat-linux", @@ -1103,6 +1128,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( static const char *const PPCTriples[] = { "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", + "powerpc-linux-gnuspe", "powerpc-suse-linux", "powerpc-montavista-linuxspe" }; @@ -1115,6 +1141,16 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( }; 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)); + break; case llvm::Triple::arm: case llvm::Triple::thumb: LibDirs.append(ARMLibDirs, ARMLibDirs + llvm::array_lengthof(ARMLibDirs)); @@ -1316,60 +1352,40 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) - : ToolChain(D, Triple), GCCInstallation(getDriver(), Triple, Args) { + : ToolChain(D, Triple, Args), GCCInstallation(getDriver(), Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); } Generic_GCC::~Generic_GCC() { - // Free tool implementations. - for (llvm::DenseMap<unsigned, Tool*>::iterator - it = Tools.begin(), ie = Tools.end(); it != ie; ++it) - delete it->second; -} - -Tool &Generic_GCC::SelectTool(const Compilation &C, - const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::InputClass: - case Action::BindArchClass: - llvm_unreachable("Invalid tool kind."); - case Action::PreprocessJobClass: - T = new tools::gcc::Preprocess(*this); break; - case Action::PrecompileJobClass: - T = new tools::gcc::Precompile(*this); break; - case Action::AnalyzeJobClass: - case Action::MigrateJobClass: - T = new tools::Clang(*this); break; - case Action::CompileJobClass: - T = new tools::gcc::Compile(*this); break; - case Action::AssembleJobClass: - T = new tools::gcc::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::gcc::Link(*this); break; - - // This is a bit ungeneric, but the only platform using a driver - // driver is Darwin. - case Action::LipoJobClass: - T = new tools::darwin::Lipo(*this); break; - case Action::DsymutilJobClass: - T = new tools::darwin::Dsymutil(*this); break; - case Action::VerifyJobClass: - T = new tools::darwin::VerifyDebug(*this); break; - } +} + +Tool *Generic_GCC::getTool(Action::ActionClass AC) const { + switch (AC) { + case Action::PreprocessJobClass: + if (!Preprocess) + Preprocess.reset(new tools::gcc::Preprocess(*this)); + return Preprocess.get(); + case Action::PrecompileJobClass: + if (!Precompile) + Precompile.reset(new tools::gcc::Precompile(*this)); + return Precompile.get(); + case Action::CompileJobClass: + if (!Compile) + Compile.reset(new tools::gcc::Compile(*this)); + return Compile.get(); + default: + return ToolChain::getTool(AC); } +} + +Tool *Generic_GCC::buildAssembler() const { + return new tools::gcc::Assemble(*this); +} - return *T; +Tool *Generic_GCC::buildLinker() const { + return new tools::gcc::Link(*this); } bool Generic_GCC::IsUnwindTablesDefault() const { @@ -1386,71 +1402,216 @@ bool Generic_GCC::isPICDefaultForced() const { /// Hexagon Toolchain -Hexagon_TC::Hexagon_TC(const Driver &D, const llvm::Triple& Triple) - : ToolChain(D, Triple) { - getProgramPaths().push_back(getDriver().getInstalledDir()); - if (getDriver().getInstalledDir() != getDriver().Dir.c_str()) - getProgramPaths().push_back(getDriver().Dir); +std::string Hexagon_TC::GetGnuDir(const std::string &InstalledDir) { + + // Locate the rest of the toolchain ... + if (strlen(GCC_INSTALL_PREFIX)) + return std::string(GCC_INSTALL_PREFIX); + + std::string InstallRelDir = InstalledDir + "/../../gnu"; + if (llvm::sys::fs::exists(InstallRelDir)) + return InstallRelDir; + + std::string PrefixRelDir = std::string(LLVM_PREFIX) + "/../gnu"; + if (llvm::sys::fs::exists(PrefixRelDir)) + return PrefixRelDir; + + return InstallRelDir; +} + +static void GetHexagonLibraryPaths( + const ArgList &Args, + const std::string Ver, + const std::string MarchString, + const std::string &InstalledDir, + ToolChain::path_list *LibPaths) +{ + bool buildingLib = Args.hasArg(options::OPT_shared); + + //---------------------------------------------------------------------------- + // -L Args + //---------------------------------------------------------------------------- + for (arg_iterator + it = Args.filtered_begin(options::OPT_L), + ie = Args.filtered_end(); + it != ie; + ++it) { + for (unsigned i = 0, e = (*it)->getNumValues(); i != e; ++i) + LibPaths->push_back((*it)->getValue(i)); + } + + //---------------------------------------------------------------------------- + // Other standard paths + //---------------------------------------------------------------------------- + const std::string MarchSuffix = "/" + MarchString; + const std::string G0Suffix = "/G0"; + const std::string MarchG0Suffix = MarchSuffix + G0Suffix; + const std::string RootDir = Hexagon_TC::GetGnuDir(InstalledDir) + "/"; + + // lib/gcc/hexagon/... + std::string LibGCCHexagonDir = RootDir + "lib/gcc/hexagon/"; + if (buildingLib) { + LibPaths->push_back(LibGCCHexagonDir + Ver + MarchG0Suffix); + LibPaths->push_back(LibGCCHexagonDir + Ver + G0Suffix); + } + LibPaths->push_back(LibGCCHexagonDir + Ver + MarchSuffix); + LibPaths->push_back(LibGCCHexagonDir + Ver); + + // lib/gcc/... + LibPaths->push_back(RootDir + "lib/gcc"); + + // hexagon/lib/... + std::string HexagonLibDir = RootDir + "hexagon/lib"; + if (buildingLib) { + LibPaths->push_back(HexagonLibDir + MarchG0Suffix); + LibPaths->push_back(HexagonLibDir + G0Suffix); + } + LibPaths->push_back(HexagonLibDir + MarchSuffix); + LibPaths->push_back(HexagonLibDir); +} + +Hexagon_TC::Hexagon_TC(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Linux(D, Triple, Args) { + const std::string InstalledDir(getDriver().getInstalledDir()); + const std::string GnuDir = Hexagon_TC::GetGnuDir(InstalledDir); + + // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to + // program paths + const std::string BinDir(GnuDir + "/bin"); + if (llvm::sys::fs::exists(BinDir)) + getProgramPaths().push_back(BinDir); + + // Determine version of GCC libraries and headers to use. + const std::string HexagonDir(GnuDir + "/lib/gcc/hexagon"); + llvm::error_code ec; + GCCVersion MaxVersion= GCCVersion::Parse("0.0.0"); + for (llvm::sys::fs::directory_iterator di(HexagonDir, ec), de; + !ec && di != de; di = di.increment(ec)) { + GCCVersion cv = GCCVersion::Parse(llvm::sys::path::filename(di->path())); + if (MaxVersion < cv) + MaxVersion = cv; + } + GCCLibAndIncVersion = MaxVersion; + + ToolChain::path_list *LibPaths= &getFilePaths(); + + // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets + // 'elf' OS type, so the Linux paths are not appropriate. When we actually + // support 'linux' we'll need to fix this up + LibPaths->clear(); + + GetHexagonLibraryPaths( + Args, + GetGCCLibAndIncVersion(), + GetTargetCPU(Args), + InstalledDir, + LibPaths); } Hexagon_TC::~Hexagon_TC() { - // Free tool implementations. - for (llvm::DenseMap<unsigned, Tool*>::iterator - it = Tools.begin(), ie = Tools.end(); it != ie; ++it) - delete it->second; -} - -Tool &Hexagon_TC::SelectTool(const Compilation &C, - const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - // if (JA.getKind () == Action::CompileJobClass) - // Key = JA.getKind (); - // else - - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - // if ((JA.getKind () == Action::CompileJobClass) - // && (JA.getType () != types::TY_LTO_BC)) { - // Key = JA.getKind (); - // } - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::InputClass: - case Action::BindArchClass: - assert(0 && "Invalid tool kind."); - case Action::AnalyzeJobClass: - T = new tools::Clang(*this); break; - case Action::AssembleJobClass: - T = new tools::hexagon::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::hexagon::Link(*this); break; - default: - assert(false && "Unsupported action for Hexagon target."); - } +} + +Tool *Hexagon_TC::buildAssembler() const { + return new tools::hexagon::Assemble(*this); +} + +Tool *Hexagon_TC::buildLinker() const { + return new tools::hexagon::Link(*this); +} + +void Hexagon_TC::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + + if (DriverArgs.hasArg(options::OPT_nostdinc) || + 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); + addExternCSystemInclude(DriverArgs, CC1Args, HexagonDir + "/include"); + addExternCSystemInclude(DriverArgs, CC1Args, HexagonDir + "/include-fixed"); + addExternCSystemInclude(DriverArgs, CC1Args, GnuDir + "/hexagon/include"); +} + +void Hexagon_TC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + const Driver &D = getDriver(); + std::string Ver(GetGCCLibAndIncVersion()); + llvm::sys::Path IncludeDir(Hexagon_TC::GetGnuDir(D.InstalledDir)); + + IncludeDir.appendComponent("hexagon/include/c++/"); + IncludeDir.appendComponent(Ver); + addSystemInclude(DriverArgs, CC1Args, IncludeDir.str()); +} + +ToolChain::CXXStdlibType +Hexagon_TC::GetCXXStdlibType(const ArgList &Args) const { + Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); + if (!A) + return ToolChain::CST_Libstdcxx; + + StringRef Value = A->getValue(); + if (Value != "libstdc++") { + getDriver().Diag(diag::err_drv_invalid_stdlib_name) + << A->getAsString(Args); } - return *T; + return ToolChain::CST_Libstdcxx; } -bool Hexagon_TC::isPICDefault() const { - return false; +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(); + } + } + } + return A; } -bool Hexagon_TC::isPICDefaultForced() const { - return false; +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; + } + + return "v4"; } +// End Hexagon /// TCEToolChain - A tool chain using the llvm bitcode tools to perform /// all subcommands. See http://tce.cs.tut.fi for our peculiar target. /// Currently does not support anything else but compilation. -TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple& Triple) - : ToolChain(D, Triple) { +TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple& Triple, + const ArgList &Args) + : ToolChain(D, Triple, Args) { // Path mangling to find libexec std::string Path(getDriver().Dir); @@ -1459,9 +1620,6 @@ TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple& Triple) } TCEToolChain::~TCEToolChain() { - for (llvm::DenseMap<unsigned, Tool*>::iterator - it = Tools.begin(), ie = Tools.end(); it != ie; ++it) - delete it->second; } bool TCEToolChain::IsMathErrnoDefault() const { @@ -1476,26 +1634,6 @@ bool TCEToolChain::isPICDefaultForced() const { return false; } -Tool &TCEToolChain::SelectTool(const Compilation &C, - const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - Key = Action::AnalyzeJobClass; - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::PreprocessJobClass: - T = new tools::gcc::Preprocess(*this); break; - case Action::AnalyzeJobClass: - T = new tools::Clang(*this); break; - default: - llvm_unreachable("Unsupported action for TCE target."); - } - } - return *T; -} - /// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly. OpenBSD::OpenBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) @@ -1504,36 +1642,12 @@ OpenBSD::OpenBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Arg getFilePaths().push_back("/usr/lib"); } -Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: { - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::openbsd::Assemble(*this); - break; - } - case Action::LinkJobClass: - T = new tools::openbsd::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *OpenBSD::buildAssembler() const { + return new tools::openbsd::Assemble(*this); +} - return *T; +Tool *OpenBSD::buildLinker() const { + return new tools::openbsd::Link(*this); } /// Bitrig - Bitrig tool chain which can call as(1) and ld(1) directly. @@ -1544,36 +1658,12 @@ Bitrig::Bitrig(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) getFilePaths().push_back("/usr/lib"); } -Tool &Bitrig::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: { - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::bitrig::Assemble(*this); - break; - } - case Action::LinkJobClass: - T = new tools::bitrig::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *Bitrig::buildAssembler() const { + return new tools::bitrig::Assemble(*this); +} - return *T; +Tool *Bitrig::buildLinker() const { + return new tools::bitrig::Link(*this); } void Bitrig::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, @@ -1636,35 +1726,12 @@ FreeBSD::FreeBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Arg getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); } -Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::freebsd::Assemble(*this); - break; - case Action::LinkJobClass: - T = new tools::freebsd::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *FreeBSD::buildAssembler() const { + return new tools::freebsd::Assemble(*this); +} - return *T; +Tool *FreeBSD::buildLinker() const { + return new tools::freebsd::Link(*this); } bool FreeBSD::UseSjLjExceptions() const { @@ -1698,36 +1765,12 @@ NetBSD::NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) } } -Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::netbsd::Assemble(*this); - break; - case Action::LinkJobClass: - T = new tools::netbsd::Link(*this); - break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *NetBSD::buildAssembler() const { + return new tools::netbsd::Assemble(*this); +} - return *T; +Tool *NetBSD::buildLinker() const { + return new tools::netbsd::Link(*this); } /// Minix - Minix tool chain which can call as(1) and ld(1) directly. @@ -1738,27 +1781,12 @@ Minix::Minix(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) getFilePaths().push_back("/usr/lib"); } -Tool &Minix::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - T = new tools::minix::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::minix::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *Minix::buildAssembler() const { + return new tools::minix::Assemble(*this); +} - return *T; +Tool *Minix::buildLinker() const { + return new tools::minix::Link(*this); } /// AuroraUX - AuroraUX tool chain which can call as(1) and ld(1) directly. @@ -1779,27 +1807,12 @@ AuroraUX::AuroraUX(const Driver &D, const llvm::Triple& Triple, } -Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - T = new tools::auroraux::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::auroraux::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *AuroraUX::buildAssembler() const { + return new tools::auroraux::Assemble(*this); +} - return *T; +Tool *AuroraUX::buildLinker() const { + return new tools::auroraux::Link(*this); } /// Solaris - Solaris tool chain which can call as(1) and ld(1) directly. @@ -1816,36 +1829,22 @@ Solaris::Solaris(const Driver &D, const llvm::Triple& Triple, getFilePaths().push_back("/usr/lib"); } -Tool &Solaris::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - T = new tools::solaris::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::solaris::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *Solaris::buildAssembler() const { + return new tools::solaris::Assemble(*this); +} - return *T; +Tool *Solaris::buildLinker() const { + return new tools::solaris::Link(*this); } -/// Linux toolchain (very bare-bones at the moment). +/// Distribution (very bare-bones at the moment). -enum LinuxDistro { +enum Distro { ArchLinux, DebianLenny, DebianSqueeze, DebianWheezy, + DebianJessie, Exherbo, RHEL4, RHEL5, @@ -1873,33 +1872,33 @@ enum LinuxDistro { UnknownDistro }; -static bool IsRedhat(enum LinuxDistro Distro) { +static bool IsRedhat(enum Distro Distro) { return (Distro >= Fedora13 && Distro <= FedoraRawhide) || (Distro >= RHEL4 && Distro <= RHEL6); } -static bool IsOpenSuse(enum LinuxDistro Distro) { +static bool IsOpenSuse(enum Distro Distro) { return Distro >= OpenSuse11_3 && Distro <= OpenSuse12_2; } -static bool IsDebian(enum LinuxDistro Distro) { - return Distro >= DebianLenny && Distro <= DebianWheezy; +static bool IsDebian(enum Distro Distro) { + return Distro >= DebianLenny && Distro <= DebianJessie; } -static bool IsUbuntu(enum LinuxDistro Distro) { +static bool IsUbuntu(enum Distro Distro) { return Distro >= UbuntuHardy && Distro <= UbuntuRaring; } -static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { +static Distro DetectDistro(llvm::Triple::ArchType Arch) { OwningPtr<llvm::MemoryBuffer> File; if (!llvm::MemoryBuffer::getFile("/etc/lsb-release", File)) { StringRef Data = File.get()->getBuffer(); SmallVector<StringRef, 8> Lines; Data.split(Lines, "\n"); - LinuxDistro Version = UnknownDistro; + Distro Version = UnknownDistro; for (unsigned i = 0, s = Lines.size(); i != s; ++i) if (Version == UnknownDistro && Lines[i].startswith("DISTRIB_CODENAME=")) - Version = llvm::StringSwitch<LinuxDistro>(Lines[i].substr(17)) + Version = llvm::StringSwitch<Distro>(Lines[i].substr(17)) .Case("hardy", UbuntuHardy) .Case("intrepid", UbuntuIntrepid) .Case("jaunty", UbuntuJaunty) @@ -1932,11 +1931,11 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { Data.find("release 6") != StringRef::npos) return RHEL6; else if ((Data.startswith("Red Hat Enterprise Linux") || - Data.startswith("CentOS")) && + Data.startswith("CentOS")) && Data.find("release 5") != StringRef::npos) return RHEL5; else if ((Data.startswith("Red Hat Enterprise Linux") || - Data.startswith("CentOS")) && + Data.startswith("CentOS")) && Data.find("release 4") != StringRef::npos) return RHEL4; return UnknownDistro; @@ -1950,11 +1949,13 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { return DebianSqueeze; else if (Data.startswith("wheezy/sid") || Data[0] == '7') return DebianWheezy; + else if (Data.startswith("jessie/sid") || Data[0] == '8') + return DebianJessie; return UnknownDistro; } if (!llvm::MemoryBuffer::getFile("/etc/SuSE-release", File)) - return llvm::StringSwitch<LinuxDistro>(File.get()->getBuffer()) + 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) @@ -2007,6 +2008,9 @@ static std::string getMultiarchTriple(const llvm::Triple TargetTriple, if (llvm::sys::fs::exists(SysRoot + "/lib/x86_64-linux-gnu")) return "x86_64-linux-gnu"; return TargetTriple.str(); + case llvm::Triple::aarch64: + if (llvm::sys::fs::exists(SysRoot + "/lib/aarch64-linux-gnu")) + return "aarch64-linux-gnu"; case llvm::Triple::mips: if (llvm::sys::fs::exists(SysRoot + "/lib/mips-linux-gnu")) return "mips-linux-gnu"; @@ -2016,6 +2020,8 @@ static std::string getMultiarchTriple(const llvm::Triple TargetTriple, return "mipsel-linux-gnu"; return TargetTriple.str(); case llvm::Triple::ppc: + if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnuspe")) + return "powerpc-linux-gnuspe"; if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnu")) return "powerpc-linux-gnu"; return TargetTriple.str(); @@ -2083,7 +2089,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) Linker = GetProgramPath("ld"); - LinuxDistro Distro = DetectLinuxDistro(Arch); + Distro Distro = DetectDistro(Arch); if (IsOpenSuse(Distro) || IsUbuntu(Distro)) { ExtraOpts.push_back("-z"); @@ -2114,7 +2120,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) ExtraOpts.push_back("--no-add-needed"); if (Distro == DebianSqueeze || Distro == DebianWheezy || - IsOpenSuse(Distro) || + Distro == DebianJessie || IsOpenSuse(Distro) || (IsRedhat(Distro) && Distro != RHEL4 && Distro != RHEL5) || (IsUbuntu(Distro) && Distro >= UbuntuKarmic)) ExtraOpts.push_back("--build-id"); @@ -2197,40 +2203,24 @@ bool Linux::HasNativeLLVMSupport() const { return true; } -Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::linuxtools::Assemble(*this); - break; - case Action::LinkJobClass: - T = new tools::linuxtools::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *Linux::buildLinker() const { + return new tools::gnutools::Link(*this); +} - return *T; +Tool *Linux::buildAssembler() const { + return new tools::gnutools::Assemble(*this); } -void Linux::addClangTargetOptions(ArgStringList &CC1Args) const { +void Linux::addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion(); - if (V >= Generic_GCC::GCCVersion::Parse("4.7.0")) + bool UseInitArrayDefault + = V >= Generic_GCC::GCCVersion::Parse("4.7.0") || + getTriple().getArch() == llvm::Triple::aarch64 || + getTriple().getEnvironment() == llvm::Triple::Android; + if (DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, + UseInitArrayDefault)) CC1Args.push_back("-fuse-init-array"); } @@ -2289,6 +2279,9 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, "/usr/include/i686-linux-gnu", "/usr/include/i486-linux-gnu" }; + const StringRef AArch64MultiarchIncludeDirs[] = { + "/usr/include/aarch64-linux-gnu" + }; const StringRef ARMMultiarchIncludeDirs[] = { "/usr/include/arm-linux-gnueabi" }; @@ -2312,6 +2305,8 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, MultiarchIncludeDirs = X86_64MultiarchIncludeDirs; } else if (getTriple().getArch() == llvm::Triple::x86) { MultiarchIncludeDirs = X86MultiarchIncludeDirs; + } else if (getTriple().getArch() == llvm::Triple::aarch64) { + MultiarchIncludeDirs = AArch64MultiarchIncludeDirs; } else if (getTriple().getArch() == llvm::Triple::arm) { if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF) MultiarchIncludeDirs = ARMHFMultiarchIncludeDirs; @@ -2346,7 +2341,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include"); } -/// \brief Helper to add the thre variant paths for a libstdc++ installation. +/// \brief Helper to add the three variant paths for a libstdc++ installation. /*static*/ bool Linux::addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir, const ArgList &DriverArgs, ArgStringList &CC1Args) { @@ -2358,6 +2353,22 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, return true; } +/// \brief Helper to add an extra variant path for an (Ubuntu) multilib +/// libstdc++ installation. +/*static*/ bool Linux::addLibStdCXXIncludePaths(Twine Base, Twine Suffix, + Twine TargetArchDir, + Twine MultiLibSuffix, + const ArgList &DriverArgs, + ArgStringList &CC1Args) { + if (!addLibStdCXXIncludePaths(Base+Suffix, TargetArchDir + MultiLibSuffix, + DriverArgs, CC1Args)) + return false; + + addSystemInclude(DriverArgs, CC1Args, Base + "/" + TargetArchDir + Suffix + + MultiLibSuffix); + return true; +} + void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) || @@ -2385,8 +2396,14 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, StringRef Version = GCCInstallation.getVersion().Text; StringRef TripleStr = GCCInstallation.getTriple().str(); + if (addLibStdCXXIncludePaths(LibDir.str() + "/../include", + "/c++/" + Version.str(), + TripleStr, + GCCInstallation.getMultiarchSuffix(), + DriverArgs, CC1Args)) + return; + const std::string IncludePathCandidates[] = { - LibDir.str() + "/../include/c++/" + Version.str(), // 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", @@ -2420,25 +2437,10 @@ DragonFly::DragonFly(const Driver &D, const llvm::Triple& Triple, const ArgList getFilePaths().push_back("/usr/lib/gcc41"); } -Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - T = new tools::dragonfly::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::dragonfly::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *DragonFly::buildAssembler() const { + return new tools::dragonfly::Assemble(*this); +} - return *T; +Tool *DragonFly::buildLinker() const { + return new tools::dragonfly::Link(*this); } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains.h index 6f0ca83..3421c53 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains.h @@ -10,15 +10,13 @@ #ifndef CLANG_LIB_DRIVER_TOOLCHAINS_H_ #define CLANG_LIB_DRIVER_TOOLCHAINS_H_ +#include "Tools.h" +#include "clang/Basic/VersionTuple.h" #include "clang/Driver/Action.h" #include "clang/Driver/ToolChain.h" - -#include "clang/Basic/VersionTuple.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/Compiler.h" -#include "Tools.h" - namespace clang { namespace driver { namespace toolchains { @@ -119,20 +117,19 @@ protected: GCCInstallationDetector GCCInstallation; - mutable llvm::DenseMap<unsigned, Tool*> Tools; - public: Generic_GCC(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); ~Generic_GCC(); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; - virtual bool IsUnwindTablesDefault() const; virtual bool isPICDefault() const; virtual bool isPICDefaultForced() const; protected: + virtual Tool *getTool(Action::ActionClass AC) const; + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; + /// \name ToolChain Implementation Helper Functions /// @{ @@ -143,21 +140,11 @@ protected: bool isTarget32Bit() const { return getTriple().isArch32Bit(); } /// @} -}; - -class LLVM_LIBRARY_VISIBILITY Hexagon_TC : public ToolChain { -protected: - mutable llvm::DenseMap<unsigned, Tool*> Tools; - -public: - Hexagon_TC(const Driver &D, const llvm::Triple& Triple); - ~Hexagon_TC(); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; - - virtual bool isPICDefault() const; - virtual bool isPICDefaultForced() const; +private: + mutable OwningPtr<tools::gcc::Preprocess> Preprocess; + mutable OwningPtr<tools::gcc::Precompile> Precompile; + mutable OwningPtr<tools::gcc::Compile> Compile; }; /// Darwin - The base Darwin tool chain. @@ -166,8 +153,15 @@ public: /// The host version. unsigned DarwinVersion[3]; +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; + virtual Tool *getTool(Action::ActionClass AC) const; + private: - mutable llvm::DenseMap<unsigned, Tool*> Tools; + mutable OwningPtr<tools::darwin::Lipo> Lipo; + mutable OwningPtr<tools::darwin::Dsymutil> Dsymutil; + mutable OwningPtr<tools::darwin::VerifyDebug> VerifyDebug; /// Whether the information on the target has been initialized. // @@ -198,7 +192,7 @@ private: void AddDeploymentTarget(DerivedArgList &Args) const; public: - Darwin(const Driver &D, const llvm::Triple& Triple); + Darwin(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); ~Darwin(); std::string ComputeEffectiveClangTriple(const ArgList &Args, @@ -286,9 +280,6 @@ public: virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args, const char *BoundArch) const; - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; - virtual bool IsBlocksDefault() const { // Always allow blocks on Darwin; users interested in versioning are // expected to use /usr/include/Blocks.h. @@ -314,10 +305,6 @@ public: return false; } - virtual bool IsObjCDefaultSynthPropertiesDefault() const { - return true; - } - virtual bool IsEncodeExtendedBlockSignatureDefault() const { return true; } @@ -363,16 +350,17 @@ public: /// DarwinClang - The Darwin toolchain used by Clang. class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin { public: - DarwinClang(const Driver &D, const llvm::Triple& Triple); + DarwinClang(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); /// @name Darwin ToolChain Implementation /// { virtual void AddLinkRuntimeLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const; - void AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, - const char *DarwinStaticLib) const; - + void AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, + const char *DarwinStaticLib, + bool AlwaysLink = false) const; + virtual void AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const; @@ -393,7 +381,7 @@ public: std::string ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const; - virtual bool isPICDefault() const { return false; }; + virtual bool isPICDefault() const { return false; } }; class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC { @@ -404,7 +392,8 @@ public: virtual bool IsIntegratedAssemblerDefault() const { // Default integrated assembler to on for x86. - return (getTriple().getArch() == llvm::Triple::x86 || + return (getTriple().getArch() == llvm::Triple::aarch64 || + getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64); } }; @@ -413,18 +402,20 @@ class LLVM_LIBRARY_VISIBILITY AuroraUX : public Generic_GCC { public: AuroraUX(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; }; class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_GCC { public: Solaris(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; - virtual bool IsIntegratedAssemblerDefault() const { return true; } +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; + }; @@ -435,8 +426,9 @@ public: virtual bool IsMathErrnoDefault() const { return false; } virtual bool IsObjCNonFragileABIDefault() const { return true; } - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; }; class LLVM_LIBRARY_VISIBILITY Bitrig : public Generic_ELF { @@ -447,9 +439,6 @@ public: virtual bool IsObjCNonFragileABIDefault() const { return true; } virtual bool IsObjCLegacyDispatchDefault() const { return false; } - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; - virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const; virtual void AddCXXStdlibLibArgs(const ArgList &Args, @@ -457,6 +446,10 @@ public: virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const { return 1; } + +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; }; class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF { @@ -466,9 +459,10 @@ public: virtual bool IsMathErrnoDefault() const { return false; } virtual bool IsObjCNonFragileABIDefault() const { return true; } - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; virtual bool UseSjLjExceptions() const; +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; }; class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF { @@ -478,16 +472,18 @@ public: virtual bool IsMathErrnoDefault() const { return false; } virtual bool IsObjCNonFragileABIDefault() const { return true; } - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; }; class LLVM_LIBRARY_VISIBILITY Minix : public Generic_ELF { public: Minix(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; }; class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_ELF { @@ -496,8 +492,9 @@ public: virtual bool IsMathErrnoDefault() const { return false; } - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; }; class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF { @@ -506,55 +503,71 @@ public: virtual bool HasNativeLLVMSupport() const; - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; - virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const; - virtual void addClangTargetOptions(ArgStringList &CC1Args) const; + virtual void addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args) const; virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const; std::string Linker; std::vector<std::string> ExtraOpts; +protected: + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; + private: + static bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, + Twine TargetArchDir, + Twine MultiLibSuffix, + const ArgList &DriverArgs, + ArgStringList &CC1Args); static bool addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir, const ArgList &DriverArgs, ArgStringList &CC1Args); }; +class LLVM_LIBRARY_VISIBILITY Hexagon_TC : public Linux { +protected: + GCCVersion GCCLibAndIncVersion; + virtual Tool *buildAssembler() const; + virtual Tool *buildLinker() const; + +public: + Hexagon_TC(const Driver &D, const llvm::Triple &Triple, + const 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; + + StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; } + + static std::string GetGnuDir(const std::string &InstalledDir); + + static StringRef GetTargetCPU(const 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); + TCEToolChain(const Driver &D, const llvm::Triple& Triple, + const ArgList &Args); ~TCEToolChain(); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; bool IsMathErrnoDefault() const; bool isPICDefault() const; bool isPICDefaultForced() const; - -private: - mutable llvm::DenseMap<unsigned, Tool*> Tools; - }; class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain { - mutable llvm::DenseMap<unsigned, Tool*> Tools; - public: - Windows(const Driver &D, const llvm::Triple& Triple); - - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const; - - virtual bool IsObjCDefaultSynthPropertiesDefault() const { - return true; - } + Windows(const Driver &D, const llvm::Triple& Triple, const ArgList &Args); virtual bool IsIntegratedAssemblerDefault() const; virtual bool IsUnwindTablesDefault() const; @@ -565,7 +578,9 @@ public: ArgStringList &CC1Args) const; virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const; - +protected: + virtual Tool *buildLinker() const; + virtual Tool *buildAssembler() const; }; } // end namespace toolchains diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp index 5739fa1..294b791 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp @@ -8,33 +8,31 @@ //===----------------------------------------------------------------------===// #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/Compilation.h" #include "clang/Driver/Job.h" #include "clang/Driver/Option.h" #include "clang/Driver/Options.h" #include "clang/Driver/ToolChain.h" #include "clang/Driver/Util.h" -#include "clang/Basic/ObjCRuntime.h" - #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Host.h" #include "llvm/Support/Process.h" -#include "llvm/Support/ErrorHandling.h" - -#include "InputInfo.h" -#include "SanitizerArgs.h" -#include "ToolChains.h" +#include "llvm/Support/raw_ostream.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -230,6 +228,7 @@ static bool forwardToGCC(const Option &O) { } void Clang::AddPreprocessingOptions(Compilation &C, + const JobAction &JA, const Driver &D, const ArgList &Args, ArgStringList &CmdArgs, @@ -250,15 +249,15 @@ void Clang::AddPreprocessingOptions(Compilation &C, const char *DepFile; if (Arg *MF = Args.getLastArg(options::OPT_MF)) { DepFile = MF->getValue(); - C.addFailureResultFile(DepFile); + C.addFailureResultFile(DepFile, &JA); } else if (Output.getType() == types::TY_Dependencies) { DepFile = Output.getFilename(); } else if (A->getOption().matches(options::OPT_M) || A->getOption().matches(options::OPT_MM)) { DepFile = "-"; } else { - DepFile = darwin::CC1::getDependencyFileName(Args, Inputs); - C.addFailureResultFile(DepFile); + DepFile = getDependencyFileName(Args, Inputs); + C.addFailureResultFile(DepFile, &JA); } CmdArgs.push_back("-dependency-file"); CmdArgs.push_back(DepFile); @@ -415,21 +414,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, CmdArgs.push_back(C.getArgs().MakeArgString(sysroot)); } } - - // If a module path was provided, pass it along. Otherwise, use a temporary - // directory. - if (Arg *A = Args.getLastArg(options::OPT_fmodule_cache_path)) { - A->claim(); - A->render(Args, CmdArgs); - } else { - SmallString<128> DefaultModuleCache; - llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, - DefaultModuleCache); - llvm::sys::path::append(DefaultModuleCache, "clang-module-cache"); - CmdArgs.push_back("-fmodule-cache-path"); - CmdArgs.push_back(Args.MakeArgString(DefaultModuleCache)); - } - + // Parse additional include paths from environment variables. // FIXME: We should probably sink the logic for handling these from the // frontend into the driver. It will allow deleting 4 otherwise unused flags. @@ -471,10 +456,12 @@ static const char *getLLVMArchSuffixForARM(StringRef CPU) { .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6") .Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6") .Cases("arm1156t2-s", "arm1156t2f-s", "v6t2") - .Cases("cortex-a8", "cortex-a9", "cortex-a15", "v7") - .Case("cortex-m3", "v7m") - .Case("cortex-m4", "v7m") + .Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7") + .Cases("cortex-a9", "cortex-a15", "v7") + .Case("cortex-r5", "v7r") .Case("cortex-m0", "v6m") + .Case("cortex-m3", "v7m") + .Case("cortex-m4", "v7em") .Case("cortex-a9-mp", "v7f") .Case("swift", "v7s") .Default(""); @@ -530,7 +517,9 @@ static std::string getARMTargetCPU(const ArgList &Args, .Case("armv6j", "arm1136j-s") .Cases("armv6z", "armv6zk", "arm1176jzf-s") .Case("armv6t2", "arm1156t2-s") + .Cases("armv6m", "armv6-m", "cortex-m0") .Cases("armv7", "armv7a", "armv7-a", "cortex-a8") + .Cases("armv7em", "armv7e-m", "cortex-m4") .Cases("armv7f", "armv7-f", "cortex-a9-mp") .Cases("armv7s", "armv7-s", "swift") .Cases("armv7r", "armv7-r", "cortex-r4") @@ -538,7 +527,6 @@ static std::string getARMTargetCPU(const ArgList &Args, .Case("ep9312", "ep9312") .Case("iwmmxt", "iwmmxt") .Case("xscale", "xscale") - .Cases("armv6m", "armv6-m", "cortex-m0") // If all else failed, return the most base CPU LLVM supports. .Default("arm7tdmi"); } @@ -549,6 +537,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) { default: return true; + case llvm::Triple::aarch64: case llvm::Triple::arm: case llvm::Triple::ppc: case llvm::Triple::ppc64: @@ -609,8 +598,9 @@ static void addFPMathArgs(const Driver &D, const Arg *A, const ArgList &Args, CmdArgs.push_back("-target-feature"); CmdArgs.push_back("+neonfp"); - if (CPU != "cortex-a8" && CPU != "cortex-a9" && CPU != "cortex-a9-mp" && - CPU != "cortex-a15") + 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" || @@ -883,8 +873,8 @@ static void getMipsCPUAndABI(const ArgList &Args, if (!ABIName.empty()) { // Deduce CPU name from ABI name. CPUName = llvm::StringSwitch<const char *>(ABIName) - .Cases("o32", "eabi", DefMips32CPU) - .Cases("n32", "n64", DefMips64CPU) + .Cases("32", "o32", "eabi", DefMips32CPU) + .Cases("n32", "n64", "64", DefMips64CPU) .Default(""); } else if (!CPUName.empty()) { @@ -898,6 +888,14 @@ static void getMipsCPUAndABI(const ArgList &Args, // FIXME: Warn on inconsistent cpu and abi usage. } +// Convert ABI name to the GNU tools acceptable variant. +static StringRef getGnuCompatibleMipsABIName(StringRef ABI) { + return llvm::StringSwitch<llvm::StringRef>(ABI) + .Case("o32", "32") + .Case("n64", "64") + .Default(ABI); +} + // Select the MIPS float ABI as determined by -msoft-float, -mhard-float, // and -mfloat-abi=. static StringRef getMipsFloatABI(const Driver &D, const ArgList &Args) { @@ -960,7 +958,9 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, StringRef FloatABI = getMipsFloatABI(D, Args); - if (FloatABI == "soft") { + bool IsMips16 = Args.getLastArg(options::OPT_mips16) != NULL; + + if (FloatABI == "soft" || (FloatABI == "hard" && IsMips16)) { // Floating point operations and argument passing are soft. CmdArgs.push_back("-msoft-float"); CmdArgs.push_back("-mfloat-abi"); @@ -971,6 +971,11 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, // 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"); + } } else if (FloatABI == "single") { // Restrict the use of hardware floating-point @@ -995,6 +1000,13 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, 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"); + CmdArgs.push_back("-mxgot"); + } + } + if (Arg *A = Args.getLastArg(options::OPT_G)) { StringRef v = A->getValue(); CmdArgs.push_back("-mllvm"); @@ -1029,6 +1041,7 @@ static std::string getPPCTargetCPU(const ArgList &Args) { .Case("604", "604") .Case("604e", "604e") .Case("620", "620") + .Case("630", "pwr3") .Case("G3", "g3") .Case("7400", "7400") .Case("G4", "g4") @@ -1038,10 +1051,23 @@ static std::string getPPCTargetCPU(const ArgList &Args) { .Case("970", "970") .Case("G5", "g5") .Case("a2", "a2") + .Case("a2q", "a2q") .Case("e500mc", "e500mc") .Case("e5500", "e5500") + .Case("power3", "pwr3") + .Case("power4", "pwr4") + .Case("power5", "pwr5") + .Case("power5x", "pwr5x") .Case("power6", "pwr6") + .Case("power6x", "pwr6x") .Case("power7", "pwr7") + .Case("pwr3", "pwr3") + .Case("pwr4", "pwr4") + .Case("pwr5", "pwr5") + .Case("pwr5x", "pwr5x") + .Case("pwr6", "pwr6") + .Case("pwr6x", "pwr6x") + .Case("pwr7", "pwr7") .Case("powerpc", "ppc") .Case("powerpc64", "ppc64") .Default(""); @@ -1069,6 +1095,55 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, 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"); + + AddTargetFeature(Args, CmdArgs, + options::OPT_mfprnd, options::OPT_mno_fprnd, + "fprnd"); + + // Note that gcc calls this mfcrf and LLVM calls this mfocrf. + AddTargetFeature(Args, CmdArgs, + options::OPT_mmfcrf, options::OPT_mno_mfcrf, + "mfocrf"); + + AddTargetFeature(Args, CmdArgs, + options::OPT_mpopcntd, options::OPT_mno_popcntd, + "popcntd"); + + // 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"); + } +} + +/// 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(); + return llvm::StringSwitch<const char *>(GPUName) + .Cases("rv610", "rv620", "rv630", "r600") + .Cases("rv635", "rs780", "rs880", "r600") + .Case("rv740", "rv770") + .Case("palm", "cedar") + .Cases("sumo", "sumo2", "redwood") + .Case("hemlock", "cypress") + .Case("aruba", "cayman") + .Default(GPUName.c_str()); + } + 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())); } void Clang::AddSparcTargetArgs(const ArgList &Args, @@ -1174,9 +1249,18 @@ void Clang::AddX86TargetArgs(const ArgList &Args, Args.hasArg(options::OPT_fapple_kext)) CmdArgs.push_back("-disable-red-zone"); - if (Args.hasFlag(options::OPT_msoft_float, - options::OPT_mno_soft_float, - false)) + // Default to avoid implicit floating-point for kernel/kext code, but allow + // that to be overridden with -mno-soft-float. + bool NoImplicitFloat = (Args.hasArg(options::OPT_mkernel) || + Args.hasArg(options::OPT_fapple_kext)); + if (Arg *A = Args.getLastArg(options::OPT_msoft_float, + options::OPT_mno_soft_float, + options::OPT_mno_implicit_float)) { + const Option &O = A->getOption(); + NoImplicitFloat = (O.matches(options::OPT_mno_implicit_float) || + O.matches(options::OPT_msoft_float)); + } + if (NoImplicitFloat) CmdArgs.push_back("-no-implicit-float"); if (const char *CPUName = getX86TargetCPU(Args, getToolChain().getTriple())) { @@ -1219,43 +1303,26 @@ void Clang::AddX86TargetArgs(const ArgList &Args, } } -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(); - } - } - } - return A; +static inline bool HasPICArg(const ArgList &Args) { + return Args.hasArg(options::OPT_fPIC) + || Args.hasArg(options::OPT_fpic); } -static StringRef getHexagonTargetCPU(const ArgList &Args) -{ - Arg *A; - llvm::StringRef WhichHexagon; +static Arg *GetLastSmallDataThresholdArg(const ArgList &Args) { + return Args.getLastArg(options::OPT_G, + options::OPT_G_EQ, + options::OPT_msmall_data_threshold_EQ); +} - // Select the default CPU (v4) if none was given or detection failed. - if ((A = getLastHexagonArchArg (Args))) { - WhichHexagon = A->getValue(); - if (WhichHexagon == "") - return "v4"; - else - return WhichHexagon; +static std::string GetHexagonSmallDataThresholdValue(const ArgList &Args) { + std::string value; + if (HasPICArg(Args)) + value = "0"; + else if (Arg *A = GetLastSmallDataThresholdArg(Args)) { + value = A->getValue(); + A->claim(); } - else - return "v4"; + return value; } void Clang::AddHexagonTargetArgs(const ArgList &Args, @@ -1263,20 +1330,18 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args, llvm::Triple Triple = getToolChain().getTriple(); CmdArgs.push_back("-target-cpu"); - CmdArgs.push_back(Args.MakeArgString("hexagon" + getHexagonTargetCPU(Args))); + CmdArgs.push_back(Args.MakeArgString( + "hexagon" + + toolchains::Hexagon_TC::GetTargetCPU(Args))); CmdArgs.push_back("-fno-signed-char"); - CmdArgs.push_back("-nobuiltininc"); - - if (Args.hasArg(options::OPT_mqdsp6_compat)) - CmdArgs.push_back("-mqdsp6-compat"); + CmdArgs.push_back("-mqdsp6-compat"); + CmdArgs.push_back("-Wreturn-type"); - if (Arg *A = Args.getLastArg(options::OPT_G, - options::OPT_msmall_data_threshold_EQ)) { - std::string SmallDataThreshold="-small-data-threshold="; - SmallDataThreshold += A->getValue(); + std::string SmallDataThreshold = GetHexagonSmallDataThresholdValue(Args); + if (!SmallDataThreshold.empty()) { CmdArgs.push_back ("-mllvm"); - CmdArgs.push_back(Args.MakeArgString(SmallDataThreshold)); - A->claim(); + CmdArgs.push_back(Args.MakeArgString( + "-hexagon-small-data-threshold=" + SmallDataThreshold)); } if (!Args.hasArg(options::OPT_fno_short_enums)) @@ -1393,24 +1458,18 @@ static bool ShouldDisableCFI(const ArgList &Args, if (TC.getTriple().isOSDarwin()) { // The native darwin assembler doesn't support cfi directives, so // we disable them if we think the .s file will be passed to it. - Default = Args.hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - TC.IsIntegratedAssemblerDefault()); + Default = TC.useIntegratedAs(); } return !Args.hasFlag(options::OPT_fdwarf2_cfi_asm, - options::OPT_fno_dwarf2_cfi_asm, - Default); + options::OPT_fno_dwarf2_cfi_asm, + Default); } static bool ShouldDisableDwarfDirectory(const ArgList &Args, const ToolChain &TC) { - bool IsIADefault = TC.IsIntegratedAssemblerDefault(); - bool UseIntegratedAs = Args.hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIADefault); bool UseDwarfDirectory = Args.hasFlag(options::OPT_fdwarf_directory_asm, options::OPT_fno_dwarf_directory_asm, - UseIntegratedAs); + TC.useIntegratedAs()); return !UseDwarfDirectory; } @@ -1449,63 +1508,147 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) { RelaxDefault); } -SanitizerArgs::SanitizerArgs(const Driver &D, const ArgList &Args) { - Kind = 0; - - const Arg *AsanArg, *TsanArg, *UbsanArg; +SanitizerArgs::SanitizerArgs(const Driver &D, 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). for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) { - unsigned Add = 0, Remove = 0; - const char *DeprecatedReplacement = 0; - if ((*I)->getOption().matches(options::OPT_faddress_sanitizer)) { - Add = Address; - DeprecatedReplacement = "-fsanitize=address"; - } else if ((*I)->getOption().matches(options::OPT_fno_address_sanitizer)) { - Remove = Address; - DeprecatedReplacement = "-fno-sanitize=address"; - } else if ((*I)->getOption().matches(options::OPT_fthread_sanitizer)) { - Add = Thread; - DeprecatedReplacement = "-fsanitize=thread"; - } else if ((*I)->getOption().matches(options::OPT_fno_thread_sanitizer)) { - Remove = Thread; - DeprecatedReplacement = "-fno-sanitize=thread"; - } else if ((*I)->getOption().matches(options::OPT_fcatch_undefined_behavior)) { - Add = Undefined; - DeprecatedReplacement = "-fsanitize=undefined"; - } else if ((*I)->getOption().matches(options::OPT_fsanitize_EQ)) { - Add = parse(D, *I); - } else if ((*I)->getOption().matches(options::OPT_fno_sanitize_EQ)) { - Remove = parse(D, *I); - } else { + unsigned Add, Remove; + if (!parse(D, Args, *I, Add, Remove, true)) continue; - } - (*I)->claim(); - Kind |= Add; Kind &= ~Remove; + AllKinds |= Add; + } - if (Add & NeedsAsanRt) AsanArg = *I; - if (Add & NeedsTsanRt) TsanArg = *I; - if (Add & NeedsUbsanRt) UbsanArg = *I; + 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 this is a deprecated synonym, produce a warning directing users - // towards the new spelling. - if (DeprecatedReplacement) - D.Diag(diag::warn_drv_deprecated_arg) - << (*I)->getAsString(Args) << DeprecatedReplacement; + 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. - // FIXME: Allow Ubsan to be combined with the other two. bool NeedsAsan = needsAsanRt(); bool NeedsTsan = needsTsanRt(); - bool NeedsUbsan = needsUbsanRt(); - if (NeedsAsan + NeedsTsan + NeedsUbsan > 1) + bool NeedsMsan = needsMsanRt(); + if (NeedsAsan && NeedsTsan) D.Diag(diag::err_drv_argument_not_allowed_with) - << describeSanitizeArg(Args, NeedsAsan ? AsanArg : TsanArg, - NeedsAsan ? NeedsAsanRt : NeedsTsanRt) - << describeSanitizeArg(Args, NeedsUbsan ? UbsanArg : TsanArg, - NeedsUbsan ? NeedsUbsanRt : NeedsTsanRt); + << 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) + AsanZeroBaseShadow = + Args.hasFlag(options::OPT_fsanitize_address_zero_base_shadow, + options::OPT_fno_sanitize_address_zero_base_shadow, + /* Default */false); +} + +static void addSanitizerRTLinkFlagsLinux( + const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, + const StringRef Sanitizer, bool BeforeLibStdCXX, + bool ExportSymbols = true) { + // Sanitizer runtime is located in the Linux library directory and + // has name "libclang_rt.<Sanitizer>-<ArchName>.a". + SmallString<128> LibSanitizer(TC.getDriver().ResourceDir); + llvm::sys::path::append( + LibSanitizer, "lib", "linux", + (Twine("libclang_rt.") + Sanitizer + "-" + TC.getArchName() + ".a")); + + // Sanitizer runtime may need to come before -lstdc++ (or -lc++, libstdc++.a, + // etc.) so that the linker picks custom versions of the global 'operator + // new' and 'operator delete' symbols. We take the extreme (but simple) + // strategy of inserting it at the front of the link command. It also + // needs to be forced to end up in the executable, so wrap it in + // whole-archive. + SmallVector<const char *, 3> LibSanitizerArgs; + LibSanitizerArgs.push_back("-whole-archive"); + LibSanitizerArgs.push_back(Args.MakeArgString(LibSanitizer)); + LibSanitizerArgs.push_back("-no-whole-archive"); + + CmdArgs.insert(BeforeLibStdCXX ? CmdArgs.begin() : CmdArgs.end(), + LibSanitizerArgs.begin(), LibSanitizerArgs.end()); + + CmdArgs.push_back("-lpthread"); + CmdArgs.push_back("-ldl"); + + // 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 + // all symbols from the binary. + if (ExportSymbols) { + if (llvm::sys::fs::exists(LibSanitizer + ".syms")) + CmdArgs.push_back( + Args.MakeArgString("--dynamic-list=" + LibSanitizer + ".syms")); + else + CmdArgs.push_back("-export-dynamic"); + } } /// If AddressSanitizer is enabled, add appropriate linker flags (Linux). @@ -1522,19 +1665,17 @@ static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args, llvm::sys::path::append(LibAsan, "lib", "linux", (Twine("libclang_rt.asan-") + TC.getArchName() + "-android.so")); - CmdArgs.push_back(Args.MakeArgString(LibAsan)); + CmdArgs.insert(CmdArgs.begin(), Args.MakeArgString(LibAsan)); } else { if (!Args.hasArg(options::OPT_shared)) { - // LibAsan is "libclang_rt.asan-<ArchName>.a" in the Linux library - // resource directory. - SmallString<128> LibAsan(TC.getDriver().ResourceDir); - llvm::sys::path::append(LibAsan, "lib", "linux", - (Twine("libclang_rt.asan-") + - TC.getArchName() + ".a")); - CmdArgs.push_back(Args.MakeArgString(LibAsan)); - CmdArgs.push_back("-lpthread"); - CmdArgs.push_back("-ldl"); - CmdArgs.push_back("-export-dynamic"); + bool ZeroBaseShadow = Args.hasFlag( + options::OPT_fsanitize_address_zero_base_shadow, + options::OPT_fno_sanitize_address_zero_base_shadow, false); + if (ZeroBaseShadow && !Args.hasArg(options::OPT_pie)) { + TC.getDriver().Diag(diag::err_drv_argument_only_allowed_with) << + "-fsanitize-address-zero-base-shadow" << "-pie"; + } + addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "asan", true); } } } @@ -1544,33 +1685,44 @@ static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args, static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { if (!Args.hasArg(options::OPT_shared)) { - // LibTsan is "libclang_rt.tsan-<ArchName>.a" in the Linux library - // resource directory. - SmallString<128> LibTsan(TC.getDriver().ResourceDir); - llvm::sys::path::append(LibTsan, "lib", "linux", - (Twine("libclang_rt.tsan-") + - TC.getArchName() + ".a")); - CmdArgs.push_back(Args.MakeArgString(LibTsan)); - CmdArgs.push_back("-lpthread"); - CmdArgs.push_back("-ldl"); - CmdArgs.push_back("-export-dynamic"); + if (!Args.hasArg(options::OPT_pie)) + TC.getDriver().Diag(diag::err_drv_argument_only_allowed_with) << + "-fsanitize=thread" << "-pie"; + 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_pie)) + TC.getDriver().Diag(diag::err_drv_argument_only_allowed_with) << + "-fsanitize=memory" << "-pie"; + addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "msan", true); } } /// If UndefinedBehaviorSanitizer is enabled, add appropriate linker flags /// (Linux). static void addUbsanRTLinux(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { - if (!Args.hasArg(options::OPT_shared)) { - // LibUbsan is "libclang_rt.ubsan-<ArchName>.a" in the Linux library - // resource directory. - SmallString<128> LibUbsan(TC.getDriver().ResourceDir); - llvm::sys::path::append(LibUbsan, "lib", "linux", - (Twine("libclang_rt.ubsan-") + - TC.getArchName() + ".a")); - CmdArgs.push_back(Args.MakeArgString(LibUbsan)); - CmdArgs.push_back("-lpthread"); - } + 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) + addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "san", true, false); + + addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "ubsan", false); + + // Only include the bits of the runtime which need a C++ ABI library if + // we're linking in C++ mode. + if (IsCXX) + addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "ubsan_cxx", false); } static bool shouldUseFramePointer(const ArgList &Args, @@ -1591,6 +1743,80 @@ static bool shouldUseFramePointer(const ArgList &Args, return true; } +static bool shouldUseLeafFramePointer(const ArgList &Args, + const llvm::Triple &Triple) { + if (Arg *A = Args.getLastArg(options::OPT_mno_omit_leaf_frame_pointer, + 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; +} + +/// If the PWD environment variable is set, add a CC1 option to specify the +/// debug compilation directory. +static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs) { + if (const char *pwd = ::getenv("PWD")) { + // GCC also verifies that stat(pwd) and stat(".") have the same inode + // number. Not doing those because stats are slow, but we could. + if (llvm::sys::path::is_absolute(pwd)) { + std::string CompDir = pwd; + CmdArgs.push_back("-fdebug-compilation-dir"); + CmdArgs.push_back(Args.MakeArgString(CompDir)); + } + } +} + +static const char *SplitDebugName(const ArgList &Args, + const InputInfoList &Inputs) { + Arg *FinalOutput = Args.getLastArg(options::OPT_o); + if (FinalOutput && Args.hasArg(options::OPT_c)) { + SmallString<128> T(FinalOutput->getValue()); + llvm::sys::path::replace_extension(T, "dwo"); + return Args.MakeArgString(T); + } else { + // Use the compilation dir. + SmallString<128> T(Args.getLastArgValue(options::OPT_fdebug_compilation_dir)); + SmallString<128> F(llvm::sys::path::stem(Inputs[0].getBaseInput())); + llvm::sys::path::replace_extension(F, "dwo"); + T += F; + return Args.MakeArgString(F); + } +} + +static void SplitDebugInfo(const ToolChain &TC, Compilation &C, + const Tool &T, const JobAction &JA, + const ArgList &Args, const InputInfo &Output, + const char *OutFile) { + ArgStringList ExtractArgs; + ExtractArgs.push_back("--extract-dwo"); + + ArgStringList StripArgs; + StripArgs.push_back("--strip-dwo"); + + // Grabbing the output of the earlier compile step. + StripArgs.push_back(Output.getFilename()); + ExtractArgs.push_back(Output.getFilename()); + ExtractArgs.push_back(OutFile); + + const char *Exec = + Args.MakeArgString(TC.GetProgramPath("objcopy")); + + // First extract the dwo sections. + C.addCommand(new Command(JA, T, Exec, ExtractArgs)); + + // Then remove them from the original .o file. + C.addCommand(new Command(JA, T, Exec, StripArgs)); +} + void Clang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -1624,8 +1850,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } else if (isa<PreprocessJobAction>(JA)) { if (Output.getType() == types::TY_Dependencies) CmdArgs.push_back("-Eonly"); - else + else { CmdArgs.push_back("-E"); + if (Args.hasArg(options::OPT_rewrite_objc) && + !Args.hasArg(options::OPT_g_Group)) + CmdArgs.push_back("-P"); + } } else if (isa<AssembleJobAction>(JA)) { CmdArgs.push_back("-emit-obj"); @@ -1686,6 +1916,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-S"); } else if (JA.getType() == types::TY_AST) { CmdArgs.push_back("-emit-pch"); + } else if (JA.getType() == types::TY_ModuleFile) { + CmdArgs.push_back("-module-file-info"); } else if (JA.getType() == types::TY_RewrittenObjC) { CmdArgs.push_back("-rewrite-objc"); rewriteKind = RK_NonFragile; @@ -1709,10 +1941,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Set the main file name, so that debug info works even with // -save-temps. CmdArgs.push_back("-main-file-name"); - CmdArgs.push_back(darwin::CC1::getBaseInputName(Args, Inputs)); + CmdArgs.push_back(getBaseInputName(Args, Inputs)); // Some flags which affect the language (via preprocessor - // defines). See darwin::CC1::AddCPPArgs. + // defines). if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("-static-define"); @@ -1808,8 +2040,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Note that these flags are trump-cards. Regardless of the order w.r.t. the // PIC or PIE options above, if these show up, PIC is disabled. llvm::Triple Triple(TripleStr); - if ((Args.hasArg(options::OPT_mkernel) || - Args.hasArg(options::OPT_fapple_kext)) && + if (KernelOrKext && (Triple.getOS() != llvm::Triple::IOS || Triple.isOSVersionLT(6))) PIC = PIE = false; @@ -1874,6 +2105,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_strict_aliasing, getToolChain().IsStrictAliasingDefault())) CmdArgs.push_back("-relaxed-aliasing"); + if (Args.hasArg(options::OPT_fstruct_path_tbaa)) + CmdArgs.push_back("-struct-path-tbaa"); if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums, false)) CmdArgs.push_back("-fstrict-enums"); @@ -1881,6 +2114,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_optimize_sibling_calls)) CmdArgs.push_back("-mdisable-tail-calls"); + // Handle segmented stacks. + if (Args.hasArg(options::OPT_fsplit_stack)) + CmdArgs.push_back("-split-stacks"); + // Handle various floating point optimization flags, mapping them to the // appropriate LLVM code generation flags. The pattern for all of these is to // default off the codegen optimizations, and if any flag enables them and no @@ -2043,7 +2280,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, AsynchronousUnwindTables)) CmdArgs.push_back("-munwind-tables"); - getToolChain().addClangTargetOptions(CmdArgs); + getToolChain().addClangTargetOptions(Args, CmdArgs); if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); @@ -2080,6 +2317,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, AddPPCTargetArgs(Args, CmdArgs); break; + case llvm::Triple::r600: + AddR600TargetArgs(Args, CmdArgs); + break; + case llvm::Triple::sparc: AddSparcTargetArgs(Args, CmdArgs); break; @@ -2102,10 +2343,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } - // -mno-omit-leaf-frame-pointer is the default on Darwin. - if (Args.hasFlag(options::OPT_momit_leaf_frame_pointer, - options::OPT_mno_omit_leaf_frame_pointer, - !getToolChain().getTriple().isOSDarwin())) + if (!shouldUseLeafFramePointer(Args, getToolChain().getTriple())) CmdArgs.push_back("-momit-leaf-frame-pointer"); // Explicitly error on some things we know we don't support and can't just @@ -2139,16 +2377,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, D.CCLogDiagnosticsFilename : "-"); } - // Use the last option from "-g" group. "-gline-tables-only" is - // preserved, all other debug options are substituted with "-g". + // Use the last option from "-g" group. "-gline-tables-only" + // is preserved, all other debug options are substituted with "-g". Args.ClaimAllArgs(options::OPT_g_Group); if (Arg *A = Args.getLastArg(options::OPT_g_Group)) { - if (A->getOption().matches(options::OPT_gline_tables_only)) { + if (A->getOption().matches(options::OPT_gline_tables_only)) CmdArgs.push_back("-gline-tables-only"); - } else if (!A->getOption().matches(options::OPT_g0) && - !A->getOption().matches(options::OPT_ggdb0)) { + else if (!A->getOption().matches(options::OPT_g0) && + !A->getOption().matches(options::OPT_ggdb0)) CmdArgs.push_back("-g"); - } } // We ignore flags -gstrict-dwarf and -grecord-gcc-switches for now. @@ -2156,6 +2393,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_gcolumn_info)) CmdArgs.push_back("-dwarf-column-info"); + // -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 && + Args.hasArg(options::OPT_gsplit_dwarf)) { + CmdArgs.push_back("-g"); + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-split-dwarf=Enable"); + } + Args.AddAllArgs(CmdArgs, options::OPT_ffunction_sections); Args.AddAllArgs(CmdArgs, options::OPT_fdata_sections); @@ -2172,9 +2419,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, C.getArgs().hasArg(options::OPT_S)) { if (Output.isFilename()) { CmdArgs.push_back("-coverage-file"); - SmallString<128> absFilename(Output.getFilename()); - llvm::sys::fs::make_absolute(absFilename); - CmdArgs.push_back(Args.MakeArgString(absFilename)); + 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); + } + } + } + CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); } } @@ -2246,7 +2501,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // // FIXME: Support -fpreprocessed if (types::getPreprocessedType(InputType) != types::TY_INVALID) - AddPreprocessingOptions(C, D, Args, CmdArgs, Output, Inputs); + AddPreprocessingOptions(C, JA, D, Args, CmdArgs, Output, Inputs); // Don't warn about "clang -c -DPIC -fPIC test.i" because libtool.m4 assumes // that "The compiler can only warn and ignore the option if not recognized". @@ -2266,6 +2521,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->render(Args, CmdArgs); } + // Don't warn about unused -flto. This can happen when we're preprocessing or + // precompiling. + Args.ClaimAllArgs(options::OPT_flto); + Args.AddAllArgs(CmdArgs, options::OPT_W_Group); if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false)) CmdArgs.push_back("-pedantic"); @@ -2338,15 +2597,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (ShouldDisableDwarfDirectory(Args, getToolChain())) CmdArgs.push_back("-fno-dwarf-directory-asm"); - if (const char *pwd = ::getenv("PWD")) { - // GCC also verifies that stat(pwd) and stat(".") have the same inode - // number. Not doing those because stats are slow, but we could. - if (llvm::sys::path::is_absolute(pwd)) { - std::string CompDir = pwd; - CmdArgs.push_back("-fdebug-compilation-dir"); - CmdArgs.push_back(Args.MakeArgString(CompDir)); - } - } + // Add in -fdebug-compilation-dir if necessary. + addDebugCompDirArg(Args, CmdArgs); if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_, options::OPT_ftemplate_depth_EQ)) { @@ -2359,6 +2611,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, 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()); + } + if (Arg *A = Args.getLastArg(options::OPT_Wlarge_by_value_copy_EQ, options::OPT_Wlarge_by_value_copy_def)) { if (A->getNumValues()) { @@ -2368,14 +2625,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-Wlarge-by-value-copy=64"); // default value } - if (Arg *A = Args.getLastArg(options::OPT_fbounds_checking, - options::OPT_fbounds_checking_EQ)) { - if (A->getNumValues()) { - StringRef val = A->getValue(); - CmdArgs.push_back(Args.MakeArgString("-fbounds-checking=" + val)); - } else - CmdArgs.push_back("-fbounds-checking=1"); - } if (Args.hasArg(options::OPT_relocatable_pch)) CmdArgs.push_back("-relocatable-pch"); @@ -2422,9 +2671,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Twine(N))); } - if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ)) { - CmdArgs.push_back("-fvisibility"); - CmdArgs.push_back(A->getValue()); + // -fvisibility= and -fvisibility-ms-compat are of a piece. + if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ, + options::OPT_fvisibility_ms_compat)) { + if (A->getOption().matches(options::OPT_fvisibility_EQ)) { + CmdArgs.push_back("-fvisibility"); + CmdArgs.push_back(A->getValue()); + } else { + assert(A->getOption().matches(options::OPT_fvisibility_ms_compat)); + CmdArgs.push_back("-fvisibility"); + CmdArgs.push_back("hidden"); + CmdArgs.push_back("-ftype-visibility"); + CmdArgs.push_back("default"); + } } Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden); @@ -2450,7 +2709,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, SanitizerArgs Sanitize(D, Args); Sanitize.addArgs(Args, CmdArgs); - // Report and error for -faltivec on anything other then PowerPC. + if (!Args.hasFlag(options::OPT_fsanitize_recover, + options::OPT_fno_sanitize_recover, + true)) + CmdArgs.push_back("-fno-sanitize-recover"); + + 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, false)) + CmdArgs.push_back("-fsanitize-undefined-trap-on-error"); + + // 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)) @@ -2549,7 +2818,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment); CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment)); } - if (Args.hasArg(options::OPT_mstrict_align)) { + // -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"); } @@ -2588,12 +2858,49 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fmodules enables modules (off by default). However, for C++/Objective-C++, // users must also pass -fcxx-modules. The latter flag will disappear once the // modules implementation is solid for C++/Objective-C++ programs as well. + bool HaveModules = false; if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) { bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules, options::OPT_fno_cxx_modules, false); - if (AllowedInCXX || !types::isCXX(InputType)) + if (AllowedInCXX || !types::isCXX(InputType)) { CmdArgs.push_back("-fmodules"); + HaveModules = true; + } + } + + // If a module path was provided, pass it along. Otherwise, use a temporary + // directory. + if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) { + A->claim(); + if (HaveModules) { + A->render(Args, CmdArgs); + } + } else if (HaveModules) { + SmallString<128> DefaultModuleCache; + llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, + DefaultModuleCache); + llvm::sys::path::append(DefaultModuleCache, "org.llvm.clang"); + llvm::sys::path::append(DefaultModuleCache, "ModuleCache"); + const char Arg[] = "-fmodules-cache-path="; + DefaultModuleCache.insert(DefaultModuleCache.begin(), + Arg, Arg + strlen(Arg)); + CmdArgs.push_back(Args.MakeArgString(DefaultModuleCache)); + } + + // Pass through all -fmodules-ignore-macro arguments. + Args.AddAllArgs(CmdArgs, options::OPT_fmodules_ignore_macro); + Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval); + Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after); + + // -fmodules-autolink (on by default when modules is enabled) automatically + // links against libraries for imported modules. This requires the + // integrated assembler. + if (HaveModules && getToolChain().useIntegratedAs() && + Args.hasFlag(options::OPT_fmodules_autolink, + options::OPT_fno_modules_autolink, + true)) { + CmdArgs.push_back("-fmodules-autolink"); } // -faccess-control is default. @@ -2655,10 +2962,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().getTriple().getOS() == llvm::Triple::Win32)) CmdArgs.push_back("-fms-extensions"); - // -fms-inline-asm. - if (Args.hasArg(options::OPT_fenable_experimental_ms_inline_asm)) - CmdArgs.push_back("-fenable-experimental-ms-inline-asm"); - // -fms-compatibility=0 is default. if (Args.hasFlag(options::OPT_fms_compatibility, options::OPT_fno_ms_compatibility, @@ -2680,7 +2983,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } - // -fborland-extensions=0 is default. + // -fno-borland-extensions is default. if (Args.hasFlag(options::OPT_fborland_extensions, options::OPT_fno_borland_extensions, false)) CmdArgs.push_back("-fborland-extensions"); @@ -2834,8 +3137,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fpack-struct=1"); } - if (Args.hasArg(options::OPT_mkernel) || - Args.hasArg(options::OPT_fapple_kext)) { + if (KernelOrKext) { if (!Args.hasArg(options::OPT_fcommon)) CmdArgs.push_back("-fno-common"); Args.ClaimAllArgs(options::OPT_fno_common); @@ -2916,9 +3218,24 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fno-spell-checking"); - // Silently ignore -fasm-blocks for now. - (void) Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks, - false); + // -fno-asm-blocks is default. + if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks, + false)) + CmdArgs.push_back("-fasm-blocks"); + + // -fvectorize is default. + if (Args.hasFlag(options::OPT_fvectorize, + options::OPT_fno_vectorize, true)) { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-vectorize-loops"); + } + + // -fno-slp-vectorize is default. + if (Args.hasFlag(options::OPT_fslp_vectorize, + options::OPT_fno_slp_vectorize, false)) { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-vectorize"); + } if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ)) A->render(Args, CmdArgs); @@ -2980,6 +3297,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_fretain_comments_from_system_headers)) CmdArgs.push_back("-fretain-comments-from-system-headers"); + // Forward -fcomment-block-commands to -cc1. + Args.AddAllArgs(CmdArgs, options::OPT_fcomment_block_commands); + // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option // parser. Args.AddAllArgValues(CmdArgs, options::OPT_Xclang); @@ -3040,8 +3360,27 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Flags.str())); } + // 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) && + (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA)); + const char *SplitDwarfOut; + if (SplitDwarf) { + CmdArgs.push_back("-split-dwarf-file"); + SplitDwarfOut = SplitDebugName(Args, Inputs); + CmdArgs.push_back(SplitDwarfOut); + } + + // Finally add the compile command to the compilation. 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 (SplitDwarf && !isa<CompileJobAction>(JA)) + SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDwarfOut); + if (Arg *A = Args.getLastArg(options::OPT_pg)) if (Args.hasArg(options::OPT_fomit_frame_pointer)) D.Diag(diag::err_drv_argument_not_allowed_with) @@ -3249,6 +3588,11 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-filetype"); CmdArgs.push_back("obj"); + // Set the main file name, so that debug info works even with + // -save-temps or preprocessed assembly. + CmdArgs.push_back("-main-file-name"); + CmdArgs.push_back(Clang::getBaseInputName(Args, Inputs)); + if (UseRelaxAll(C, Args)) CmdArgs.push_back("-relax-all"); @@ -3278,13 +3622,22 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, SourceAction = SourceAction->getInputs()[0]; } - // Forward -g, assuming we are dealing with an actual assembly file. + // Forward -g and handle debug info related flags, assuming we are dealing + // with an actual assembly file. if (SourceAction->getType() == types::TY_Asm || SourceAction->getType() == types::TY_PP_Asm) { Args.ClaimAllArgs(options::OPT_g_Group); if (Arg *A = Args.getLastArg(options::OPT_g_Group)) if (!A->getOption().matches(options::OPT_g0)) CmdArgs.push_back("-g"); + + // Add the -fdebug-compilation-dir flag if needed. + addDebugCompDirArg(Args, CmdArgs); + + // Set the AT_producer to the clang version when using the integrated + // assembler on assembly source files. + CmdArgs.push_back("-dwarf-debug-producer"); + CmdArgs.push_back(Args.MakeArgString(getClangFullVersion())); } // Optionally embed the -cc1as level arguments into the debug info, for build @@ -3372,7 +3725,7 @@ 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::x86_64) + else if (Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::ppc64) CmdArgs.push_back("-m64"); if (Output.isFilename()) { @@ -3406,6 +3759,9 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, else if (II.getType() == types::TY_AST) D.Diag(diag::err_drv_no_ast_support) << getToolChain().getTripleString(); + else if (II.getType() == types::TY_ModuleFile) + D.Diag(diag::err_drv_no_module_support) + << getToolChain().getTripleString(); if (types::canTypeBeUserSpecified(II.getType())) { CmdArgs.push_back("-x"); @@ -3494,7 +3850,7 @@ void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA, ArgStringList CmdArgs; std::string MarchString = "-march="; - MarchString += getHexagonTargetCPU(Args); + MarchString += toolchains::Hexagon_TC::GetTargetCPU(Args); CmdArgs.push_back(Args.MakeArgString(MarchString)); RenderExtraToolArgs(JA, CmdArgs); @@ -3507,6 +3863,14 @@ void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fsyntax-only"); } + std::string SmallDataThreshold = GetHexagonSmallDataThresholdValue(Args); + if (!SmallDataThreshold.empty()) + CmdArgs.push_back( + Args.MakeArgString(std::string("-G") + SmallDataThreshold)); + + Args.AddAllArgs(CmdArgs, options::OPT_g_Group); + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, + options::OPT_Xassembler); // Only pass -x if gcc will understand it; otherwise hope gcc // understands the suffix correctly. The main use case this would go @@ -3528,6 +3892,9 @@ void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA, else if (II.getType() == types::TY_AST) D.Diag(clang::diag::err_drv_no_ast_support) << getToolChain().getTripleString(); + else if (II.getType() == types::TY_ModuleFile) + D.Diag(diag::err_drv_no_module_support) + << getToolChain().getTripleString(); if (II.isFilename()) CmdArgs.push_back(II.getFilename()); @@ -3553,77 +3920,168 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA, const ArgList &Args, const char *LinkingOutput) const { - const Driver &D = getToolChain().getDriver(); + const toolchains::Hexagon_TC& ToolChain = + static_cast<const toolchains::Hexagon_TC&>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + ArgStringList CmdArgs; - for (ArgList::const_iterator - it = Args.begin(), ie = Args.end(); it != ie; ++it) { - Arg *A = *it; - if (forwardToGCC(A->getOption())) { - // Don't forward any -g arguments to assembly steps. - if (isa<AssembleJobAction>(JA) && - A->getOption().matches(options::OPT_g_Group)) - continue; + //---------------------------------------------------------------------------- + // + //---------------------------------------------------------------------------- + bool hasStaticArg = Args.hasArg(options::OPT_static); + bool buildingLib = Args.hasArg(options::OPT_shared); + bool buildPIE = Args.hasArg(options::OPT_pie); + bool incStdLib = !Args.hasArg(options::OPT_nostdlib); + bool incStartFiles = !Args.hasArg(options::OPT_nostartfiles); + bool incDefLibs = !Args.hasArg(options::OPT_nodefaultlibs); + bool useShared = buildingLib && !hasStaticArg; + + //---------------------------------------------------------------------------- + // Silence warnings for various options + //---------------------------------------------------------------------------- - // 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 - // to get to the assembler. - A->claim(); - A->render(Args, CmdArgs); - } + Args.ClaimAllArgs(options::OPT_g_Group); + Args.ClaimAllArgs(options::OPT_emit_llvm); + Args.ClaimAllArgs(options::OPT_w); // Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_static_libgcc); + + //---------------------------------------------------------------------------- + // + //---------------------------------------------------------------------------- + for (std::vector<std::string>::const_iterator i = ToolChain.ExtraOpts.begin(), + e = ToolChain.ExtraOpts.end(); + i != e; ++i) + CmdArgs.push_back(i->c_str()); + + std::string MarchString = toolchains::Hexagon_TC::GetTargetCPU(Args); + CmdArgs.push_back(Args.MakeArgString("-m" + MarchString)); + + if (buildingLib) { + CmdArgs.push_back("-shared"); + CmdArgs.push_back("-call_shared"); // should be the default, but doing as + // hexagon-gcc does } - RenderExtraToolArgs(JA, CmdArgs); + if (hasStaticArg) + CmdArgs.push_back("-static"); - // Add Arch Information - Arg *A; - if ((A = getLastHexagonArchArg(Args))) { - if (A->getOption().matches(options::OPT_m_Joined)) - A->render(Args, CmdArgs); - else - CmdArgs.push_back (Args.MakeArgString("-m" + getHexagonTargetCPU(Args))); + if (buildPIE && !buildingLib) + CmdArgs.push_back("-pie"); + + std::string SmallDataThreshold = GetHexagonSmallDataThresholdValue(Args); + if (!SmallDataThreshold.empty()) { + CmdArgs.push_back( + Args.MakeArgString(std::string("-G") + SmallDataThreshold)); } - else { - CmdArgs.push_back (Args.MakeArgString("-m" + getHexagonTargetCPU(Args))); + + //---------------------------------------------------------------------------- + // + //---------------------------------------------------------------------------- + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + const std::string MarchSuffix = "/" + MarchString; + const std::string G0Suffix = "/G0"; + const std::string MarchG0Suffix = MarchSuffix + G0Suffix; + const std::string RootDir = toolchains::Hexagon_TC::GetGnuDir(D.InstalledDir) + + "/"; + const std::string StartFilesDir = RootDir + + "hexagon/lib" + + (buildingLib + ? MarchG0Suffix : MarchSuffix); + + //---------------------------------------------------------------------------- + // moslib + //---------------------------------------------------------------------------- + std::vector<std::string> oslibs; + bool hasStandalone= false; + + for (arg_iterator it = Args.filtered_begin(options::OPT_moslib_EQ), + ie = Args.filtered_end(); it != ie; ++it) { + (*it)->claim(); + oslibs.push_back((*it)->getValue()); + hasStandalone = hasStandalone || (oslibs.back() == "standalone"); + } + if (oslibs.empty()) { + oslibs.push_back("standalone"); + hasStandalone = true; } - CmdArgs.push_back("-mqdsp6-compat"); + //---------------------------------------------------------------------------- + // Start Files + //---------------------------------------------------------------------------- + if (incStdLib && incStartFiles) { - const char *GCCName; - if (C.getDriver().CCCIsCXX) - GCCName = "hexagon-g++"; - else - GCCName = "hexagon-gcc"; - const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(GCCName)); + if (!buildingLib) { + if (hasStandalone) { + CmdArgs.push_back( + Args.MakeArgString(StartFilesDir + "/crt0_standalone.o")); + } + CmdArgs.push_back(Args.MakeArgString(StartFilesDir + "/crt0.o")); + } + std::string initObj = useShared ? "/initS.o" : "/init.o"; + CmdArgs.push_back(Args.MakeArgString(StartFilesDir + initObj)); + } + + //---------------------------------------------------------------------------- + // Library Search Paths + //---------------------------------------------------------------------------- + const ToolChain::path_list &LibPaths = ToolChain.getFilePaths(); + for (ToolChain::path_list::const_iterator + i = LibPaths.begin(), + e = LibPaths.end(); + i != e; + ++i) + CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + *i)); - if (Output.isFilename()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - } + //---------------------------------------------------------------------------- + // + //---------------------------------------------------------------------------- + Args.AddAllArgs(CmdArgs, options::OPT_T_Group); + Args.AddAllArgs(CmdArgs, options::OPT_e); + Args.AddAllArgs(CmdArgs, options::OPT_s); + Args.AddAllArgs(CmdArgs, options::OPT_t); + Args.AddAllArgs(CmdArgs, options::OPT_u_Group); - for (InputInfoList::const_iterator - it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { - const InputInfo &II = *it; + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); - // Don't try to pass LLVM or AST inputs to a generic gcc. - if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR || - II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC) - D.Diag(clang::diag::err_drv_no_linker_llvm_support) - << getToolChain().getTripleString(); - else if (II.getType() == types::TY_AST) - D.Diag(clang::diag::err_drv_no_ast_support) - << getToolChain().getTripleString(); + //---------------------------------------------------------------------------- + // Libraries + //---------------------------------------------------------------------------- + if (incStdLib && incDefLibs) { + if (D.CCCIsCXX) { + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + CmdArgs.push_back("-lm"); + } - if (II.isFilename()) - CmdArgs.push_back(II.getFilename()); - else - // Don't render as input, we need gcc to do the translations. FIXME: Pranav: What is this ? - II.getInputArg().render(Args, CmdArgs); + CmdArgs.push_back("--start-group"); + + if (!buildingLib) { + for(std::vector<std::string>::iterator i = oslibs.begin(), + e = oslibs.end(); i != e; ++i) + CmdArgs.push_back(Args.MakeArgString("-l" + *i)); + CmdArgs.push_back("-lc"); + } + CmdArgs.push_back("-lgcc"); + + CmdArgs.push_back("--end-group"); + } + + //---------------------------------------------------------------------------- + // End files + //---------------------------------------------------------------------------- + if (incStdLib && incStartFiles) { + std::string finiObj = useShared ? "/finiS.o" : "/fini.o"; + CmdArgs.push_back(Args.MakeArgString(StartFilesDir + finiObj)); } - C.addCommand(new Command(JA, *this, Exec, CmdArgs)); + std::string Linker = ToolChain.GetProgramPath("hexagon-ld"); + C.addCommand( + new Command( + JA, *this, + Args.MakeArgString(Linker), CmdArgs)); } // Hexagon tools end. @@ -3649,8 +4107,9 @@ llvm::Triple::ArchType darwin::getArchTypeForDarwinArchName(StringRef Str) { llvm::Triple::x86) .Case("x86_64", llvm::Triple::x86_64) // This is derived from the driver driver. - .Cases("arm", "armv4t", "armv5", "armv6", llvm::Triple::arm) - .Cases("armv7", "armv7f", "armv7k", "armv7s", "xscale", llvm::Triple::arm) + .Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm) + .Cases("armv7", "armv7em", "armv7f", "armv7k", "armv7m", llvm::Triple::arm) + .Cases("armv7s", "xscale", llvm::Triple::arm) .Case("r600", llvm::Triple::r600) .Case("nvptx", llvm::Triple::nvptx) .Case("nvptx64", llvm::Triple::nvptx64) @@ -3659,38 +4118,14 @@ llvm::Triple::ArchType darwin::getArchTypeForDarwinArchName(StringRef Str) { .Default(llvm::Triple::UnknownArch); } -const char *darwin::CC1::getCC1Name(types::ID Type) const { - switch (Type) { - default: - llvm_unreachable("Unexpected type for Darwin CC1 tool."); - case types::TY_Asm: - case types::TY_C: case types::TY_CHeader: - case types::TY_PP_C: case types::TY_PP_CHeader: - return "cc1"; - case types::TY_ObjC: case types::TY_ObjCHeader: - case types::TY_PP_ObjC: case types::TY_PP_ObjC_Alias: - case types::TY_PP_ObjCHeader: - return "cc1obj"; - case types::TY_CXX: case types::TY_CXXHeader: - case types::TY_PP_CXX: case types::TY_PP_CXXHeader: - return "cc1plus"; - case types::TY_ObjCXX: case types::TY_ObjCXXHeader: - case types::TY_PP_ObjCXX: case types::TY_PP_ObjCXX_Alias: - case types::TY_PP_ObjCXXHeader: - return "cc1objplus"; - } -} - -void darwin::CC1::anchor() {} - -const char *darwin::CC1::getBaseInputName(const ArgList &Args, - const InputInfoList &Inputs) { +const char *Clang::getBaseInputName(const ArgList &Args, + const InputInfoList &Inputs) { return Args.MakeArgString( llvm::sys::path::filename(Inputs[0].getBaseInput())); } -const char *darwin::CC1::getBaseInputStem(const ArgList &Args, - const InputInfoList &Inputs) { +const char *Clang::getBaseInputStem(const ArgList &Args, + const InputInfoList &Inputs) { const char *Str = getBaseInputName(Args, Inputs); if (const char *End = strrchr(Str, '.')) @@ -3699,9 +4134,8 @@ const char *darwin::CC1::getBaseInputStem(const ArgList &Args, return Str; } -const char * -darwin::CC1::getDependencyFileName(const ArgList &Args, - const InputInfoList &Inputs) { +const char *Clang::getDependencyFileName(const ArgList &Args, + const InputInfoList &Inputs) { // FIXME: Think about this more. std::string Res; @@ -3709,588 +4143,11 @@ darwin::CC1::getDependencyFileName(const ArgList &Args, std::string Str(OutputOpt->getValue()); Res = Str.substr(0, Str.rfind('.')); } else { - Res = darwin::CC1::getBaseInputStem(Args, Inputs); + Res = getBaseInputStem(Args, Inputs); } return Args.MakeArgString(Res + ".d"); } -void darwin::CC1::RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const { - for (ArgStringList::iterator it = CmdArgs.begin(), ie = CmdArgs.end(); - it != ie;) { - - StringRef Option = *it; - bool RemoveOption = false; - - // Erase both -fmodule-cache-path and its argument. - if (Option.equals("-fmodule-cache-path") && it+2 != ie) { - it = CmdArgs.erase(it, it+2); - ie = CmdArgs.end(); - continue; - } - - // Remove unsupported -f options. - if (Option.startswith("-f")) { - // Remove -f/-fno- to reduce the number of cases. - if (Option.startswith("-fno-")) - Option = Option.substr(5); - else - Option = Option.substr(2); - RemoveOption = llvm::StringSwitch<bool>(Option) - .Case("altivec", true) - .Case("modules", true) - .Case("diagnostics-show-note-include-stack", true) - .Default(false); - } - - // Handle machine specific options. - if (Option.startswith("-m")) { - RemoveOption = llvm::StringSwitch<bool>(Option) - .Case("-mthumb", true) - .Case("-mno-thumb", true) - .Case("-mno-fused-madd", true) - .Case("-mlong-branch", true) - .Case("-mlongcall", true) - .Case("-mcpu=G4", true) - .Case("-mcpu=G5", true) - .Default(false); - } - - // Handle warning options. - if (Option.startswith("-W")) { - // Remove -W/-Wno- to reduce the number of cases. - if (Option.startswith("-Wno-")) - Option = Option.substr(5); - else - Option = Option.substr(2); - - RemoveOption = llvm::StringSwitch<bool>(Option) - .Case("address-of-temporary", true) - .Case("ambiguous-member-template", true) - .Case("analyzer-incompatible-plugin", true) - .Case("array-bounds", true) - .Case("array-bounds-pointer-arithmetic", true) - .Case("bind-to-temporary-copy", true) - .Case("bitwise-op-parentheses", true) - .Case("bool-conversions", true) - .Case("builtin-macro-redefined", true) - .Case("c++-hex-floats", true) - .Case("c++0x-compat", true) - .Case("c++0x-extensions", true) - .Case("c++0x-narrowing", true) - .Case("c++11-compat", true) - .Case("c++11-extensions", true) - .Case("c++11-narrowing", true) - .Case("conditional-uninitialized", true) - .Case("constant-conversion", true) - .Case("conversion-null", true) - .Case("CFString-literal", true) - .Case("constant-logical-operand", true) - .Case("custom-atomic-properties", true) - .Case("default-arg-special-member", true) - .Case("delegating-ctor-cycles", true) - .Case("delete-non-virtual-dtor", true) - .Case("deprecated-implementations", true) - .Case("deprecated-writable-strings", true) - .Case("distributed-object-modifiers", true) - .Case("duplicate-method-arg", true) - .Case("dynamic-class-memaccess", true) - .Case("enum-compare", true) - .Case("enum-conversion", true) - .Case("exit-time-destructors", true) - .Case("gnu", true) - .Case("gnu-designator", true) - .Case("header-hygiene", true) - .Case("idiomatic-parentheses", true) - .Case("ignored-qualifiers", true) - .Case("implicit-atomic-properties", true) - .Case("incompatible-pointer-types", true) - .Case("incomplete-implementation", true) - .Case("int-conversion", true) - .Case("initializer-overrides", true) - .Case("invalid-noreturn", true) - .Case("invalid-token-paste", true) - .Case("language-extension-token", true) - .Case("literal-conversion", true) - .Case("literal-range", true) - .Case("local-type-template-args", true) - .Case("logical-op-parentheses", true) - .Case("method-signatures", true) - .Case("microsoft", true) - .Case("mismatched-tags", true) - .Case("missing-method-return-type", true) - .Case("non-pod-varargs", true) - .Case("nonfragile-abi2", true) - .Case("null-arithmetic", true) - .Case("null-dereference", true) - .Case("out-of-line-declaration", true) - .Case("overriding-method-mismatch", true) - .Case("readonly-setter-attrs", true) - .Case("return-stack-address", true) - .Case("self-assign", true) - .Case("semicolon-before-method-body", true) - .Case("sentinel", true) - .Case("shift-overflow", true) - .Case("shift-sign-overflow", true) - .Case("sign-conversion", true) - .Case("sizeof-array-argument", true) - .Case("sizeof-pointer-memaccess", true) - .Case("string-compare", true) - .Case("super-class-method-mismatch", true) - .Case("tautological-compare", true) - .Case("typedef-redefinition", true) - .Case("typename-missing", true) - .Case("undefined-reinterpret-cast", true) - .Case("unknown-warning-option", true) - .Case("unnamed-type-template-args", true) - .Case("unneeded-internal-declaration", true) - .Case("unneeded-member-function", true) - .Case("unused-comparison", true) - .Case("unused-exception-parameter", true) - .Case("unused-member-function", true) - .Case("unused-result", true) - .Case("vector-conversions", true) - .Case("vla", true) - .Case("used-but-marked-unused", true) - .Case("weak-vtables", true) - .Default(false); - } // if (Option.startswith("-W")) - if (RemoveOption) { - it = CmdArgs.erase(it); - ie = CmdArgs.end(); - } else { - ++it; - } - } -} - -void darwin::CC1::AddCC1Args(const ArgList &Args, - ArgStringList &CmdArgs) const { - const Driver &D = getToolChain().getDriver(); - - CheckCodeGenerationOptions(D, Args); - - // Derived from cc1 spec. - if ((!Args.hasArg(options::OPT_mkernel) || - (getDarwinToolChain().isTargetIPhoneOS() && - !getDarwinToolChain().isIPhoneOSVersionLT(6, 0))) && - !Args.hasArg(options::OPT_static) && - !Args.hasArg(options::OPT_mdynamic_no_pic)) - CmdArgs.push_back("-fPIC"); - - if (getToolChain().getTriple().getArch() == llvm::Triple::arm || - getToolChain().getTriple().getArch() == llvm::Triple::thumb) { - if (!Args.hasArg(options::OPT_fbuiltin_strcat)) - CmdArgs.push_back("-fno-builtin-strcat"); - if (!Args.hasArg(options::OPT_fbuiltin_strcpy)) - CmdArgs.push_back("-fno-builtin-strcpy"); - } - - if (Args.hasArg(options::OPT_g_Flag) && - !Args.hasArg(options::OPT_fno_eliminate_unused_debug_symbols)) - CmdArgs.push_back("-feliminate-unused-debug-symbols"); -} - -void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, - const InputInfoList &Inputs, - const ArgStringList &OutputArgs) const { - const Driver &D = getToolChain().getDriver(); - - // Derived from cc1_options spec. - if (Args.hasArg(options::OPT_fast) || - Args.hasArg(options::OPT_fastf) || - Args.hasArg(options::OPT_fastcp)) - CmdArgs.push_back("-O3"); - - if (Arg *A = Args.getLastArg(options::OPT_pg)) - if (Args.hasArg(options::OPT_fomit_frame_pointer)) - D.Diag(diag::err_drv_argument_not_allowed_with) - << A->getAsString(Args) << "-fomit-frame-pointer"; - - AddCC1Args(Args, CmdArgs); - - if (!Args.hasArg(options::OPT_Q)) - CmdArgs.push_back("-quiet"); - - CmdArgs.push_back("-dumpbase"); - CmdArgs.push_back(darwin::CC1::getBaseInputName(Args, Inputs)); - - Args.AddAllArgs(CmdArgs, options::OPT_d_Group); - - Args.AddAllArgs(CmdArgs, options::OPT_m_Group); - Args.AddAllArgs(CmdArgs, options::OPT_a_Group); - - // FIXME: The goal is to use the user provided -o if that is our - // final output, otherwise to drive from the original input - // name. Find a clean way to go about this. - if ((Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) && - Args.hasArg(options::OPT_o)) { - Arg *OutputOpt = Args.getLastArg(options::OPT_o); - CmdArgs.push_back("-auxbase-strip"); - CmdArgs.push_back(OutputOpt->getValue()); - } else { - CmdArgs.push_back("-auxbase"); - CmdArgs.push_back(darwin::CC1::getBaseInputStem(Args, Inputs)); - } - - Args.AddAllArgs(CmdArgs, options::OPT_g_Group); - - Args.AddAllArgs(CmdArgs, options::OPT_O); - // FIXME: -Wall is getting some special treatment. Investigate. - Args.AddAllArgs(CmdArgs, options::OPT_W_Group, options::OPT_pedantic_Group); - Args.AddLastArg(CmdArgs, options::OPT_w); - Args.AddAllArgs(CmdArgs, options::OPT_std_EQ, options::OPT_ansi, - options::OPT_trigraphs); - if (!Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) { - // Honor -std-default. - Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, - "-std=", /*Joined=*/true); - } - - if (Args.hasArg(options::OPT_v)) - CmdArgs.push_back("-version"); - if (Args.hasArg(options::OPT_pg) && - getToolChain().SupportsProfiling()) - CmdArgs.push_back("-p"); - Args.AddLastArg(CmdArgs, options::OPT_p); - - // The driver treats -fsyntax-only specially. - if (getToolChain().getTriple().getArch() == llvm::Triple::arm || - getToolChain().getTriple().getArch() == llvm::Triple::thumb) { - // Removes -fbuiltin-str{cat,cpy}; these aren't recognized by cc1 but are - // used to inhibit the default -fno-builtin-str{cat,cpy}. - // - // FIXME: Should we grow a better way to deal with "removing" args? - for (arg_iterator it = Args.filtered_begin(options::OPT_f_Group, - options::OPT_fsyntax_only), - ie = Args.filtered_end(); it != ie; ++it) { - if (!(*it)->getOption().matches(options::OPT_fbuiltin_strcat) && - !(*it)->getOption().matches(options::OPT_fbuiltin_strcpy)) { - (*it)->claim(); - (*it)->render(Args, CmdArgs); - } - } - } else - Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only); - - // Claim Clang only -f options, they aren't worth warning about. - Args.ClaimAllArgs(options::OPT_f_clang_Group); - - Args.AddAllArgs(CmdArgs, options::OPT_undef); - if (Args.hasArg(options::OPT_Qn)) - CmdArgs.push_back("-fno-ident"); - - // FIXME: This isn't correct. - //Args.AddLastArg(CmdArgs, options::OPT__help) - //Args.AddLastArg(CmdArgs, options::OPT__targetHelp) - - CmdArgs.append(OutputArgs.begin(), OutputArgs.end()); - - // FIXME: Still don't get what is happening here. Investigate. - Args.AddAllArgs(CmdArgs, options::OPT__param); - - if (Args.hasArg(options::OPT_fmudflap) || - Args.hasArg(options::OPT_fmudflapth)) { - CmdArgs.push_back("-fno-builtin"); - CmdArgs.push_back("-fno-merge-constants"); - } - - if (Args.hasArg(options::OPT_coverage)) { - CmdArgs.push_back("-fprofile-arcs"); - CmdArgs.push_back("-ftest-coverage"); - } - - if (types::isCXX(Inputs[0].getType())) - CmdArgs.push_back("-D__private_extern__=extern"); -} - -void darwin::CC1::AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, - const InputInfoList &Inputs, - const ArgStringList &OutputArgs) const { - // Derived from cpp_options - AddCPPUniqueOptionsArgs(Args, CmdArgs, Inputs); - - CmdArgs.append(OutputArgs.begin(), OutputArgs.end()); - - AddCC1Args(Args, CmdArgs); - - // NOTE: The code below has some commonality with cpp_options, but - // in classic gcc style ends up sending things in different - // orders. This may be a good merge candidate once we drop pedantic - // compatibility. - - Args.AddAllArgs(CmdArgs, options::OPT_m_Group); - Args.AddAllArgs(CmdArgs, options::OPT_std_EQ, options::OPT_ansi, - options::OPT_trigraphs); - if (!Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) { - // Honor -std-default. - Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, - "-std=", /*Joined=*/true); - } - Args.AddAllArgs(CmdArgs, options::OPT_W_Group, options::OPT_pedantic_Group); - Args.AddLastArg(CmdArgs, options::OPT_w); - - // The driver treats -fsyntax-only specially. - Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only); - - // Claim Clang only -f options, they aren't worth warning about. - Args.ClaimAllArgs(options::OPT_f_clang_Group); - - if (Args.hasArg(options::OPT_g_Group) && !Args.hasArg(options::OPT_g0) && - !Args.hasArg(options::OPT_fno_working_directory)) - CmdArgs.push_back("-fworking-directory"); - - Args.AddAllArgs(CmdArgs, options::OPT_O); - Args.AddAllArgs(CmdArgs, options::OPT_undef); - if (Args.hasArg(options::OPT_save_temps)) - CmdArgs.push_back("-fpch-preprocess"); -} - -void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args, - ArgStringList &CmdArgs, - const InputInfoList &Inputs) const { - const Driver &D = getToolChain().getDriver(); - - CheckPreprocessingOptions(D, Args); - - // Derived from cpp_unique_options. - // -{C,CC} only with -E is checked in CheckPreprocessingOptions(). - Args.AddLastArg(CmdArgs, options::OPT_C); - Args.AddLastArg(CmdArgs, options::OPT_CC); - if (!Args.hasArg(options::OPT_Q)) - CmdArgs.push_back("-quiet"); - Args.AddAllArgs(CmdArgs, options::OPT_nostdinc); - Args.AddAllArgs(CmdArgs, options::OPT_nostdincxx); - Args.AddLastArg(CmdArgs, options::OPT_v); - Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F); - Args.AddLastArg(CmdArgs, options::OPT_P); - - // FIXME: Handle %I properly. - if (getToolChain().getArch() == llvm::Triple::x86_64) { - CmdArgs.push_back("-imultilib"); - CmdArgs.push_back("x86_64"); - } - - if (Args.hasArg(options::OPT_MD)) { - CmdArgs.push_back("-MD"); - CmdArgs.push_back(darwin::CC1::getDependencyFileName(Args, Inputs)); - } - - if (Args.hasArg(options::OPT_MMD)) { - CmdArgs.push_back("-MMD"); - CmdArgs.push_back(darwin::CC1::getDependencyFileName(Args, Inputs)); - } - - Args.AddLastArg(CmdArgs, options::OPT_M); - Args.AddLastArg(CmdArgs, options::OPT_MM); - Args.AddAllArgs(CmdArgs, options::OPT_MF); - Args.AddLastArg(CmdArgs, options::OPT_MG); - Args.AddLastArg(CmdArgs, options::OPT_MP); - Args.AddAllArgs(CmdArgs, options::OPT_MQ); - Args.AddAllArgs(CmdArgs, options::OPT_MT); - if (!Args.hasArg(options::OPT_M) && !Args.hasArg(options::OPT_MM) && - (Args.hasArg(options::OPT_MD) || Args.hasArg(options::OPT_MMD))) { - if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) { - CmdArgs.push_back("-MQ"); - CmdArgs.push_back(OutputOpt->getValue()); - } - } - - Args.AddLastArg(CmdArgs, options::OPT_remap); - if (Args.hasArg(options::OPT_g3)) - CmdArgs.push_back("-dD"); - Args.AddLastArg(CmdArgs, options::OPT_H); - - AddCPPArgs(Args, CmdArgs); - - Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U, options::OPT_A); - Args.AddAllArgs(CmdArgs, options::OPT_i_Group); - - for (InputInfoList::const_iterator - it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { - const InputInfo &II = *it; - - CmdArgs.push_back(II.getFilename()); - } - - Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA, - options::OPT_Xpreprocessor); - - if (Args.hasArg(options::OPT_fmudflap)) { - CmdArgs.push_back("-D_MUDFLAP"); - CmdArgs.push_back("-include"); - CmdArgs.push_back("mf-runtime.h"); - } - - if (Args.hasArg(options::OPT_fmudflapth)) { - CmdArgs.push_back("-D_MUDFLAP"); - CmdArgs.push_back("-D_MUDFLAPTH"); - CmdArgs.push_back("-include"); - CmdArgs.push_back("mf-runtime.h"); - } -} - -void darwin::CC1::AddCPPArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - // Derived from cpp spec. - - if (Args.hasArg(options::OPT_static)) { - // The gcc spec is broken here, it refers to dynamic but - // that has been translated. Start by being bug compatible. - - // if (!Args.hasArg(arglist.parser.dynamicOption)) - CmdArgs.push_back("-D__STATIC__"); - } else - CmdArgs.push_back("-D__DYNAMIC__"); - - if (Args.hasArg(options::OPT_pthread)) - CmdArgs.push_back("-D_REENTRANT"); -} - -void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - ArgStringList CmdArgs; - - assert(Inputs.size() == 1 && "Unexpected number of inputs!"); - - CmdArgs.push_back("-E"); - - if (Args.hasArg(options::OPT_traditional) || - Args.hasArg(options::OPT_traditional_cpp)) - CmdArgs.push_back("-traditional-cpp"); - - ArgStringList OutputArgs; - assert(Output.isFilename() && "Unexpected CC1 output."); - OutputArgs.push_back("-o"); - OutputArgs.push_back(Output.getFilename()); - - if (Args.hasArg(options::OPT_E) || getToolChain().getDriver().CCCIsCPP) { - AddCPPOptionsArgs(Args, CmdArgs, Inputs, OutputArgs); - } else { - AddCPPOptionsArgs(Args, CmdArgs, Inputs, ArgStringList()); - CmdArgs.append(OutputArgs.begin(), OutputArgs.end()); - } - - Args.AddAllArgs(CmdArgs, options::OPT_d_Group); - - RemoveCC1UnsupportedArgs(CmdArgs); - - const char *CC1Name = getCC1Name(Inputs[0].getType()); - const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(CC1Name)); - C.addCommand(new Command(JA, *this, Exec, CmdArgs)); -} - -void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const Driver &D = getToolChain().getDriver(); - ArgStringList CmdArgs; - - assert(Inputs.size() == 1 && "Unexpected number of inputs!"); - - // Silence warning about unused --serialize-diagnostics - Args.ClaimAllArgs(options::OPT__serialize_diags); - - types::ID InputType = Inputs[0].getType(); - if (const Arg *A = Args.getLastArg(options::OPT_traditional)) - D.Diag(diag::err_drv_argument_only_allowed_with) - << A->getAsString(Args) << "-E"; - - if (JA.getType() == types::TY_LLVM_IR || - JA.getType() == types::TY_LTO_IR) - CmdArgs.push_back("-emit-llvm"); - else if (JA.getType() == types::TY_LLVM_BC || - JA.getType() == types::TY_LTO_BC) - CmdArgs.push_back("-emit-llvm-bc"); - else if (Output.getType() == types::TY_AST) - D.Diag(diag::err_drv_no_ast_support) - << getToolChain().getTripleString(); - else if (JA.getType() != types::TY_PP_Asm && - JA.getType() != types::TY_PCH) - D.Diag(diag::err_drv_invalid_gcc_output_type) - << getTypeName(JA.getType()); - - ArgStringList OutputArgs; - if (Output.getType() != types::TY_PCH) { - OutputArgs.push_back("-o"); - if (Output.isNothing()) - OutputArgs.push_back("/dev/null"); - else - OutputArgs.push_back(Output.getFilename()); - } - - // There is no need for this level of compatibility, but it makes - // diffing easier. - bool OutputArgsEarly = (Args.hasArg(options::OPT_fsyntax_only) || - Args.hasArg(options::OPT_S)); - - if (types::getPreprocessedType(InputType) != types::TY_INVALID) { - AddCPPUniqueOptionsArgs(Args, CmdArgs, Inputs); - if (OutputArgsEarly) { - AddCC1OptionsArgs(Args, CmdArgs, Inputs, OutputArgs); - } else { - AddCC1OptionsArgs(Args, CmdArgs, Inputs, ArgStringList()); - CmdArgs.append(OutputArgs.begin(), OutputArgs.end()); - } - } else { - CmdArgs.push_back("-fpreprocessed"); - - for (InputInfoList::const_iterator - it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { - const InputInfo &II = *it; - - // Reject AST inputs. - if (II.getType() == types::TY_AST) { - D.Diag(diag::err_drv_no_ast_support) - << getToolChain().getTripleString(); - return; - } - - CmdArgs.push_back(II.getFilename()); - } - - if (OutputArgsEarly) { - AddCC1OptionsArgs(Args, CmdArgs, Inputs, OutputArgs); - } else { - AddCC1OptionsArgs(Args, CmdArgs, Inputs, ArgStringList()); - CmdArgs.append(OutputArgs.begin(), OutputArgs.end()); - } - } - - if (Output.getType() == types::TY_PCH) { - assert(Output.isFilename() && "Invalid PCH output."); - - CmdArgs.push_back("-o"); - // NOTE: gcc uses a temp .s file for this, but there doesn't seem - // to be a good reason. - const char *TmpPath = C.getArgs().MakeArgString( - D.GetTemporaryPath("cc", "s")); - C.addTempFile(TmpPath); - CmdArgs.push_back(TmpPath); - - // If we're emitting a pch file with the last 4 characters of ".pth" - // and falling back to llvm-gcc we want to use ".gch" instead. - std::string OutputFile(Output.getFilename()); - size_t loc = OutputFile.rfind(".pth"); - if (loc != std::string::npos) - OutputFile.replace(loc, 4, ".gch"); - const char *Tmp = C.getArgs().MakeArgString("--output-pch="+OutputFile); - CmdArgs.push_back(Tmp); - } - - RemoveCC1UnsupportedArgs(CmdArgs); - - const char *CC1Name = getCC1Name(Inputs[0].getType()); - const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(CC1Name)); - C.addCommand(new Command(JA, *this, Exec, CmdArgs)); -} - void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -4624,6 +4481,9 @@ 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()); @@ -4721,11 +4581,11 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); SanitizerArgs Sanitize(getToolChain().getDriver(), Args); - // If we're building a dynamic lib with -fsanitize=address, or - // -fsanitize=undefined, unresolved symbols may appear. Mark all + // 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() || Sanitize.needsUbsanRt()) { + if (Sanitize.needsAsanRt()) { if (Args.hasArg(options::OPT_dynamiclib) || Args.hasArg(options::OPT_bundle)) { CmdArgs.push_back("-undefined"); @@ -4839,10 +4699,10 @@ void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA, } void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { ArgStringList CmdArgs; CmdArgs.push_back("--verify"); CmdArgs.push_back("--debug-info"); @@ -5136,6 +4996,14 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + if ((!Args.hasArg(options::OPT_nostdlib)) && (!Args.hasArg(options::OPT_shared))) { CmdArgs.push_back("-e"); @@ -5190,6 +5058,10 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); + Args.AddAllArgs(CmdArgs, options::OPT_s); + Args.AddAllArgs(CmdArgs, options::OPT_t); + Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); + Args.AddAllArgs(CmdArgs, options::OPT_r); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); @@ -5406,14 +5278,8 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-march"); CmdArgs.push_back(CPUName.data()); - // Convert ABI name to the GNU tools acceptable variant. - if (ABIName == "o32") - ABIName = "32"; - else if (ABIName == "n64") - ABIName = "64"; - CmdArgs.push_back("-mabi"); - CmdArgs.push_back(ABIName.data()); + CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data()); if (getToolChain().getArch() == llvm::Triple::mips || getToolChain().getArch() == llvm::Triple::mips64) @@ -5788,11 +5654,11 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } -void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { +void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { ArgStringList CmdArgs; // Add --32/--64 to make sure we get the format we want. @@ -5832,14 +5698,8 @@ void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-march"); CmdArgs.push_back(CPUName.data()); - // Convert ABI name to the GNU tools acceptable variant. - if (ABIName == "o32") - ABIName = "32"; - else if (ABIName == "n64") - ABIName = "64"; - CmdArgs.push_back("-mabi"); - CmdArgs.push_back(ABIName.data()); + CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data()); if (getToolChain().getArch() == llvm::Triple::mips || getToolChain().getArch() == llvm::Triple::mips64) @@ -5880,12 +5740,12 @@ void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, static void AddLibgcc(llvm::Triple Triple, const Driver &D, ArgStringList &CmdArgs, const ArgList &Args) { bool isAndroid = Triple.getEnvironment() == llvm::Triple::Android; - bool StaticLibgcc = isAndroid || Args.hasArg(options::OPT_static) || - Args.hasArg(options::OPT_static_libgcc); + bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) || + Args.hasArg(options::OPT_static); if (!D.CCCIsCXX) CmdArgs.push_back("-lgcc"); - if (StaticLibgcc) { + if (StaticLibgcc || isAndroid) { if (D.CCCIsCXX) CmdArgs.push_back("-lgcc"); } else { @@ -5900,6 +5760,14 @@ static void AddLibgcc(llvm::Triple Triple, const Driver &D, CmdArgs.push_back("-lgcc_eh"); 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 + // linking with non-static libgcc. + // + // NOTE: This fixes a link error on Android MIPS as well. The non-static + // libgcc for MIPS relies on _Unwind_Find_FDE and dl_iterate_phdr from libdl. + if (isAndroid && !StaticLibgcc) + CmdArgs.push_back("-ldl"); } static bool hasMipsN32ABIArg(const ArgList &Args) { @@ -5907,11 +5775,11 @@ static bool hasMipsN32ABIArg(const ArgList &Args) { return A && (A->getValue() == StringRef("n32")); } -void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { +void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { const toolchains::Linux& ToolChain = static_cast<const toolchains::Linux&>(getToolChain()); const Driver &D = ToolChain.getDriver(); @@ -5931,7 +5799,7 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - if (Args.hasArg(options::OPT_pie)) + if (Args.hasArg(options::OPT_pie) && !Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-pie"); if (Args.hasArg(options::OPT_rdynamic)) @@ -5952,6 +5820,8 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-m"); if (ToolChain.getArch() == llvm::Triple::x86) CmdArgs.push_back("elf_i386"); + else if (ToolChain.getArch() == llvm::Triple::aarch64) + CmdArgs.push_back("aarch64linux"); else if (ToolChain.getArch() == llvm::Triple::arm || ToolChain.getArch() == llvm::Triple::thumb) CmdArgs.push_back("armelf_linux_eabi"); @@ -6000,6 +5870,8 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, 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) @@ -6102,9 +5974,17 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, SanitizerArgs Sanitize(D, Args); - // Call this before we add the C++ ABI library. + // Call these before we add the C++ ABI library. if (Sanitize.needsUbsanRt()) - addUbsanRTLinux(getToolChain(), Args, CmdArgs); + addUbsanRTLinux(getToolChain(), Args, CmdArgs, D.CCCIsCXX, + Sanitize.needsAsanRt() || Sanitize.needsTsanRt() || + Sanitize.needsMsanRt()); + if (Sanitize.needsAsanRt()) + addAsanRTLinux(getToolChain(), Args, CmdArgs); + if (Sanitize.needsTsanRt()) + addTsanRTLinux(getToolChain(), Args, CmdArgs); + if (Sanitize.needsMsanRt()) + addMsanRTLinux(getToolChain(), Args, CmdArgs); if (D.CCCIsCXX && !Args.hasArg(options::OPT_nostdlib) && @@ -6119,21 +5999,24 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lm"); } - // Call this before we add the C run-time. - if (Sanitize.needsAsanRt()) - addAsanRTLinux(getToolChain(), Args, CmdArgs); - if (Sanitize.needsTsanRt()) - addTsanRTLinux(getToolChain(), Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib)) { if (!Args.hasArg(options::OPT_nodefaultlibs)) { if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("--start-group"); + bool OpenMP = Args.hasArg(options::OPT_fopenmp); + if (OpenMP) { + CmdArgs.push_back("-lgomp"); + + // FIXME: Exclude this for platforms whith libgomp that doesn't require + // librt. Most modern Linux platfroms require it, but some may not. + CmdArgs.push_back("-lrt"); + } + AddLibgcc(ToolChain.getTriple(), D, CmdArgs, Args); if (Args.hasArg(options::OPT_pthread) || - Args.hasArg(options::OPT_pthreads)) + Args.hasArg(options::OPT_pthreads) || OpenMP) CmdArgs.push_back("-lpthread"); CmdArgs.push_back("-lc"); @@ -6235,7 +6118,7 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lCompilerRT-Generic"); CmdArgs.push_back("-L/usr/pkg/compiler-rt/lib"); CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); + Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.h b/contrib/llvm/tools/clang/lib/Driver/Tools.h index 7ac43ec..d647171 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tools.h +++ b/contrib/llvm/tools/clang/lib/Driver/Tools.h @@ -13,7 +13,6 @@ #include "clang/Driver/Tool.h" #include "clang/Driver/Types.h" #include "clang/Driver/Util.h" - #include "llvm/ADT/Triple.h" #include "llvm/Support/Compiler.h" @@ -31,7 +30,17 @@ namespace tools { /// \brief Clang compiler tool. class LLVM_LIBRARY_VISIBILITY Clang : public Tool { + public: + static const char *getBaseInputName(const ArgList &Args, + const InputInfoList &Inputs); + static const char *getBaseInputStem(const ArgList &Args, + const InputInfoList &Inputs); + static const char *getDependencyFileName(const ArgList &Args, + const InputInfoList &Inputs); + + private: void AddPreprocessingOptions(Compilation &C, + const JobAction &JA, const Driver &D, const ArgList &Args, ArgStringList &CmdArgs, @@ -42,6 +51,7 @@ namespace tools { 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; @@ -219,63 +229,6 @@ namespace darwin { const ToolChain &TC) : Tool(Name, ShortName, TC) {} }; - class LLVM_LIBRARY_VISIBILITY CC1 : public DarwinTool { - virtual void anchor(); - public: - static const char *getBaseInputName(const ArgList &Args, - const InputInfoList &Input); - static const char *getBaseInputStem(const ArgList &Args, - const InputInfoList &Input); - static const char *getDependencyFileName(const ArgList &Args, - const InputInfoList &Inputs); - - protected: - const char *getCC1Name(types::ID Type) const; - - void AddCC1Args(const ArgList &Args, ArgStringList &CmdArgs) const; - void RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const; - void AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, - const InputInfoList &Inputs, - const ArgStringList &OutputArgs) const; - void AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, - const InputInfoList &Inputs, - const ArgStringList &OutputArgs) const; - void AddCPPUniqueOptionsArgs(const ArgList &Args, - ArgStringList &CmdArgs, - const InputInfoList &Inputs) const; - void AddCPPArgs(const ArgList &Args, ArgStringList &CmdArgs) const; - - public: - CC1(const char *Name, const char *ShortName, - const ToolChain &TC) : DarwinTool(Name, ShortName, TC) {} - - virtual bool hasGoodDiagnostics() const { return true; } - virtual bool hasIntegratedCPP() const { return true; } - }; - - class LLVM_LIBRARY_VISIBILITY Preprocess : public CC1 { - public: - Preprocess(const ToolChain &TC) : CC1("darwin::Preprocess", - "gcc preprocessor", TC) {} - - virtual void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &TCArgs, - const char *LinkingOutput) const; - }; - - class LLVM_LIBRARY_VISIBILITY Compile : public CC1 { - public: - Compile(const ToolChain &TC) : CC1("darwin::Compile", "gcc frontend", TC) {} - - virtual void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &TCArgs, - const char *LinkingOutput) const; - }; - class LLVM_LIBRARY_VISIBILITY Assemble : public DarwinTool { public: Assemble(const ToolChain &TC) : DarwinTool("darwin::Assemble", @@ -327,6 +280,7 @@ namespace darwin { "dsymutil", TC) {} virtual bool hasIntegratedCPP() const { return false; } + virtual bool isDsymutilJob() const { return true; } virtual void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, @@ -338,15 +292,15 @@ namespace darwin { class LLVM_LIBRARY_VISIBILITY VerifyDebug : public DarwinTool { public: VerifyDebug(const ToolChain &TC) : DarwinTool("darwin::VerifyDebug", - "dwarfdump", TC) {} + "dwarfdump", TC) {} virtual bool hasIntegratedCPP() const { return false; } virtual void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &TCArgs, - const char *LinkingOutput) const; + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, + const char *LinkingOutput) const; }; } @@ -474,12 +428,11 @@ namespace netbsd { }; } // end namespace netbsd - /// linux -- Directly call GNU Binutils assembler and linker -namespace linuxtools { + /// Directly call GNU Binutils' assembler and linker. +namespace gnutools { class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { public: - Assemble(const ToolChain &TC) : Tool("linux::Assemble", "assembler", - TC) {} + Assemble(const ToolChain &TC) : Tool("GNU::Assemble", "assembler", TC) {} virtual bool hasIntegratedCPP() const { return false; } @@ -491,7 +444,7 @@ namespace linuxtools { }; class LLVM_LIBRARY_VISIBILITY Link : public Tool { public: - Link(const ToolChain &TC) : Tool("linux::Link", "linker", TC) {} + Link(const ToolChain &TC) : Tool("GNU::Link", "linker", TC) {} virtual bool hasIntegratedCPP() const { return false; } virtual bool isLinkJob() const { return true; } diff --git a/contrib/llvm/tools/clang/lib/Driver/Types.cpp b/contrib/llvm/tools/clang/lib/Driver/Types.cpp index 862025e..7d22596 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Types.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Types.cpp @@ -8,10 +8,9 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Types.h" - #include "llvm/ADT/StringSwitch.h" -#include <string.h> #include <cassert> +#include <string.h> using namespace clang::driver; using namespace clang::driver::types; @@ -88,7 +87,7 @@ bool types::isAcceptedByClang(ID Id) { case TY_ObjCHeader: case TY_PP_ObjCHeader: case TY_CXXHeader: case TY_PP_CXXHeader: case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: - case TY_AST: + case TY_AST: case TY_ModuleFile: case TY_LLVM_IR: case TY_LLVM_BC: return true; } @@ -113,7 +112,7 @@ bool types::isCXX(ID Id) { return false; case TY_CXX: case TY_PP_CXX: - case TY_ObjCXX: case TY_PP_ObjCXX: + case TY_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias: case TY_CXXHeader: case TY_PP_CXXHeader: case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: case TY_CUDA: @@ -165,16 +164,15 @@ types::ID types::lookupTypeForExtension(const char *Ext) { .Case("F90", TY_Fortran) .Case("F95", TY_Fortran) .Case("mii", TY_PP_ObjCXX) + .Case("pcm", TY_ModuleFile) .Default(TY_INVALID); } types::ID types::lookupTypeForTypeSpecifier(const char *Name) { - unsigned N = strlen(Name); - for (unsigned i=0; i<numTypes; ++i) { types::ID Id = (types::ID) (i + 1); if (canTypeBeUserSpecified(Id) && - memcmp(Name, getInfo(Id).Name, N + 1) == 0) + strcmp(Name, getInfo(Id).Name) == 0) return Id; } @@ -182,54 +180,36 @@ types::ID types::lookupTypeForTypeSpecifier(const char *Name) { } // FIXME: Why don't we just put this list in the defs file, eh. - -unsigned types::getNumCompilationPhases(ID Id) { - if (Id == TY_Object) - return 1; - - unsigned N = 0; - if (getPreprocessedType(Id) != TY_INVALID) - N += 1; - - if (onlyAssembleType(Id)) - return N + 2; // assemble, link - if (onlyPrecompileType(Id)) - return N + 1; // precompile - - return N + 3; // compile, assemble, link -} - -phases::ID types::getCompilationPhase(ID Id, unsigned N) { - assert(N < getNumCompilationPhases(Id) && "Invalid index."); - - if (Id == TY_Object) - return phases::Link; - - if (getPreprocessedType(Id) != TY_INVALID) { - if (N == 0) - return phases::Preprocess; - --N; +void types::getCompilationPhases( + ID Id, + llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> &P) { + if (Id != TY_Object) { + if (getPreprocessedType(Id) != TY_INVALID) { + P.push_back(phases::Preprocess); + } + + if (onlyPrecompileType(Id)) { + P.push_back(phases::Precompile); + } else { + if (!onlyAssembleType(Id)) { + P.push_back(phases::Compile); + } + P.push_back(phases::Assemble); + } } - - if (onlyAssembleType(Id)) - return N == 0 ? phases::Assemble : phases::Link; - - if (onlyPrecompileType(Id)) - return phases::Precompile; - - if (N == 0) - return phases::Compile; - if (N == 1) - return phases::Assemble; - - return phases::Link; + if (!onlyPrecompileType(Id)) { + P.push_back(phases::Link); + } + assert(0 < P.size() && "Not enough phases in list"); + assert(P.size() <= phases::MaxNumberOfPhases && "Too many phases in list"); + return; } ID types::lookupCXXTypeForCType(ID Id) { switch (Id) { default: return Id; - + case types::TY_C: return types::TY_CXX; case types::TY_PP_C: diff --git a/contrib/llvm/tools/clang/lib/Driver/WindowsToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/WindowsToolChain.cpp index de2d535..dac7e77 100644 --- a/contrib/llvm/tools/clang/lib/Driver/WindowsToolChain.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/WindowsToolChain.cpp @@ -8,13 +8,14 @@ //===----------------------------------------------------------------------===// #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 "clang/Basic/Version.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Path.h" @@ -31,49 +32,20 @@ using namespace clang::driver; using namespace clang::driver::toolchains; using namespace clang; -Windows::Windows(const Driver &D, const llvm::Triple& Triple) - : ToolChain(D, Triple) { +Windows::Windows(const Driver &D, const llvm::Triple& Triple, + const ArgList &Args) + : ToolChain(D, Triple, Args) { } -Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::InputClass: - case Action::BindArchClass: - case Action::LipoJobClass: - case Action::DsymutilJobClass: - case Action::VerifyJobClass: - llvm_unreachable("Invalid tool kind."); - case Action::PreprocessJobClass: - case Action::PrecompileJobClass: - case Action::AnalyzeJobClass: - case Action::MigrateJobClass: - case Action::CompileJobClass: - T = new tools::Clang(*this); break; - case Action::AssembleJobClass: - if (!UseIntegratedAs && getTriple().getEnvironment() == llvm::Triple::MachO) - T = new tools::darwin::Assemble(*this); - else - T = new tools::ClangAs(*this); - break; - case Action::LinkJobClass: - T = new tools::visualstudio::Link(*this); break; - } - } +Tool *Windows::buildLinker() const { + return new tools::visualstudio::Link(*this); +} - return *T; +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); + return NULL; } bool Windows::IsIntegratedAssemblerDefault() const { @@ -158,12 +130,12 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName, for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; index++) { const char *sp = keyName; - while (*sp && !isdigit(*sp)) + while (*sp && !isDigit(*sp)) sp++; if (!*sp) continue; const char *ep = sp + 1; - while (*ep && (isdigit(*ep) || (*ep == '.'))) + while (*ep && (isDigit(*ep) || (*ep == '.'))) ep++; char numBuf[32]; strncpy(numBuf, sp, sizeof(numBuf) - 1); |