diff options
Diffstat (limited to 'lib/Driver/Driver.cpp')
| -rw-r--r-- | lib/Driver/Driver.cpp | 506 | 
1 files changed, 284 insertions, 222 deletions
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index ef26bfacdd640..1664d0d49d469 100644 --- a/lib/Driver/Driver.cpp +++ b/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;  | 
