diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Driver/Driver.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/Driver.cpp | 506 |
1 files changed, 284 insertions, 222 deletions
diff --git a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp index ef26bfa..1664d0d 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp @@ -50,7 +50,6 @@ Driver::Driver(StringRef ClangExecutable, : Opts(createDriverOptTable()), Diags(Diags), Mode(GCCMode), ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT), UseStdLib(true), DefaultTargetTriple(DefaultTargetTriple), - DefaultImageName("a.out"), DriverTitle("clang LLVM compiler"), CCPrintOptionsFilename(nullptr), CCPrintHeadersFilename(nullptr), CCLogDiagnosticsFilename(nullptr), @@ -65,10 +64,13 @@ Driver::Driver(StringRef ClangExecutable, // Compute the path to the resource directory. StringRef ClangResourceDir(CLANG_RESOURCE_DIR); SmallString<128> P(Dir); - if (ClangResourceDir != "") + if (ClangResourceDir != "") { llvm::sys::path::append(P, ClangResourceDir); - else - llvm::sys::path::append(P, "..", "lib", "clang", CLANG_VERSION_STRING); + } else { + StringRef ClangLibdirSuffix(CLANG_LIBDIR_SUFFIX); + llvm::sys::path::append(P, "..", Twine("lib") + ClangLibdirSuffix, "clang", + CLANG_VERSION_STRING); + } ResourceDir = P.str(); } @@ -83,6 +85,9 @@ void Driver::ParseDriverMode(ArrayRef<const char *> Args) { getOpts().getOption(options::OPT_driver_mode).getPrefixedName(); for (size_t I = 0, E = Args.size(); I != E; ++I) { + // Ingore nullptrs, they are response file's EOL markers + if (Args[I] == nullptr) + continue; const StringRef Arg = Args[I]; if (!Arg.startswith(OptName)) continue; @@ -102,7 +107,7 @@ void Driver::ParseDriverMode(ArrayRef<const char *> Args) { } } -InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) { +InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings) { llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); unsigned IncludedFlagsBitmask; @@ -111,7 +116,7 @@ InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) { getIncludeExcludeOptionFlagMasks(); unsigned MissingArgIndex, MissingArgCount; - InputArgList *Args = getOpts().ParseArgs(ArgList.begin(), ArgList.end(), + InputArgList *Args = getOpts().ParseArgs(ArgStrings.begin(), ArgStrings.end(), MissingArgIndex, MissingArgCount, IncludedFlagsBitmask, ExcludedFlagsBitmask); @@ -122,9 +127,7 @@ InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) { << Args->getArgString(MissingArgIndex) << MissingArgCount; // Check for unsupported options. - for (ArgList::const_iterator it = Args->begin(), ie = Args->end(); - it != ie; ++it) { - Arg *A = *it; + for (const Arg *A : *Args) { if (A->getOption().hasFlag(options::Unsupported)) { Diag(clang::diag::err_drv_unsupported_opt) << A->getAsString(*Args); continue; @@ -162,7 +165,7 @@ const { (PhaseArg = DAL.getLastArg(options::OPT__SLASH_P))) { FinalPhase = phases::Preprocess; - // -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler. + // -{fsyntax-only,-analyze,emit-ast} 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_verify_pch)) || @@ -171,10 +174,13 @@ const { (PhaseArg = DAL.getLastArg(options::OPT__migrate)) || (PhaseArg = DAL.getLastArg(options::OPT__analyze, options::OPT__analyze_auto)) || - (PhaseArg = DAL.getLastArg(options::OPT_emit_ast)) || - (PhaseArg = DAL.getLastArg(options::OPT_S))) { + (PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) { FinalPhase = phases::Compile; + // -S only runs up to the backend. + } else if ((PhaseArg = DAL.getLastArg(options::OPT_S))) { + FinalPhase = phases::Backend; + // -c only runs up to the assembler. } else if ((PhaseArg = DAL.getLastArg(options::OPT_c))) { FinalPhase = phases::Assemble; @@ -202,10 +208,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { DerivedArgList *DAL = new DerivedArgList(Args); bool HasNostdlib = Args.hasArg(options::OPT_nostdlib); - for (ArgList::const_iterator it = Args.begin(), - ie = Args.end(); it != ie; ++it) { - const Arg *A = *it; - + for (Arg *A : Args) { // Unfortunately, we have to parse some forwarding options (-Xassembler, // -Xlinker, -Xpreprocessor) because we either integrate their functionality // (assembler and preprocessor), or bypass a previous driver ('collect2'). @@ -271,7 +274,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { continue; } - DAL->append(*it); + DAL->append(A); } // Add a default value of -mlinker-version=, if one was given and the user @@ -400,13 +403,13 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // preprocessed source file(s). Request that the developer attach the // diagnostic information to a bug report. void Driver::generateCompilationDiagnostics(Compilation &C, - const Command *FailingCommand) { + const Command &FailingCommand) { if (C.getArgs().hasArg(options::OPT_fno_crash_diagnostics)) return; // Don't try to generate diagnostics for link or dsymutil jobs. - if (FailingCommand && (FailingCommand->getCreator().isLinkJob() || - FailingCommand->getCreator().isDsymutilJob())) + if (FailingCommand.getCreator().isLinkJob() || + FailingCommand.getCreator().isDsymutilJob()) return; // Print the version of the compiler. @@ -421,15 +424,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C, CCGenDiagnostics = true; // Save the original job command(s). - std::string Cmd; - llvm::raw_string_ostream OS(Cmd); - if (FailingCommand) - FailingCommand->Print(OS, "\n", /*Quote*/ false, /*CrashReport*/ true); - else - // Crash triggered by FORCE_CLANG_DIAGNOSTICS_CRASH, which doesn't have an - // associated FailingCommand, so just pass all jobs. - C.getJobs().Print(OS, "\n", /*Quote*/ false, /*CrashReport*/ true); - OS.flush(); + Command Cmd = FailingCommand; // Keep track of whether we produce any errors while trying to produce // preprocessed sources. @@ -473,9 +468,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C, // Don't attempt to generate preprocessed files if multiple -arch options are // used, unless they're all duplicates. llvm::StringSet<> ArchNames; - for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end(); - it != ie; ++it) { - Arg *A = *it; + for (const Arg *A : C.getArgs()) { if (A->getOption().matches(options::OPT_arch)) { StringRef ArchName = A->getValue(); ArchNames.insert(ArchName); @@ -509,70 +502,86 @@ void Driver::generateCompilationDiagnostics(Compilation &C, SmallVector<std::pair<int, const Command *>, 4> FailingCommands; C.ExecuteJob(C.getJobs(), FailingCommands); - // If the command succeeded, we are done. - if (FailingCommands.empty()) { + // If any of the preprocessing commands failed, clean up and exit. + if (!FailingCommands.empty()) { + 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)."; + return; + } + + const ArgStringList &TempFiles = C.getTempFiles(); + if (TempFiles.empty()) { + Diag(clang::diag::note_drv_command_failed_diag_msg) + << "Error generating preprocessed source(s)."; + return; + } + + Diag(clang::diag::note_drv_command_failed_diag_msg) << "\n********************\n\n" - "PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:\n" - "Preprocessed source(s) and associated run script(s) are located at:"; - ArgStringList Files = C.getTempFiles(); - for (ArgStringList::const_iterator it = Files.begin(), ie = Files.end(); - it != ie; ++it) { - Diag(clang::diag::note_drv_command_failed_diag_msg) << *it; - std::string Script = StringRef(*it).rsplit('.').first; + "PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:\n" + "Preprocessed source(s) and associated run script(s) are located at:"; + + SmallString<128> VFS; + for (const char *TempFile : TempFiles) { + Diag(clang::diag::note_drv_command_failed_diag_msg) << TempFile; + if (StringRef(TempFile).endswith(".cache")) { // In some cases (modules) we'll dump extra data to help with reproducing // the crash into a directory next to the output. - SmallString<128> VFS; - if (llvm::sys::fs::exists(Script + ".cache")) { - Diag(clang::diag::note_drv_command_failed_diag_msg) - << Script + ".cache"; - VFS = llvm::sys::path::filename(Script + ".cache"); - llvm::sys::path::append(VFS, "vfs", "vfs.yaml"); - } - - std::string Err; - Script += ".sh"; - llvm::raw_fd_ostream ScriptOS(Script.c_str(), Err, llvm::sys::fs::F_Excl); - if (!Err.empty()) { - Diag(clang::diag::note_drv_command_failed_diag_msg) - << "Error generating run script: " + Script + " " + Err; - } else { - // Replace the original filename with the preprocessed one. - size_t I, E; - I = Cmd.find("-main-file-name "); - assert (I != std::string::npos && "Expected to find -main-file-name"); - I += 16; - E = Cmd.find(" ", I); - assert (E != std::string::npos && "-main-file-name missing argument?"); - StringRef OldFilename = StringRef(Cmd).slice(I, E); - StringRef NewFilename = llvm::sys::path::filename(*it); - I = StringRef(Cmd).rfind(OldFilename); - E = I + OldFilename.size(); - I = Cmd.rfind(" ", I) + 1; - Cmd.replace(I, E - I, NewFilename.data(), NewFilename.size()); - if (!VFS.empty()) { - // Add the VFS overlay to the reproduction script. - I += NewFilename.size(); - Cmd.insert(I, std::string(" -ivfsoverlay ") + VFS.c_str()); - } - ScriptOS << Cmd; - Diag(clang::diag::note_drv_command_failed_diag_msg) << Script; - } + VFS = llvm::sys::path::filename(TempFile); + llvm::sys::path::append(VFS, "vfs", "vfs.yaml"); } + } + + // Assume associated files are based off of the first temporary file. + CrashReportInfo CrashInfo(TempFiles[0], VFS); + + std::string Script = CrashInfo.Filename.rsplit('.').first.str() + ".sh"; + std::error_code EC; + llvm::raw_fd_ostream ScriptOS(Script, EC, llvm::sys::fs::F_Excl); + if (EC) { Diag(clang::diag::note_drv_command_failed_diag_msg) - << "\n\n********************"; + << "Error generating run script: " + Script + " " + EC.message(); } else { - // Failure, remove preprocessed files. - if (!C.getArgs().hasArg(options::OPT_save_temps)) - C.CleanupFileList(C.getTempFiles(), true); + Cmd.Print(ScriptOS, "\n", /*Quote=*/true, &CrashInfo); + Diag(clang::diag::note_drv_command_failed_diag_msg) << Script; + } - Diag(clang::diag::note_drv_command_failed_diag_msg) - << "Error generating preprocessed source(s)."; + for (const auto &A : C.getArgs().filtered(options::OPT_frewrite_map_file, + options::OPT_frewrite_map_file_EQ)) + Diag(clang::diag::note_drv_command_failed_diag_msg) << A->getValue(); + + Diag(clang::diag::note_drv_command_failed_diag_msg) + << "\n\n********************"; +} + +void Driver::setUpResponseFiles(Compilation &C, Job &J) { + if (JobList *Jobs = dyn_cast<JobList>(&J)) { + for (auto &Job : *Jobs) + setUpResponseFiles(C, Job); + return; } + + Command *CurCommand = dyn_cast<Command>(&J); + if (!CurCommand) + return; + + // Since argumentsFitWithinSystemLimits() may underestimate system's capacity + // if the tool does not support response files, there is a chance/ that things + // will just work without a response file, so we silently just skip it. + if (CurCommand->getCreator().getResponseFilesSupport() == Tool::RF_None || + llvm::sys::argumentsFitWithinSystemLimits(CurCommand->getArguments())) + return; + + std::string TmpName = GetTemporaryPath("response", "txt"); + CurCommand->setResponseFile(C.addTempFile(C.getArgs().MakeArgString( + TmpName.c_str()))); } -int Driver::ExecuteCompilation(const Compilation &C, - SmallVectorImpl< std::pair<int, const Command *> > &FailingCommands) const { +int Driver::ExecuteCompilation(Compilation &C, + SmallVectorImpl< std::pair<int, const Command *> > &FailingCommands) { // Just print if -### was present. if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) { C.getJobs().Print(llvm::errs(), "\n", true); @@ -583,6 +592,9 @@ int Driver::ExecuteCompilation(const Compilation &C, if (Diags.hasErrorOccurred()) return 1; + // Set up response file names for each command, if necessary + setUpResponseFiles(C, C.getJobs()); + C.ExecuteJob(C.getJobs(), FailingCommands); // Remove temp files. @@ -653,9 +665,13 @@ void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const { OS << "Target: " << TC.getTripleString() << '\n'; // Print the threading model. - // - // FIXME: Implement correctly. - OS << "Thread model: " << "posix" << '\n'; + if (Arg *A = C.getArgs().getLastArg(options::OPT_mthread_model)) { + // Don't print if the ToolChain would have barfed on it already + if (TC.isThreadModelSupported(A->getValue())) + OS << "Thread model: " << A->getValue(); + } else + OS << "Thread model: " << TC.getThreadModel(); + OS << '\n'; } /// PrintDiagnosticCategories - Implement the --print-diagnostic-categories @@ -836,7 +852,9 @@ void Driver::PrintActions(const Compilation &C) const { /// \brief Check whether the given input tree contains any compilation or /// assembly actions. static bool ContainsCompileOrAssembleAction(const Action *A) { - if (isa<CompileJobAction>(A) || isa<AssembleJobAction>(A)) + if (isa<CompileJobAction>(A) || + isa<BackendJobAction>(A) || + isa<AssembleJobAction>(A)) return true; for (Action::const_iterator it = A->begin(), ie = A->end(); it != ie; ++it) @@ -855,10 +873,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC, // be handled once (in the order seen). llvm::StringSet<> ArchNames; SmallVector<const char *, 4> Archs; - for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); - it != ie; ++it) { - Arg *A = *it; - + for (Arg *A : Args) { if (A->getOption().matches(options::OPT_arch)) { // Validate the option here; we don't save the type here because its // particular spelling may participate in other driver choices. @@ -871,7 +886,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC, } A->claim(); - if (ArchNames.insert(A->getValue())) + if (ArchNames.insert(A->getValue()).second) Archs.push_back(A->getValue()); } } @@ -901,7 +916,8 @@ void Driver::BuildUniversalActions(const ToolChain &TC, ActionList Inputs; for (unsigned i = 0, e = Archs.size(); i != e; ++i) { - Inputs.push_back(new BindArchAction(Act, Archs[i])); + Inputs.push_back( + new BindArchAction(std::unique_ptr<Action>(Act), Archs[i])); if (i != 0) Inputs.back()->setOwnsInputs(false); } @@ -932,9 +948,9 @@ void Driver::BuildUniversalActions(const ToolChain &TC, // Verify the debug info output. if (Args.hasArg(options::OPT_verify_debug_info)) { - Action *VerifyInput = Actions.back(); + std::unique_ptr<Action> VerifyInput(Actions.back()); Actions.pop_back(); - Actions.push_back(new VerifyDebugInfoJobAction(VerifyInput, + Actions.push_back(new VerifyDebugInfoJobAction(std::move(VerifyInput), types::TY_Nothing)); } } @@ -981,8 +997,8 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, Arg *InputTypeArg = nullptr; // The last /TC or /TP option sets the input type to C or C++ globally. - if (Arg *TCTP = Args.getLastArg(options::OPT__SLASH_TC, - options::OPT__SLASH_TP)) { + if (Arg *TCTP = Args.getLastArgNoClaim(options::OPT__SLASH_TC, + options::OPT__SLASH_TP)) { InputTypeArg = TCTP; InputType = TCTP->getOption().matches(options::OPT__SLASH_TC) ? types::TY_C : types::TY_CXX; @@ -1005,10 +1021,7 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, assert(!Args.hasArg(options::OPT_x) && "-x and /TC or /TP is not allowed"); } - for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); - it != ie; ++it) { - Arg *A = *it; - + for (Arg *A : Args) { if (A->getOption().getKind() == Option::InputClass) { const char *Value = A->getValue(); types::ID Ty = types::TY_INVALID; @@ -1070,8 +1083,17 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, } } else { assert(InputTypeArg && "InputType set w/o InputTypeArg"); - InputTypeArg->claim(); - Ty = InputType; + if (!InputTypeArg->getOption().matches(options::OPT_x)) { + // If emulating cl.exe, make sure that /TC and /TP don't affect input + // object files. + const char *Ext = strrchr(Value, '.'); + if (Ext && TC.LookupTypeForExtension(Ext + 1) == types::TY_Object) + Ty = types::TY_Object; + } + if (Ty == types::TY_INVALID) { + Ty = InputType; + InputTypeArg->claim(); + } } if (DiagnoseInputExistence(*this, Args, Value)) @@ -1142,11 +1164,8 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args, // Diagnose misuse of /Fo. if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fo)) { StringRef V = A->getValue(); - if (V.empty()) { - // It has to have a value. - Diag(clang::diag::err_drv_missing_argument) << A->getSpelling() << 1; - Args.eraseArg(options::OPT__SLASH_Fo); - } else if (Inputs.size() > 1 && !llvm::sys::path::is_separator(V.back())) { + if (Inputs.size() > 1 && !V.empty() && + !llvm::sys::path::is_separator(V.back())) { // Check whether /Fo tries to name an output file for multiple inputs. Diag(clang::diag::err_drv_out_file_argument_with_multiple_sources) << A->getSpelling() << V; @@ -1157,7 +1176,8 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args, // Diagnose misuse of /Fa. if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fa)) { StringRef V = A->getValue(); - if (Inputs.size() > 1 && !llvm::sys::path::is_separator(V.back())) { + if (Inputs.size() > 1 && !V.empty() && + !llvm::sys::path::is_separator(V.back())) { // Check whether /Fa tries to name an asm file for multiple inputs. Diag(clang::diag::err_drv_out_file_argument_with_multiple_sources) << A->getSpelling() << V; @@ -1165,12 +1185,12 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args, } } - // Diagnose misuse of /Fe. - if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fe)) { + // Diagnose misuse of /o. + if (Arg *A = Args.getLastArg(options::OPT__SLASH_o)) { if (A->getValue()[0] == '\0') { // It has to have a value. Diag(clang::diag::err_drv_missing_argument) << A->getSpelling() << 1; - Args.eraseArg(options::OPT__SLASH_Fe); + Args.eraseArg(options::OPT__SLASH_o); } } @@ -1244,7 +1264,7 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args, continue; // Otherwise construct the appropriate action. - Current.reset(ConstructPhaseAction(Args, Phase, Current.release())); + Current = ConstructPhaseAction(Args, Phase, std::move(Current)); if (Current->getType() == types::TY_Nothing) break; } @@ -1269,8 +1289,9 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args, Args.ClaimAllArgs(options::OPT_cl_ignored_Group); } -Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, - Action *Input) const { +std::unique_ptr<Action> +Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, + std::unique_ptr<Action> Input) const { llvm::PrettyStackTraceString CrashInfo("Constructing phase actions"); // Build the appropriate action. switch (Phase) { @@ -1289,7 +1310,7 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, assert(OutputTy != types::TY_INVALID && "Cannot preprocess this input type!"); } - return new PreprocessJobAction(Input, OutputTy); + return llvm::make_unique<PreprocessJobAction>(std::move(Input), OutputTy); } case phases::Precompile: { types::ID OutputTy = types::TY_PCH; @@ -1297,39 +1318,53 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, // Syntax checks should not emit a PCH file OutputTy = types::TY_Nothing; } - return new PrecompileJobAction(Input, OutputTy); + return llvm::make_unique<PrecompileJobAction>(std::move(Input), OutputTy); } case phases::Compile: { - if (Args.hasArg(options::OPT_fsyntax_only)) { - return new CompileJobAction(Input, types::TY_Nothing); - } else if (Args.hasArg(options::OPT_rewrite_objc)) { - return new CompileJobAction(Input, types::TY_RewrittenObjC); - } else if (Args.hasArg(options::OPT_rewrite_legacy_objc)) { - return new CompileJobAction(Input, types::TY_RewrittenLegacyObjC); - } else if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto)) { - return new AnalyzeJobAction(Input, types::TY_Plist); - } else if (Args.hasArg(options::OPT__migrate)) { - 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 (Args.hasArg(options::OPT_verify_pch)) { - return new VerifyPCHJobAction(Input, types::TY_Nothing); - } else if (IsUsingLTO(Args)) { + if (Args.hasArg(options::OPT_fsyntax_only)) + return llvm::make_unique<CompileJobAction>(std::move(Input), + types::TY_Nothing); + if (Args.hasArg(options::OPT_rewrite_objc)) + return llvm::make_unique<CompileJobAction>(std::move(Input), + types::TY_RewrittenObjC); + if (Args.hasArg(options::OPT_rewrite_legacy_objc)) + return llvm::make_unique<CompileJobAction>(std::move(Input), + types::TY_RewrittenLegacyObjC); + if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto)) + return llvm::make_unique<AnalyzeJobAction>(std::move(Input), + types::TY_Plist); + if (Args.hasArg(options::OPT__migrate)) + return llvm::make_unique<MigrateJobAction>(std::move(Input), + types::TY_Remap); + if (Args.hasArg(options::OPT_emit_ast)) + return llvm::make_unique<CompileJobAction>(std::move(Input), + types::TY_AST); + if (Args.hasArg(options::OPT_module_file_info)) + return llvm::make_unique<CompileJobAction>(std::move(Input), + types::TY_ModuleFile); + if (Args.hasArg(options::OPT_verify_pch)) + return llvm::make_unique<VerifyPCHJobAction>(std::move(Input), + types::TY_Nothing); + return llvm::make_unique<CompileJobAction>(std::move(Input), + types::TY_LLVM_BC); + } + case phases::Backend: { + if (IsUsingLTO(Args)) { types::ID Output = Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC; - return new CompileJobAction(Input, Output); - } else if (Args.hasArg(options::OPT_emit_llvm)) { + return llvm::make_unique<BackendJobAction>(std::move(Input), Output); + } + if (Args.hasArg(options::OPT_emit_llvm)) { types::ID Output = Args.hasArg(options::OPT_S) ? types::TY_LLVM_IR : types::TY_LLVM_BC; - return new CompileJobAction(Input, Output); - } else { - return new CompileJobAction(Input, types::TY_PP_Asm); + return llvm::make_unique<BackendJobAction>(std::move(Input), Output); } + return llvm::make_unique<BackendJobAction>(std::move(Input), + types::TY_PP_Asm); } case phases::Assemble: - return new AssembleJobAction(Input, types::TY_Object); + return llvm::make_unique<AssembleJobAction>(std::move(Input), + types::TY_Object); } llvm_unreachable("invalid phase in ConstructPhaseAction"); @@ -1351,9 +1386,8 @@ void Driver::BuildJobs(Compilation &C) const { // files. if (FinalOutput) { unsigned NumOutputs = 0; - for (ActionList::const_iterator it = C.getActions().begin(), - ie = C.getActions().end(); it != ie; ++it) - if ((*it)->getType() != types::TY_Nothing) + for (const Action *A : C.getActions()) + if (A->getType() != types::TY_Nothing) ++NumOutputs; if (NumOutputs > 1) { @@ -1364,19 +1398,12 @@ void Driver::BuildJobs(Compilation &C) const { // Collect the list of architectures. llvm::StringSet<> ArchNames; - if (C.getDefaultToolChain().getTriple().isOSBinFormatMachO()) { - for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end(); - it != ie; ++it) { - Arg *A = *it; + if (C.getDefaultToolChain().getTriple().isOSBinFormatMachO()) + for (const Arg *A : C.getArgs()) if (A->getOption().matches(options::OPT_arch)) ArchNames.insert(A->getValue()); - } - } - - for (ActionList::const_iterator it = C.getActions().begin(), - ie = C.getActions().end(); it != ie; ++it) { - Action *A = *it; + for (Action *A : C.getActions()) { // If we are linking an image for multiple archs then the linker wants // -arch_multiple and -final_output <final image name>. Unfortunately, this // doesn't fit in cleanly because we have to pass this information down. @@ -1388,7 +1415,7 @@ void Driver::BuildJobs(Compilation &C) const { if (FinalOutput) LinkingOutput = FinalOutput->getValue(); else - LinkingOutput = DefaultImageName.c_str(); + LinkingOutput = getDefaultImageName(); } InputInfo II; @@ -1412,10 +1439,7 @@ void Driver::BuildJobs(Compilation &C) const { // Claim --driver-mode, it was handled earlier. (void) C.getArgs().hasArg(options::OPT_driver_mode); - for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end(); - it != ie; ++it) { - Arg *A = *it; - + for (Arg *A : C.getArgs()) { // FIXME: It would be nice to be able to send the argument to the // DiagnosticsEngine, so that extra values, position, and so on could be // printed. @@ -1462,12 +1486,34 @@ static const Tool *SelectToolForJob(Compilation &C, const ToolChain *TC, !C.getArgs().hasArg(options::OPT__SLASH_FA) && !C.getArgs().hasArg(options::OPT__SLASH_Fa) && isa<AssembleJobAction>(JA) && - Inputs->size() == 1 && isa<CompileJobAction>(*Inputs->begin())) { - const Tool *Compiler = - TC->SelectTool(cast<JobAction>(**Inputs->begin())); + Inputs->size() == 1 && isa<BackendJobAction>(*Inputs->begin())) { + // A BackendJob is always preceded by a CompileJob, and without + // -save-temps they will always get combined together, so instead of + // checking the backend tool, check if the tool for the CompileJob + // has an integrated assembler. + const ActionList *BackendInputs = &(*Inputs)[0]->getInputs(); + JobAction *CompileJA = cast<CompileJobAction>(*BackendInputs->begin()); + const Tool *Compiler = TC->SelectTool(*CompileJA); if (!Compiler) return nullptr; if (Compiler->hasIntegratedAssembler()) { + Inputs = &(*BackendInputs)[0]->getInputs(); + ToolForJob = Compiler; + } + } + + // A backend job should always be combined with the preceding compile job + // unless OPT_save_temps is enabled and the compiler is capable of emitting + // LLVM IR as an intermediate output. + if (isa<BackendJobAction>(JA)) { + // Check if the compiler supports emitting LLVM IR. + assert(Inputs->size() == 1); + JobAction *CompileJA = cast<CompileJobAction>(*Inputs->begin()); + const Tool *Compiler = TC->SelectTool(*CompileJA); + if (!Compiler) + return nullptr; + if (!Compiler->canEmitIR() || + !C.getArgs().hasArg(options::OPT_save_temps)) { Inputs = &(*Inputs)[0]->getInputs(); ToolForJob = Compiler; } @@ -1537,8 +1583,7 @@ void Driver::BuildJobsForAction(Compilation &C, // Only use pipes when there is exactly one input. InputInfoList InputInfos; - for (ActionList::const_iterator it = Inputs->begin(), ie = Inputs->end(); - it != ie; ++it) { + for (const Action *Input : *Inputs) { // Treat dsymutil and verify sub-jobs as being at the top-level too, they // shouldn't get temporary output names. // FIXME: Clean this up. @@ -1547,7 +1592,7 @@ void Driver::BuildJobsForAction(Compilation &C, SubJobAtTopLevel = true; InputInfo II; - BuildJobsForAction(C, *it, TC, BoundArch, SubJobAtTopLevel, MultipleArchs, + BuildJobsForAction(C, Input, TC, BoundArch, SubJobAtTopLevel, MultipleArchs, LinkingOutput, II); InputInfos.push_back(II); } @@ -1583,6 +1628,11 @@ void Driver::BuildJobsForAction(Compilation &C, } } +const char *Driver::getDefaultImageName() const { + llvm::Triple Target(llvm::Triple::normalize(DefaultTargetTriple)); + return Target.isOSWindows() ? "a.exe" : "a.out"; +} + /// \brief Create output filename based on ArgValue, which could either be a /// full filename, filename without extension, or a directory. If ArgValue /// does not provide a filename, then use BaseName, and use the extension @@ -1634,7 +1684,8 @@ const char *Driver::GetNamedOutputPath(Compilation &C, assert(AtTopLevel && isa<PreprocessJobAction>(JA)); StringRef BaseName = llvm::sys::path::filename(BaseInput); StringRef NameArg; - if (Arg *A = C.getArgs().getLastArg(options::OPT__SLASH_Fi)) + if (Arg *A = C.getArgs().getLastArg(options::OPT__SLASH_Fi, + options::OPT__SLASH_o)) NameArg = A->getValue(); return C.addResultFile(MakeCLOutputFilename(C.getArgs(), NameArg, BaseName, types::TY_PP_C), &JA); @@ -1681,15 +1732,17 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const char *NamedOutput; if (JA.getType() == types::TY_Object && - C.getArgs().hasArg(options::OPT__SLASH_Fo)) { - // The /Fo flag decides the object filename. - StringRef Val = C.getArgs().getLastArg(options::OPT__SLASH_Fo)->getValue(); + C.getArgs().hasArg(options::OPT__SLASH_Fo, options::OPT__SLASH_o)) { + // The /Fo or /o flag decides the object filename. + StringRef Val = C.getArgs().getLastArg(options::OPT__SLASH_Fo, + options::OPT__SLASH_o)->getValue(); NamedOutput = MakeCLOutputFilename(C.getArgs(), Val, BaseName, types::TY_Object); } else if (JA.getType() == types::TY_Image && - C.getArgs().hasArg(options::OPT__SLASH_Fe)) { - // The /Fe flag names the linked file. - StringRef Val = C.getArgs().getLastArg(options::OPT__SLASH_Fe)->getValue(); + C.getArgs().hasArg(options::OPT__SLASH_Fe, options::OPT__SLASH_o)) { + // The /Fe or /o flag names the linked file. + StringRef Val = C.getArgs().getLastArg(options::OPT__SLASH_Fe, + options::OPT__SLASH_o)->getValue(); NamedOutput = MakeCLOutputFilename(C.getArgs(), Val, BaseName, types::TY_Image); } else if (JA.getType() == types::TY_Image) { @@ -1698,12 +1751,12 @@ const char *Driver::GetNamedOutputPath(Compilation &C, NamedOutput = MakeCLOutputFilename(C.getArgs(), "", BaseName, types::TY_Image); } else if (MultipleArchs && BoundArch) { - SmallString<128> Output(DefaultImageName.c_str()); + SmallString<128> Output(getDefaultImageName()); Output += "-"; Output.append(BoundArch); NamedOutput = C.getArgs().MakeArgString(Output.c_str()); } else - NamedOutput = DefaultImageName.c_str(); + NamedOutput = getDefaultImageName(); } else { const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode()); assert(Suffix && "All types used for output should have a suffix."); @@ -1716,6 +1769,12 @@ const char *Driver::GetNamedOutputPath(Compilation &C, Suffixed += "-"; Suffixed.append(BoundArch); } + // When using both -save-temps and -emit-llvm, use a ".tmp.bc" suffix for + // the unoptimized bitcode so that it does not get overwritten by the ".bc" + // optimized bitcode output. + if (!AtTopLevel && C.getArgs().hasArg(options::OPT_emit_llvm) && + JA.getType() == types::TY_LLVM_BC) + Suffixed += ".tmp"; Suffixed += '.'; Suffixed += Suffix; NamedOutput = C.getArgs().MakeArgString(Suffixed.c_str()); @@ -1793,51 +1852,56 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const { return Name; } +void +Driver::generatePrefixedToolNames(const char *Tool, const ToolChain &TC, + SmallVectorImpl<std::string> &Names) const { + // FIXME: Needs a better variable than DefaultTargetTriple + Names.push_back(DefaultTargetTriple + "-" + Tool); + Names.push_back(Tool); +} + +static bool ScanDirForExecutable(SmallString<128> &Dir, + ArrayRef<std::string> Names) { + for (const auto &Name : Names) { + llvm::sys::path::append(Dir, Name); + if (llvm::sys::fs::can_execute(Twine(Dir))) + return true; + llvm::sys::path::remove_filename(Dir); + } + return false; +} + std::string Driver::GetProgramPath(const char *Name, const ToolChain &TC) const { - // FIXME: Needs a better variable than DefaultTargetTriple - std::string TargetSpecificExecutable(DefaultTargetTriple + "-" + Name); + SmallVector<std::string, 2> TargetSpecificExecutables; + generatePrefixedToolNames(Name, TC, TargetSpecificExecutables); + // Respect a limited subset of the '-Bprefix' functionality in GCC by // attempting to use this prefix when looking for program paths. - for (Driver::prefix_list::const_iterator it = PrefixDirs.begin(), - ie = PrefixDirs.end(); it != ie; ++it) { - if (llvm::sys::fs::is_directory(*it)) { - SmallString<128> P(*it); - llvm::sys::path::append(P, TargetSpecificExecutable); - if (llvm::sys::fs::can_execute(Twine(P))) - return P.str(); - llvm::sys::path::remove_filename(P); - llvm::sys::path::append(P, Name); - if (llvm::sys::fs::can_execute(Twine(P))) + for (const auto &PrefixDir : PrefixDirs) { + if (llvm::sys::fs::is_directory(PrefixDir)) { + SmallString<128> P(PrefixDir); + if (ScanDirForExecutable(P, TargetSpecificExecutables)) return P.str(); } else { - SmallString<128> P(*it + Name); + SmallString<128> P(PrefixDir + Name); if (llvm::sys::fs::can_execute(Twine(P))) return P.str(); } } const ToolChain::path_list &List = TC.getProgramPaths(); - for (ToolChain::path_list::const_iterator - it = List.begin(), ie = List.end(); it != ie; ++it) { - SmallString<128> P(*it); - llvm::sys::path::append(P, TargetSpecificExecutable); - if (llvm::sys::fs::can_execute(Twine(P))) - return P.str(); - llvm::sys::path::remove_filename(P); - llvm::sys::path::append(P, Name); - if (llvm::sys::fs::can_execute(Twine(P))) + for (const auto &Path : List) { + SmallString<128> P(Path); + if (ScanDirForExecutable(P, TargetSpecificExecutables)) return P.str(); } // If all else failed, search the path. - std::string P(llvm::sys::FindProgramByName(TargetSpecificExecutable)); - if (!P.empty()) - return P; - - P = llvm::sys::FindProgramByName(Name); - if (!P.empty()) - return P; + for (const auto &TargetSpecificExecutable : TargetSpecificExecutables) + if (llvm::ErrorOr<std::string> P = + llvm::sys::findProgramByName(TargetSpecificExecutable)) + return *P; return Name; } @@ -1893,8 +1957,6 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, Target.setArch(llvm::Triple::mips64el); else if (Target.getArch() == llvm::Triple::aarch64_be) Target.setArch(llvm::Triple::aarch64); - else if (Target.getArch() == llvm::Triple::arm64_be) - Target.setArch(llvm::Triple::arm64); } else { if (Target.getArch() == llvm::Triple::mipsel) Target.setArch(llvm::Triple::mips); @@ -1902,15 +1964,11 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, Target.setArch(llvm::Triple::mips64); else if (Target.getArch() == llvm::Triple::aarch64) Target.setArch(llvm::Triple::aarch64_be); - else if (Target.getArch() == llvm::Triple::arm64) - Target.setArch(llvm::Triple::arm64_be); } } // Skip further flag support on OSes which don't support '-m32' or '-m64'. - if (Target.getArchName() == "tce" || - Target.getOS() == llvm::Triple::AuroraUX || - Target.getOS() == llvm::Triple::Minix) + if (Target.getArchName() == "tce" || Target.getOS() == llvm::Triple::Minix) return Target; // Handle pseudo-target flags '-m64', '-mx32', '-m32' and '-m16'. @@ -1918,21 +1976,25 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, options::OPT_m32, options::OPT_m16)) { llvm::Triple::ArchType AT = llvm::Triple::UnknownArch; - if (A->getOption().matches(options::OPT_m64)) + if (A->getOption().matches(options::OPT_m64)) { AT = Target.get64BitArchVariant().getArch(); - else if (A->getOption().matches(options::OPT_mx32) && + if (Target.getEnvironment() == llvm::Triple::GNUX32) + Target.setEnvironment(llvm::Triple::GNU); + } else if (A->getOption().matches(options::OPT_mx32) && Target.get64BitArchVariant().getArch() == llvm::Triple::x86_64) { AT = llvm::Triple::x86_64; Target.setEnvironment(llvm::Triple::GNUX32); - } else if (A->getOption().matches(options::OPT_m32)) + } else if (A->getOption().matches(options::OPT_m32)) { AT = Target.get32BitArchVariant().getArch(); - else if (A->getOption().matches(options::OPT_m16) && + if (Target.getEnvironment() == llvm::Triple::GNUX32) + Target.setEnvironment(llvm::Triple::GNU); + } else if (A->getOption().matches(options::OPT_m16) && Target.get32BitArchVariant().getArch() == llvm::Triple::x86) { AT = llvm::Triple::x86; Target.setEnvironment(llvm::Triple::CODE16); } - if (AT != llvm::Triple::UnknownArch) + if (AT != llvm::Triple::UnknownArch && AT != Target.getArch()) Target.setArch(AT); } @@ -1947,9 +2009,6 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, ToolChain *&TC = ToolChains[Target.str()]; if (!TC) { switch (Target.getOS()) { - case llvm::Triple::AuroraUX: - TC = new toolchains::AuroraUX(*this, Target, Args); - break; case llvm::Triple::Darwin: case llvm::Triple::MacOSX: case llvm::Triple::IOS: @@ -2000,9 +2059,12 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, else TC = new toolchains::Generic_GCC(*this, Target, Args); break; + case llvm::Triple::Itanium: + TC = new toolchains::CrossWindowsToolChain(*this, Target, Args); + break; case llvm::Triple::MSVC: case llvm::Triple::UnknownEnvironment: - TC = new toolchains::Windows(*this, Target, Args); + TC = new toolchains::MSVCToolChain(*this, Target, Args); break; } break; @@ -2025,7 +2087,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, TC = new toolchains::Generic_ELF(*this, Target, Args); break; } - if (Target.getObjectFormat() == llvm::Triple::MachO) { + if (Target.isOSBinFormatMachO()) { TC = new toolchains::MachO(*this, Target, Args); break; } @@ -2045,7 +2107,7 @@ bool Driver::ShouldUseClangCompiler(const JobAction &JA) const { // Otherwise make sure this is an action clang understands. if (!isa<PreprocessJobAction>(JA) && !isa<PrecompileJobAction>(JA) && - !isa<CompileJobAction>(JA)) + !isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA)) return false; return true; |